react-native-nitro-fetch 0.1.7 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/android/src/main/java/com/margelo/nitro/nitrofetch/AutoPrefetcher.kt +3 -1
  2. package/android/src/main/java/com/margelo/nitro/nitrofetch/CronetExtensions.kt +31 -0
  3. package/android/src/main/java/com/margelo/nitro/nitrofetch/NitroCronet.kt +89 -0
  4. package/android/src/main/java/com/margelo/nitro/nitrofetch/NitroFetchClient.kt +115 -28
  5. package/android/src/main/java/com/margelo/nitro/nitrofetch/NitroUrlRequest.kt +35 -0
  6. package/android/src/main/java/com/margelo/nitro/nitrofetch/NitroUrlRequestBuilder.kt +181 -0
  7. package/ios/HybridNitroCronet.swift +31 -0
  8. package/ios/HybridUrlRequest.swift +41 -0
  9. package/ios/HybridUrlRequestBuilder.swift +255 -0
  10. package/ios/NitroAutoPrefetcher.swift +3 -1
  11. package/ios/NitroFetchClient.swift +87 -5
  12. package/ios/URLSessionExtensions.swift +36 -0
  13. package/lib/module/NitroCronet.nitro.js +4 -0
  14. package/lib/module/NitroCronet.nitro.js.map +1 -0
  15. package/lib/module/NitroInstances.js +1 -0
  16. package/lib/module/NitroInstances.js.map +1 -1
  17. package/lib/module/fetch.js +179 -9
  18. package/lib/module/fetch.js.map +1 -1
  19. package/lib/typescript/src/NitroCronet.nitro.d.ts +53 -0
  20. package/lib/typescript/src/NitroCronet.nitro.d.ts.map +1 -0
  21. package/lib/typescript/src/NitroFetch.nitro.d.ts +10 -0
  22. package/lib/typescript/src/NitroFetch.nitro.d.ts.map +1 -1
  23. package/lib/typescript/src/NitroInstances.d.ts +3 -1
  24. package/lib/typescript/src/NitroInstances.d.ts.map +1 -1
  25. package/lib/typescript/src/fetch.d.ts +5 -2
  26. package/lib/typescript/src/fetch.d.ts.map +1 -1
  27. package/lib/typescript/src/index.d.ts +1 -1
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/nitro.json +34 -6
  30. package/nitrogen/generated/android/c++/JFunc_void_UrlResponseInfo.hpp +82 -0
  31. package/nitrogen/generated/android/c++/JFunc_void_UrlResponseInfo_std__shared_ptr_ArrayBuffer__double.hpp +84 -0
  32. package/nitrogen/generated/android/c++/JFunc_void_UrlResponseInfo_std__string.hpp +82 -0
  33. package/nitrogen/generated/android/c++/JFunc_void_std__optional_UrlResponseInfo_.hpp +83 -0
  34. package/nitrogen/generated/android/c++/JFunc_void_std__optional_UrlResponseInfo__RequestException.hpp +85 -0
  35. package/nitrogen/generated/android/c++/JHttpHeader.hpp +61 -0
  36. package/nitrogen/generated/android/c++/JHybridNativeStorageSpec.cpp +23 -16
  37. package/nitrogen/generated/android/c++/JHybridNativeStorageSpec.hpp +20 -21
  38. package/nitrogen/generated/android/c++/JHybridNitroCronetSpec.cpp +57 -0
  39. package/nitrogen/generated/android/c++/JHybridNitroCronetSpec.hpp +63 -0
  40. package/nitrogen/generated/android/c++/JHybridNitroFetchClientSpec.cpp +32 -16
  41. package/nitrogen/generated/android/c++/JHybridNitroFetchClientSpec.hpp +21 -21
  42. package/nitrogen/generated/android/c++/JHybridNitroFetchSpec.cpp +22 -15
  43. package/nitrogen/generated/android/c++/JHybridNitroFetchSpec.hpp +20 -21
  44. package/nitrogen/generated/android/c++/JHybridUrlRequestBuilderSpec.cpp +123 -0
  45. package/nitrogen/generated/android/c++/JHybridUrlRequestBuilderSpec.hpp +73 -0
  46. package/nitrogen/generated/android/c++/JHybridUrlRequestSpec.cpp +69 -0
  47. package/nitrogen/generated/android/c++/JHybridUrlRequestSpec.hpp +67 -0
  48. package/nitrogen/generated/android/c++/JNitroFormDataPart.hpp +74 -0
  49. package/nitrogen/generated/android/c++/JNitroHeader.hpp +7 -3
  50. package/nitrogen/generated/android/c++/JNitroRequest.hpp +39 -6
  51. package/nitrogen/generated/android/c++/JNitroRequestMethod.hpp +9 -10
  52. package/nitrogen/generated/android/c++/JNitroResponse.hpp +9 -4
  53. package/nitrogen/generated/android/c++/JRequestException.hpp +57 -0
  54. package/nitrogen/generated/android/c++/JUrlResponseInfo.hpp +146 -0
  55. package/nitrogen/generated/android/c++/JVariant_ArrayBuffer_String.cpp +26 -0
  56. package/nitrogen/generated/android/c++/JVariant_ArrayBuffer_String.hpp +70 -0
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Func_void_UrlResponseInfo.kt +80 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Func_void_UrlResponseInfo_std__shared_ptr_ArrayBuffer__double.kt +80 -0
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Func_void_UrlResponseInfo_std__string.kt +80 -0
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Func_void_std__optional_UrlResponseInfo_.kt +80 -0
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Func_void_std__optional_UrlResponseInfo__RequestException.kt +80 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HttpHeader.kt +41 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridNativeStorageSpec.kt +18 -16
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridNitroCronetSpec.kt +54 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridNitroFetchClientSpec.kt +23 -16
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridNitroFetchSpec.kt +18 -16
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridUrlRequestBuilderSpec.kt +125 -0
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/HybridUrlRequestSpec.kt +70 -0
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/NitroFormDataPart.kt +50 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/NitroHeader.kt +19 -10
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/NitroRequest.kt +40 -25
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/NitroRequestMethod.kt +3 -1
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/NitroResponse.kt +39 -30
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/RequestException.kt +38 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/UrlResponseInfo.kt +65 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/Variant_ArrayBuffer_String.kt +53 -0
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrofetch/nitrofetchOnLoad.kt +1 -1
  78. package/nitrogen/generated/android/nitrofetch+autolinking.cmake +8 -1
  79. package/nitrogen/generated/android/nitrofetch+autolinking.gradle +1 -1
  80. package/nitrogen/generated/android/nitrofetchOnLoad.cpp +85 -33
  81. package/nitrogen/generated/android/nitrofetchOnLoad.hpp +14 -5
  82. package/nitrogen/generated/ios/NitroFetch+autolinking.rb +2 -2
  83. package/nitrogen/generated/ios/NitroFetch-Swift-Cxx-Bridge.cpp +102 -10
  84. package/nitrogen/generated/ios/NitroFetch-Swift-Cxx-Bridge.hpp +359 -24
  85. package/nitrogen/generated/ios/NitroFetch-Swift-Cxx-Umbrella.hpp +32 -1
  86. package/nitrogen/generated/ios/NitroFetchAutolinking.mm +9 -1
  87. package/nitrogen/generated/ios/NitroFetchAutolinking.swift +29 -22
  88. package/nitrogen/generated/ios/c++/HybridNativeStorageSpecSwift.cpp +1 -1
  89. package/nitrogen/generated/ios/c++/HybridNativeStorageSpecSwift.hpp +10 -1
  90. package/nitrogen/generated/ios/c++/HybridNitroCronetSpecSwift.cpp +11 -0
  91. package/nitrogen/generated/ios/c++/HybridNitroCronetSpecSwift.hpp +85 -0
  92. package/nitrogen/generated/ios/c++/HybridNitroFetchClientSpecSwift.cpp +1 -1
  93. package/nitrogen/generated/ios/c++/HybridNitroFetchClientSpecSwift.hpp +22 -4
  94. package/nitrogen/generated/ios/c++/HybridNitroFetchSpecSwift.cpp +1 -1
  95. package/nitrogen/generated/ios/c++/HybridNitroFetchSpecSwift.hpp +10 -1
  96. package/nitrogen/generated/ios/c++/HybridUrlRequestBuilderSpecSwift.cpp +11 -0
  97. package/nitrogen/generated/ios/c++/HybridUrlRequestBuilderSpecSwift.hpp +163 -0
  98. package/nitrogen/generated/ios/c++/HybridUrlRequestSpecSwift.cpp +11 -0
  99. package/nitrogen/generated/ios/c++/HybridUrlRequestSpecSwift.hpp +106 -0
  100. package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
  101. package/nitrogen/generated/ios/swift/Func_void_NitroResponse.swift +1 -2
  102. package/nitrogen/generated/ios/swift/Func_void_UrlResponseInfo.swift +46 -0
  103. package/nitrogen/generated/ios/swift/Func_void_UrlResponseInfo_std__shared_ptr_ArrayBuffer__double.swift +46 -0
  104. package/nitrogen/generated/ios/swift/Func_void_UrlResponseInfo_std__string.swift +46 -0
  105. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
  106. package/nitrogen/generated/ios/swift/Func_void_std__optional_UrlResponseInfo_.swift +46 -0
  107. package/nitrogen/generated/ios/swift/Func_void_std__optional_UrlResponseInfo__RequestException.swift +46 -0
  108. package/nitrogen/generated/ios/swift/HttpHeader.swift +34 -0
  109. package/nitrogen/generated/ios/swift/HybridNativeStorageSpec.swift +10 -4
  110. package/nitrogen/generated/ios/swift/HybridNativeStorageSpec_cxx.swift +18 -3
  111. package/nitrogen/generated/ios/swift/HybridNitroCronetSpec.swift +55 -0
  112. package/nitrogen/generated/ios/swift/HybridNitroCronetSpec_cxx.swift +141 -0
  113. package/nitrogen/generated/ios/swift/HybridNitroFetchClientSpec.swift +11 -4
  114. package/nitrogen/generated/ios/swift/HybridNitroFetchClientSpec_cxx.swift +29 -3
  115. package/nitrogen/generated/ios/swift/HybridNitroFetchSpec.swift +10 -4
  116. package/nitrogen/generated/ios/swift/HybridNitroFetchSpec_cxx.swift +18 -3
  117. package/nitrogen/generated/ios/swift/HybridUrlRequestBuilderSpec.swift +65 -0
  118. package/nitrogen/generated/ios/swift/HybridUrlRequestBuilderSpec_cxx.swift +305 -0
  119. package/nitrogen/generated/ios/swift/HybridUrlRequestSpec.swift +59 -0
  120. package/nitrogen/generated/ios/swift/HybridUrlRequestSpec_cxx.swift +182 -0
  121. package/nitrogen/generated/ios/swift/NitroFormDataPart.swift +101 -0
  122. package/nitrogen/generated/ios/swift/NitroHeader.swift +5 -17
  123. package/nitrogen/generated/ios/swift/NitroRequest.swift +111 -121
  124. package/nitrogen/generated/ios/swift/NitroRequestMethod.swift +1 -1
  125. package/nitrogen/generated/ios/swift/NitroResponse.swift +40 -97
  126. package/nitrogen/generated/ios/swift/RequestException.swift +29 -0
  127. package/nitrogen/generated/ios/swift/UrlResponseInfo.swift +118 -0
  128. package/nitrogen/generated/ios/swift/Variant_ArrayBuffer_String.swift +18 -0
  129. package/nitrogen/generated/shared/c++/HttpHeader.hpp +87 -0
  130. package/nitrogen/generated/shared/c++/HybridNativeStorageSpec.cpp +1 -1
  131. package/nitrogen/generated/shared/c++/HybridNativeStorageSpec.hpp +1 -1
  132. package/nitrogen/generated/shared/c++/HybridNitroCronetSpec.cpp +21 -0
  133. package/nitrogen/generated/shared/c++/HybridNitroCronetSpec.hpp +65 -0
  134. package/nitrogen/generated/shared/c++/HybridNitroFetchClientSpec.cpp +2 -1
  135. package/nitrogen/generated/shared/c++/HybridNitroFetchClientSpec.hpp +3 -1
  136. package/nitrogen/generated/shared/c++/HybridNitroFetchSpec.cpp +1 -1
  137. package/nitrogen/generated/shared/c++/HybridNitroFetchSpec.hpp +1 -1
  138. package/nitrogen/generated/shared/c++/HybridUrlRequestBuilderSpec.cpp +31 -0
  139. package/nitrogen/generated/shared/c++/HybridUrlRequestBuilderSpec.hpp +85 -0
  140. package/nitrogen/generated/shared/c++/HybridUrlRequestSpec.cpp +25 -0
  141. package/nitrogen/generated/shared/c++/HybridUrlRequestSpec.hpp +66 -0
  142. package/nitrogen/generated/shared/c++/NitroFormDataPart.hpp +100 -0
  143. package/nitrogen/generated/shared/c++/NitroHeader.hpp +24 -8
  144. package/nitrogen/generated/shared/c++/NitroRequest.hpp +51 -24
  145. package/nitrogen/generated/shared/c++/NitroRequestMethod.hpp +1 -1
  146. package/nitrogen/generated/shared/c++/NitroResponse.hpp +42 -26
  147. package/nitrogen/generated/shared/c++/RequestException.hpp +83 -0
  148. package/nitrogen/generated/shared/c++/UrlResponseInfo.hpp +123 -0
  149. package/package.json +13 -10
  150. package/src/NitroCronet.nitro.ts +72 -0
  151. package/src/NitroFetch.nitro.ts +28 -6
  152. package/src/NitroInstances.ts +4 -0
  153. package/src/fetch.ts +214 -13
  154. package/src/index.tsx +1 -1
