1
1
import ConcurrencyExtras
2
2
import Foundation
3
- import Helpers
4
3
import HTTPTypes
4
+ import Helpers
5
5
6
6
#if canImport(FoundationNetworking)
7
7
import FoundationNetworking
@@ -16,6 +16,8 @@ public final class FunctionsClient: Sendable {
16
16
Data , URLResponse
17
17
)
18
18
19
+ public typealias _RequestAdapter = @Sendable ( URLRequest) async throws -> URLRequest
20
+
19
21
/// The base URL for the functions.
20
22
let url : URL
21
23
@@ -29,6 +31,7 @@ public final class FunctionsClient: Sendable {
29
31
30
32
private let http : any HTTPClientType
31
33
private let mutableState = LockIsolated ( MutableState ( ) )
34
+ private let _requestAdapter : _RequestAdapter ?
32
35
33
36
var headers : HTTPFields {
34
37
mutableState. headers
@@ -48,27 +51,32 @@ public final class FunctionsClient: Sendable {
48
51
headers: [ String : String ] = [ : ] ,
49
52
region: String ? = nil ,
50
53
logger: ( any SupabaseLogger ) ? = nil ,
51
- fetch: @escaping FetchHandler = { try await URLSession . shared. data ( for: $0) }
54
+ fetch: @escaping FetchHandler = { try await URLSession . shared. data ( for: $0) } ,
55
+ _requestAdapter: _RequestAdapter ? = nil
52
56
) {
53
57
var interceptors : [ any HTTPClientInterceptor ] = [ ]
58
+
54
59
if let logger {
55
60
interceptors. append ( LoggerInterceptor ( logger: logger) )
56
61
}
57
62
58
63
let http = HTTPClient ( fetch: fetch, interceptors: interceptors)
59
64
60
- self . init ( url: url, headers: headers, region: region, http: http)
65
+ self . init (
66
+ url: url, headers: headers, region: region, http: http, _requestAdapter: _requestAdapter)
61
67
}
62
68
63
69
init (
64
70
url: URL ,
65
71
headers: [ String : String ] ,
66
72
region: String ? ,
67
- http: any HTTPClientType
73
+ http: any HTTPClientType ,
74
+ _requestAdapter: _RequestAdapter ?
68
75
) {
69
76
self . url = url
70
77
self . region = region
71
78
self . http = http
79
+ self . _requestAdapter = _requestAdapter
72
80
73
81
mutableState. withValue {
74
82
$0. headers = HTTPFields ( headers)
@@ -91,9 +99,17 @@ public final class FunctionsClient: Sendable {
91
99
headers: [ String : String ] = [ : ] ,
92
100
region: FunctionRegion ? = nil ,
93
101
logger: ( any SupabaseLogger ) ? = nil ,
94
- fetch: @escaping FetchHandler = { try await URLSession . shared. data ( for: $0) }
102
+ fetch: @escaping FetchHandler = { try await URLSession . shared. data ( for: $0) } ,
103
+ _requestAdapter: _RequestAdapter ? = nil
95
104
) {
96
- self . init ( url: url, headers: headers, region: region? . rawValue, logger: logger, fetch: fetch)
105
+ self . init (
106
+ url: url,
107
+ headers: headers,
108
+ region: region? . rawValue,
109
+ logger: logger,
110
+ fetch: fetch,
111
+ _requestAdapter: _requestAdapter
112
+ )
97
113
}
98
114
99
115
/// Updates the authorization header.
@@ -164,7 +180,7 @@ public final class FunctionsClient: Sendable {
164
180
let request = buildRequest ( functionName: functionName, options: invokeOptions)
165
181
let response = try await http. send ( request)
166
182
167
- guard 200 ..< 300 ~= response. statusCode else {
183
+ guard 200 ..< 300 ~= response. statusCode else {
168
184
throw FunctionsError . httpError ( code: response. statusCode, data: response. data)
169
185
}
170
186
@@ -198,20 +214,37 @@ public final class FunctionsClient: Sendable {
198
214
199
215
let urlRequest = buildRequest ( functionName: functionName, options: invokeOptions) . urlRequest
200
216
201
- let task = session . dataTask ( with : urlRequest )
202
- task . resume ( )
217
+ Task {
218
+ let adaptedRequest : URLRequest
203
219
204
- continuation. onTermination = { _ in
205
- task. cancel ( )
220
+ if let _requestAdapter {
221
+ do {
222
+ adaptedRequest = try await _requestAdapter ( urlRequest)
223
+ } catch {
224
+ continuation. finish ( throwing: error)
225
+ return
226
+ }
227
+ } else {
228
+ adaptedRequest = urlRequest
229
+ }
230
+
231
+ let task = session. dataTask ( with: adaptedRequest)
232
+ task. resume ( )
233
+
234
+ continuation. onTermination = { _ in
235
+ task. cancel ( )
206
236
207
- // Hold a strong reference to delegate until continuation terminates.
208
- _ = delegate
237
+ // Hold a strong reference to delegate until continuation terminates.
238
+ _ = delegate
239
+ }
209
240
}
210
241
211
242
return stream
212
243
}
213
244
214
- private func buildRequest( functionName: String , options: FunctionInvokeOptions ) -> Helpers . HTTPRequest {
245
+ private func buildRequest( functionName: String , options: FunctionInvokeOptions )
246
+ -> Helpers . HTTPRequest
247
+ {
215
248
var request = HTTPRequest (
216
249
url: url. appendingPathComponent ( functionName) ,
217
250
method: options. httpMethod ?? . post,
@@ -243,13 +276,16 @@ final class StreamResponseDelegate: NSObject, URLSessionDataDelegate, Sendable {
243
276
continuation. finish ( throwing: error)
244
277
}
245
278
246
- func urlSession( _: URLSession , dataTask _: URLSessionDataTask , didReceive response: URLResponse , completionHandler: @escaping ( URLSession . ResponseDisposition ) -> Void ) {
279
+ func urlSession(
280
+ _: URLSession , dataTask _: URLSessionDataTask , didReceive response: URLResponse ,
281
+ completionHandler: @escaping ( URLSession . ResponseDisposition ) -> Void
282
+ ) {
247
283
guard let httpResponse = response as? HTTPURLResponse else {
248
284
continuation. finish ( throwing: URLError ( . badServerResponse) )
249
285
return
250
286
}
251
287
252
- guard 200 ..< 300 ~= httpResponse. statusCode else {
288
+ guard 200 ..< 300 ~= httpResponse. statusCode else {
253
289
let error = FunctionsError . httpError ( code: httpResponse. statusCode, data: Data ( ) )
254
290
continuation. finish ( throwing: error)
255
291
return
0 commit comments