@@ -18,26 +18,28 @@ public actor FunctionsClient {
18
18
let url : URL
19
19
/// Headers to be included in the requests.
20
20
var headers : [ String : String ]
21
- /// The fetch handler used to make requests.
22
- let fetch : FetchHandler
21
+
22
+ private let http : HTTPClient
23
23
24
24
/// Initializes a new instance of `FunctionsClient`.
25
25
///
26
26
/// - Parameters:
27
27
/// - url: The base URL for the functions.
28
28
/// - headers: Headers to be included in the requests. (Default: empty dictionary)
29
+ /// - logger: SupabaseLogger instance to use.
29
30
/// - fetch: The fetch handler used to make requests. (Default: URLSession.shared.data(for:))
30
31
public init (
31
32
url: URL ,
32
33
headers: [ String : String ] = [ : ] ,
34
+ logger: ( any SupabaseLogger ) ? = nil ,
33
35
fetch: @escaping FetchHandler = { try await URLSession . shared. data ( for: $0) }
34
36
) {
35
37
self . url = url
36
38
self . headers = headers
37
39
if headers [ " X-Client-Info " ] == nil {
38
40
self . headers [ " X-Client-Info " ] = " functions-swift/ \( version) "
39
41
}
40
- self . fetch = fetch
42
+ http = HTTPClient ( logger : logger , fetchHandler : fetch)
41
43
}
42
44
43
45
/// Updates the authorization header.
@@ -64,10 +66,10 @@ public actor FunctionsClient {
64
66
options: FunctionInvokeOptions = . init( ) ,
65
67
decode: ( Data , HTTPURLResponse ) throws -> Response
66
68
) async throws -> Response {
67
- let ( data , response) = try await rawInvoke (
69
+ let response = try await rawInvoke (
68
70
functionName: functionName, invokeOptions: options
69
71
)
70
- return try decode ( data, response)
72
+ return try decode ( response . data, response . response)
71
73
}
72
74
73
75
/// Invokes a function and decodes the response as a specific type.
@@ -102,34 +104,40 @@ public actor FunctionsClient {
102
104
private func rawInvoke(
103
105
functionName: String ,
104
106
invokeOptions: FunctionInvokeOptions
105
- ) async throws -> ( Data , HTTPURLResponse ) {
106
- let url = url. appendingPathComponent ( functionName)
107
- var urlRequest = URLRequest ( url: url)
108
- urlRequest. allHTTPHeaderFields = invokeOptions. headers. merging ( headers) { invoke, _ in invoke }
109
- urlRequest. httpMethod = ( invokeOptions. method ?? . post) . rawValue
110
- urlRequest. httpBody = invokeOptions. body
111
-
112
- let ( data, response) = try await fetch ( urlRequest)
113
-
114
- guard let httpResponse = response as? HTTPURLResponse else {
115
- throw URLError ( . badServerResponse)
116
- }
107
+ ) async throws -> Response {
108
+ let request = Request (
109
+ path: functionName,
110
+ method: . post,
111
+ headers: invokeOptions. headers. merging ( headers) { invoke, _ in invoke } ,
112
+ body: invokeOptions. body
113
+ )
114
+ let response = try await http. fetch ( request, baseURL: url)
117
115
118
- guard 200 ..< 300 ~= httpResponse . statusCode else {
119
- throw FunctionsError . httpError ( code: httpResponse . statusCode, data: data)
116
+ guard 200 ..< 300 ~= response . statusCode else {
117
+ throw FunctionsError . httpError ( code: response . statusCode, data: response . data)
120
118
}
121
119
122
- let isRelayError = httpResponse . value ( forHTTPHeaderField: " x-relay-error " ) == " true "
120
+ let isRelayError = response . response . value ( forHTTPHeaderField: " x-relay-error " ) == " true "
123
121
if isRelayError {
124
122
throw FunctionsError . relayError
125
123
}
126
124
127
- return ( data , httpResponse )
125
+ return response
128
126
}
129
-
130
- public func _invokeWithStream(
127
+
128
+ /// Invokes a function with streamed response.
129
+ ///
130
+ /// Function MUST return a `text/event-stream` content type for this method to work.
131
+ ///
132
+ /// - Parameters:
133
+ /// - functionName: The name of the function to invoke.
134
+ /// - invokeOptions: Options for invoking the function.
135
+ /// - Returns: A stream of Data.
136
+ ///
137
+ /// - Warning: Experimental method.
138
+ public func _invoke(
131
139
_ functionName: String ,
132
- options invokeOptions: FunctionInvokeOptions
140
+ options invokeOptions: FunctionInvokeOptions = . init ( )
133
141
) -> AsyncThrowingStream < Data , any Error > {
134
142
let ( stream, continuation) = AsyncThrowingStream < Data , any Error > . makeStream ( )
135
143
let delegate = StreamResponseDelegate ( continuation: continuation)
@@ -142,7 +150,24 @@ public actor FunctionsClient {
142
150
urlRequest. httpMethod = ( invokeOptions. method ?? . post) . rawValue
143
151
urlRequest. httpBody = invokeOptions. body
144
152
145
- let task = session. dataTask ( with: urlRequest)
153
+ let task = session. dataTask ( with: urlRequest) { data, response, _ in
154
+ guard let httpResponse = response as? HTTPURLResponse else {
155
+ continuation. finish ( throwing: URLError ( . badServerResponse) )
156
+ return
157
+ }
158
+
159
+ guard 200 ..< 300 ~= httpResponse. statusCode else {
160
+ let error = FunctionsError . httpError ( code: httpResponse. statusCode, data: data ?? Data ( ) )
161
+ continuation. finish ( throwing: error)
162
+ return
163
+ }
164
+
165
+ let isRelayError = httpResponse. value ( forHTTPHeaderField: " x-relay-error " ) == " true "
166
+ if isRelayError {
167
+ continuation. finish ( throwing: FunctionsError . relayError)
168
+ }
169
+ }
170
+
146
171
task. resume ( )
147
172
148
173
continuation. onTermination = { _ in
0 commit comments