@@ -0,0 +1,255 @@
1
+ import Foundation
2
+ import NitroModules
3
+
4
+ class HybridUrlRequestBuilder: HybridUrlRequestBuilderSpec {
5
+ private let url: String
6
+ private let session: URLSession
7
+ private let executor: DispatchQueue
8
+
9
+ // Callbacks stored as optionals and set via setter methods
10
+ private var onRedirectReceivedCallback: ((_ info: UrlResponseInfo, _ newLocationUrl: String) -> Void)?
11
+ private var onResponseStartedCallback: ((_ info: UrlResponseInfo) -> Void)?
12
+ private var onReadCompletedCallback: ((_ info: UrlResponseInfo, _ byteBuffer: ArrayBuffer, _ bytesRead: Double) -> Void)?
13
+ private var onSucceededCallback: ((_ info: UrlResponseInfo) -> Void)?
14
+ private var onFailedCallback: ((_ info: UrlResponseInfo?, _ error: RequestException) -> Void)?
15
+ private var onCanceledCallback: ((_ info: UrlResponseInfo?) -> Void)?
16
+
17
+ private var urlRequest: URLRequest
18
+ private var priority: Float = 0.5
19
+
20
+ init(
21
+ url: String,
22
+ session: URLSession,
23
+ executor: DispatchQueue
24
+ ) {
25
+ self.url = url
26
+ self.session = session
27
+ self.executor = executor
28
+
29
+ guard let urlObj = URL(string: url) else {
30
+ fatalError("Invalid URL: \(url)")
31
+ }
32
+ self.urlRequest = URLRequest(url: urlObj)
33
+ }
34
+
35
+ // MARK: - Callback Setters
36
+ // Each setter takes only 1 callback to avoid Swift compiler bug (crashes with 4+ callbacks)
37
+
38
+ func onSucceeded(callback: @escaping (_ info: UrlResponseInfo) -> Void) {
39
+ self.onSucceededCallback = callback
40
+ }
41
+
42
+ func onFailed(callback: @escaping (_ info: UrlResponseInfo?, _ error: RequestException) -> Void) {
43
+ self.onFailedCallback = callback
44
+ }
45
+
46
+ func onCanceled(callback: @escaping (_ info: UrlResponseInfo?) -> Void) {
47
+ self.onCanceledCallback = callback
48
+ }
49
+
50
+ func onRedirectReceived(callback: @escaping (_ info: UrlResponseInfo, _ newLocationUrl: String) -> Void) {
51
+ self.onRedirectReceivedCallback = callback
52
+ }
53
+
54
+ func onResponseStarted(callback: @escaping (_ info: UrlResponseInfo) -> Void) {
55
+ self.onResponseStartedCallback = callback
56
+ }
57
+
58
+ func onReadCompleted(callback: @escaping (_ info: UrlResponseInfo, _ byteBuffer: ArrayBuffer, _ bytesRead: Double) -> Void) {
59
+ self.onReadCompletedCallback = callback
60
+ }
61
+
62
+ func setHttpMethod(httpMethod: String) throws {
63
+ self.urlRequest.httpMethod = httpMethod
64
+ }
65
+
66
+ func addHeader(name: String, value: String) throws {
67
+ self.urlRequest.addValue(value, forHTTPHeaderField: name)
68
+ }
69
+
70
+ func setUploadBody(body: Variant_ArrayBuffer_String) throws {
71
+ switch body {
72
+ case .first(let arrayBuffer):
73
+ self.urlRequest.httpBody = arrayBuffer.toData(copyIfNeeded: true)
74
+ case .second(let string):
75
+ self.urlRequest.httpBody = string.data(using: .utf8)
76
+ }
77
+ }
78
+
79
+ func disableCache() throws {
80
+ self.urlRequest.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
81
+ }
82
+
83
+ func build() throws -> any HybridUrlRequestSpec {
84
+ let delegate = URLSessionDelegateAdapter(
85
+ onRedirectReceived: onRedirectReceivedCallback,
86
+ onResponseStarted: onResponseStartedCallback,
87
+ onReadCompleted: onReadCompletedCallback,
88
+ onSucceeded: onSucceededCallback,
89
+ onFailed: onFailedCallback,
90
+ onCanceled: onCanceledCallback,
91
+ executor: executor,
92
+ hybridRequest: nil
93
+ )
94
+
95
+ let config = URLSessionConfiguration.default
96
+ config.urlCache = session.configuration.urlCache
97
+ config.requestCachePolicy = urlRequest.cachePolicy
98
+
99
+ let delegateSession = URLSession(
100
+ configuration: config,
101
+ delegate: delegate,
102
+ delegateQueue: nil
103
+ )
104
+
105
+ let task: URLSessionDataTask = delegateSession.dataTask(with: urlRequest)
106
+
107
+ task.priority = priority
108
+ delegate.task = task
109
+
110
+ let request = HybridUrlRequest(task: task, delegate: delegate)
111
+ delegate.hybridRequest = request
112
+
113
+ return request
114
+ }
115
+ }
116
+
117
+ // MARK: - URLSession Delegate Adapter
118
+
119
+ private class URLSessionDelegateAdapter: NSObject, URLSessionDataDelegate, URLSessionTaskDelegate {
120
+ let onRedirectReceived: ((_ info: UrlResponseInfo, _ newLocationUrl: String) -> Void)?
121
+ let onResponseStarted: ((_ info: UrlResponseInfo) -> Void)?
122
+ let onReadCompleted: ((_ info: UrlResponseInfo, _ byteBuffer: ArrayBuffer, _ bytesRead: Double) -> Void)?
123
+ let onSucceeded: ((_ info: UrlResponseInfo) -> Void)?
124
+ let onFailed: ((_ info: UrlResponseInfo?, _ error: RequestException) -> Void)?
125
+ let onCanceled: ((_ info: UrlResponseInfo?) -> Void)?
126
+
127
+ let executor: DispatchQueue
128
+ weak var task: URLSessionDataTask?
129
+ weak var hybridRequest: HybridUrlRequest?
130
+
131
+ private var response: HTTPURLResponse?
132
+
133
+ init(
134
+ onRedirectReceived: ((_ info: UrlResponseInfo, _ newLocationUrl: String) -> Void)?,
135
+ onResponseStarted: ((_ info: UrlResponseInfo) -> Void)?,
136
+ onReadCompleted: ((_ info: UrlResponseInfo, _ byteBuffer: ArrayBuffer, _ bytesRead: Double) -> Void)?,
137
+ onSucceeded: ((_ info: UrlResponseInfo) -> Void)?,
138
+ onFailed: ((_ info: UrlResponseInfo?, _ error: RequestException) -> Void)?,
139
+ onCanceled: ((_ info: UrlResponseInfo?) -> Void)?,
140
+ executor: DispatchQueue,
141
+ hybridRequest: HybridUrlRequest?
142
+ ) {
143
+ self.onRedirectReceived = onRedirectReceived
144
+ self.onResponseStarted = onResponseStarted
145
+ self.onReadCompleted = onReadCompleted
146
+ self.onSucceeded = onSucceeded
147
+ self.onFailed = onFailed
148
+ self.onCanceled = onCanceled
149
+ self.executor = executor
150
+ self.hybridRequest = hybridRequest
151
+ super.init()
152
+ }
153
+
154
+ func urlSession(
155
+ _ session: URLSession,
156
+ task: URLSessionTask,
157
+ willPerformHTTPRedirection response: HTTPURLResponse,
158
+ newRequest request: URLRequest,
159
+ completionHandler: @escaping (URLRequest?) -> Void
160
+ ) {
161
+ executor.sync { [weak self] in
162
+ guard let self = self else { return }
163
+ if let callback = self.onRedirectReceived {
164
+ let info = response.toNitro()
165
+ let newUrl = request.url?.absoluteString ?? ""
166
+ callback(info, newUrl)
167
+ }
168
+ }
169
+ completionHandler(request)
170
+ }
171
+
172
+ func urlSession(
173
+ _ session: URLSession,
174
+ task: URLSessionTask,
175
+ didCompleteWithError error: Error?
176
+ ) {
177
+ executor.sync { [weak self] in
178
+ guard let self = self else { return }
179
+ self.hybridRequest?.markDone()
180
+
181
+ if let error = error {
182
+ let nsError = error as NSError
183
+ if nsError.code == NSURLErrorCancelled {
184
+ if let callback = self.onCanceled {
185
+ let nitroInfo = self.response?.toNitro()
186
+ callback(nitroInfo)
187
+ }
188
+ } else {
189
+ if let callback = self.onFailed {
190
+ let nitroError = error.toNitro()
191
+ let nitroInfo = self.response?.toNitro()
192
+ callback(nitroInfo, nitroError)
193
+ }
194
+ }
195
+ } else if let response = self.response {
196
+ if let callback = self.onSucceeded {
197
+ let info = response.toNitro()
198
+ callback(info)
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ func urlSession(
205
+ _ session: URLSession,
206
+ dataTask: URLSessionDataTask,
207
+ didReceive response: URLResponse,
208
+ completionHandler: @escaping (URLSession.ResponseDisposition) -> Void
209
+ ) {
210
+ guard let httpResponse = response as? HTTPURLResponse else {
211
+ completionHandler(.cancel)
212
+ return
213
+ }
214
+
215
+ self.response = httpResponse
216
+
217
+ executor.sync { [weak self] in
218
+ guard let self = self else { return }
219
+ if let callback = self.onResponseStarted {
220
+ let info = httpResponse.toNitro()
221
+ callback(info)
222
+ }
223
+ }
224
+
225
+ completionHandler(.allow)
226
+ }
227
+
228
+ func urlSession(
229
+ _ session: URLSession,
230
+ dataTask: URLSessionDataTask,
231
+ didReceive data: Data
232
+ ) {
233
+ if let callback = self.onReadCompleted {
234
+ executor.sync { [weak self] in
235
+ guard let self = self, let response = self.response else { return }
236
+
237
+ let arrayBuffer: ArrayBuffer
238
+ do {
239
+ arrayBuffer = try ArrayBuffer.copy(data: data)
240
+ } catch {
241
+ if let failedCallback = self.onFailed {
242
+ let nitroError = error.toNitro()
243
+ let nitroInfo = response.toNitro()
244
+ failedCallback(nitroInfo, nitroError)
245
+ }
246
+ return
247
+ }
248
+
249
+ let info = response.toNitro()
250
+ let bytesRead = Double(data.count)
251
+ callback(info, arrayBuffer, bytesRead)
252
+ }
253
+ }
254
+ }
255
+ }
@@ -29,8 +29,10 @@ public final class NitroAutoPrefetcher: NSObject {
29
29
  headers: headers,
30
30
  bodyString: nil,
31
31
  bodyBytes: nil,
32
+ bodyFormData: nil,
32
33
  timeoutMs: nil,
33
- followRedirects: true)
34
+ followRedirects: true,
35
+ requestId: nil)
34
36
  Task {
35
37
  do { try await NitroFetchClient.prefetchStatic(req) } catch { /* ignore – best effort */ }
36
38
  }
@@ -2,6 +2,29 @@ import Foundation
2
2
  import NitroModules
3
3
 
4
4
  final class NitroFetchClient: HybridNitroFetchClientSpec {
5
+
6
+ private var _lock = os_unfair_lock()
7
+ private var activeTasks: [String: Task<Void, Never>] = [:]
8
+
9
+ private func storeTask(_ task: Task<Void, Never>, forKey key: String) {
10
+ os_unfair_lock_lock(&_lock)
11
+ activeTasks[key] = task
12
+ os_unfair_lock_unlock(&_lock)
13
+ }
14
+
15
+ private func removeTask(forKey key: String) {
16
+ os_unfair_lock_lock(&_lock)
17
+ activeTasks.removeValue(forKey: key)
18
+ os_unfair_lock_unlock(&_lock)
19
+ }
20
+
21
+ func cancelRequest(requestId: String) throws {
22
+ os_unfair_lock_lock(&_lock)
23
+ let task = activeTasks.removeValue(forKey: requestId)
24
+ os_unfair_lock_unlock(&_lock)
25
+ task?.cancel()
26
+ }
27
+
5
28
  func requestSync(req: NitroRequest) throws -> NitroResponse {
6
29
  let semaphore = DispatchSemaphore(value: 0)
7
30
  var result: Result<NitroResponse, Error>?
@@ -29,7 +52,14 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
29
52
  // Async version - returns Promise<NitroResponse>
30
53
  func request(req: NitroRequest) throws -> Promise<NitroResponse> {
31
54
  let promise = Promise<NitroResponse>.init()
32
- Task {
55
+ let requestId = req.requestId
56
+
57
+ let task = Task { [weak self] in
58
+ defer {
59
+ if let rid = requestId {
60
+ self?.removeTask(forKey: rid)
61
+ }
62
+ }
33
63
  do {
34
64
  let response = try await NitroFetchClient.requestStatic(req)
35
65
  promise.resolve(withResult: response)
@@ -37,6 +67,10 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
37
67
  promise.reject(withError: error)
38
68
  }
39
69
  }
70
+
71
+ if let rid = requestId {
72
+ storeTask(task, forKey: rid)
73
+ }
40
74
  return promise
41
75
  }
42
76
 
@@ -119,7 +153,7 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
119
153
  }
120
154
  }
121
155
 
122
- let (urlRequest, finalURL) = try buildURLRequest(req)
156
+ let (urlRequest, finalURL) = try await buildURLRequest(req)
123
157
  let (data, response) = try await session.data(for: urlRequest)
124
158
  guard let http = response as? HTTPURLResponse else {
125
159
  throw NSError(domain: "NitroFetch", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
@@ -167,7 +201,7 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
167
201
  FetchCache.addPending(key) { _ in /* ignored here */ }
168
202
  Task.detached {
169
203
  do {
170
- let (urlRequest, finalURL) = try buildURLRequest(req)
204
+ let (urlRequest, finalURL) = try await buildURLRequest(req)
171
205
  let (data, response) = try await session.data(for: urlRequest)
172
206
  guard let http = response as? HTTPURLResponse else {
173
207
  throw NSError(domain: "NitroFetch", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
@@ -199,7 +233,7 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
199
233
  return req.method?.stringValue
200
234
  }
201
235
 
202
- private static func buildURLRequest(_ req: NitroRequest) throws -> (URLRequest, URL?) {
236
+ private static func buildURLRequest(_ req: NitroRequest) async throws -> (URLRequest, URL?) {
203
237
  guard let url = URL(string: req.url) else {
204
238
  throw NSError(domain: "NitroFetch", code: -3, userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(req.url)"])
205
239
  }
@@ -208,13 +242,61 @@ final class NitroFetchClient: HybridNitroFetchClientSpec {
208
242
  if let headers = req.headers {
209
243
  for h in headers { r.addValue(h.value, forHTTPHeaderField: h.key) }
210
244
  }
211
- if let s = req.bodyString {
245
+ if let parts = req.bodyFormData, !parts.isEmpty {
246
+ let (body, contentType) = try await buildMultipartBody(parts)
247
+ r.httpBody = body
248
+ r.setValue(contentType, forHTTPHeaderField: "Content-Type")
249
+ } else if let s = req.bodyString {
212
250
  r.httpBody = s.data(using: .utf8)
213
251
  }
214
252
  if let t = req.timeoutMs, t > 0 { r.timeoutInterval = TimeInterval(t) / 1000.0 }
215
253
  return (r, nil)
216
254
  }
217
255
 
256
+ private static func buildMultipartBody(_ parts: [NitroFormDataPart]) async throws -> (Data, String) {
257
+ let boundary = "NitroFetch-\(UUID().uuidString)"
258
+ var body = Data()
259
+ let crlf = "\r\n"
260
+
261
+ for part in parts {
262
+ body.append("--\(boundary)\(crlf)".data(using: .utf8)!)
263
+
264
+ if let fileUri = part.fileUri {
265
+ let fileName = part.fileName ?? "file"
266
+ let mimeType = part.mimeType ?? "application/octet-stream"
267
+ body.append("Content-Disposition: form-data; name=\"\(part.name)\"; filename=\"\(fileName)\"\(crlf)".data(using: .utf8)!)
268
+ body.append("Content-Type: \(mimeType)\(crlf)\(crlf)".data(using: .utf8)!)
269
+
270
+ let fileData = try await readFileData(fileUri)
271
+ body.append(fileData)
272
+ } else {
273
+ let value = part.value ?? ""
274
+ body.append("Content-Disposition: form-data; name=\"\(part.name)\"\(crlf)\(crlf)".data(using: .utf8)!)
275
+ body.append(value.data(using: .utf8)!)
276
+ }
277
+
278
+ body.append(crlf.data(using: .utf8)!)
279
+ }
280
+
281
+ body.append("--\(boundary)--\(crlf)".data(using: .utf8)!)
282
+ return (body, "multipart/form-data; boundary=\(boundary)")
283
+ }
284
+
285
+ private static func readFileData(_ uri: String) async throws -> Data {
286
+ if uri.hasPrefix("http://") || uri.hasPrefix("https://") {
287
+ guard let url = URL(string: uri) else {
288
+ throw NSError(domain: "NitroFetch", code: -4, userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(uri)"])
289
+ }
290
+ let (data, _) = try await session.data(from: url)
291
+ return data
292
+ }
293
+ let path = uri.hasPrefix("file://") ? String(uri.dropFirst(7)) : uri
294
+ guard let data = FileManager.default.contents(atPath: path) else {
295
+ throw NSError(domain: "NitroFetch", code: -4, userInfo: [NSLocalizedDescriptionKey: "Cannot read file at: \(uri)"])
296
+ }
297
+ return data
298
+ }
299
+
218
300
  private static func detectCharset(from http: HTTPURLResponse) -> String.Encoding? {
219
301
  if let ct = http.value(forHTTPHeaderField: "Content-Type")?.lowercased() {
220
302
  if let range = ct.range(of: "charset=") {
@@ -0,0 +1,36 @@
1
+ import Foundation
2
+ import NitroModules
3
+
4
+ extension HTTPURLResponse {
5
+ func toNitro() -> UrlResponseInfo {
6
+ let headersMap = allHeaderFields.reduce(into: [String: String]()) { result, pair in
7
+ if let key = pair.key as? String {
8
+ result[key] = String(describing: pair.value)
9
+ }
10
+ }
11
+
12
+ let headersList = allHeaderFields.compactMap { pair -> HttpHeader? in
13
+ guard let key = pair.key as? String else { return nil }
14
+ return HttpHeader(key: key, value: String(describing: pair.value))
15
+ }
16
+
17
+ return UrlResponseInfo(
18
+ url: url?.absoluteString ?? "",
19
+ httpStatusCode: Double(statusCode),
20
+ httpStatusText: HTTPURLResponse.localizedString(forStatusCode: statusCode),
21
+ allHeaders: headersMap,
22
+ allHeadersAsList: headersList,
23
+ urlChain: [url?.absoluteString ?? ""],
24
+ negotiatedProtocol: "",
25
+ proxyServer: "",
26
+ receivedByteCount: Double(expectedContentLength),
27
+ wasCached: false
28
+ )
29
+ }
30
+ }
31
+
32
+ extension Error {
33
+ func toNitro() -> RequestException {
34
+ return RequestException(message: localizedDescription)
35
+ }
36
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=NitroCronet.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["NitroCronet.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -5,4 +5,5 @@ import { NitroModules } from 'react-native-nitro-modules';
5
5
  export const NitroFetch = NitroModules.createHybridObject('NitroFetch');
6
6
  export const NativeStorage = NitroModules.createHybridObject('NativeStorage');
7
7
  export const boxedNitroFetch = NitroModules.box(NitroFetch);
8
+ export const NitroCronetSingleton = NitroModules.createHybridObject('NitroCronet');
8
9
  //# sourceMappingURL=NitroInstances.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NitroModules","NitroFetch","createHybridObject","NativeStorage","boxedNitroFetch","box"],"sourceRoot":"../../src","sources":["NitroInstances.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAMzD;AACA,OAAO,MAAMC,UAA0B,GACrCD,YAAY,CAACE,kBAAkB,CAAiB,YAAY,CAAC;AAE/D,OAAO,MAAMC,aAAgC,GAC3CH,YAAY,CAACE,kBAAkB,CAAoB,eAAe,CAAC;AAErE,OAAO,MAAME,eAAe,GAAGJ,YAAY,CAACK,GAAG,CAACJ,UAAU,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["NitroModules","NitroFetch","createHybridObject","NativeStorage","boxedNitroFetch","box","NitroCronetSingleton"],"sourceRoot":"../../src","sources":["NitroInstances.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAOzD;AACA,OAAO,MAAMC,UAA0B,GACrCD,YAAY,CAACE,kBAAkB,CAAiB,YAAY,CAAC;AAE/D,OAAO,MAAMC,aAAgC,GAC3CH,YAAY,CAACE,kBAAkB,CAAoB,eAAe,CAAC;AAErE,OAAO,MAAME,eAAe,GAAGJ,YAAY,CAACK,GAAG,CAACJ,UAAU,CAAC;AAE3D,OAAO,MAAMK,oBAAoB,GAC/BN,YAAY,CAACE,kBAAkB,CAAc,aAAa,CAAC","ignoreList":[]}