one 2.0.0-beta.106.1 → 2.0.0-beta.107.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 (81) hide show
  1. package/android/src/main/java/com/margelo/nitro/one/HybridOneFetch.kt +250 -0
  2. package/dist/cjs/platform/fetch/index.cjs +24 -0
  3. package/dist/cjs/platform/fetch/index.native.cjs +434 -0
  4. package/dist/cjs/platform/fetch/index.native.js +436 -0
  5. package/dist/cjs/platform/fetch/index.native.js.map +1 -0
  6. package/dist/cjs/platform/specs/OneFetch.nitro.cjs +16 -0
  7. package/dist/cjs/platform/specs/OneFetch.nitro.native.cjs +18 -0
  8. package/dist/cjs/platform/specs/OneFetch.nitro.native.js +20 -0
  9. package/dist/cjs/platform/specs/OneFetch.nitro.native.js.map +1 -0
  10. package/dist/cjs/polyfills-mobile.cjs +2 -0
  11. package/dist/cjs/polyfills-mobile.native.cjs +2 -0
  12. package/dist/cjs/polyfills-mobile.native.js +2 -0
  13. package/dist/cjs/polyfills-mobile.native.js.map +1 -1
  14. package/dist/esm/platform/fetch/index.mjs +4 -0
  15. package/dist/esm/platform/fetch/index.mjs.map +1 -0
  16. package/dist/esm/platform/fetch/index.native.js +407 -0
  17. package/dist/esm/platform/fetch/index.native.js.map +1 -0
  18. package/dist/esm/platform/specs/OneFetch.nitro.mjs +0 -0
  19. package/dist/esm/platform/specs/OneFetch.nitro.native.js +0 -0
  20. package/dist/esm/polyfills-mobile.mjs +2 -0
  21. package/dist/esm/polyfills-mobile.mjs.map +1 -1
  22. package/dist/esm/polyfills-mobile.native.js +2 -0
  23. package/dist/esm/polyfills-mobile.native.js.map +1 -1
  24. package/ios/Nitro/HybridOneFetch.swift +264 -0
  25. package/ios/OneFetchBlobStoreModule.mm +28 -0
  26. package/nitrogen/generated/android/One+autolinking.cmake +2 -0
  27. package/nitrogen/generated/android/OneOnLoad.cpp +22 -0
  28. package/nitrogen/generated/android/c++/JFetchBlobRef.hpp +65 -0
  29. package/nitrogen/generated/android/c++/JFetchFormPart.hpp +80 -0
  30. package/nitrogen/generated/android/c++/JFetchHeader.hpp +61 -0
  31. package/nitrogen/generated/android/c++/JFetchNativeRequest.hpp +131 -0
  32. package/nitrogen/generated/android/c++/JFetchNativeResponse.hpp +94 -0
  33. package/nitrogen/generated/android/c++/JFunc_void_FetchNativeResponse.hpp +81 -0
  34. package/nitrogen/generated/android/c++/JFunc_void_std__shared_ptr_ArrayBuffer_.hpp +77 -0
  35. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  36. package/nitrogen/generated/android/c++/JHybridOneFetchSpec.cpp +90 -0
  37. package/nitrogen/generated/android/c++/JHybridOneFetchSpec.hpp +65 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/FetchBlobRef.kt +61 -0
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/FetchFormPart.kt +76 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/FetchHeader.kt +56 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/FetchNativeRequest.kt +86 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/FetchNativeResponse.kt +71 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/Func_void_FetchNativeResponse.kt +78 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/Func_void_std__shared_ptr_ArrayBuffer_.kt +78 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/Func_void_std__string.kt +78 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/one/HybridOneFetchSpec.kt +70 -0
  47. package/nitrogen/generated/ios/One-Swift-Cxx-Bridge.cpp +33 -0
  48. package/nitrogen/generated/ios/One-Swift-Cxx-Bridge.hpp +152 -0
  49. package/nitrogen/generated/ios/One-Swift-Cxx-Umbrella.hpp +20 -0
  50. package/nitrogen/generated/ios/OneAutolinking.mm +8 -0
  51. package/nitrogen/generated/ios/OneAutolinking.swift +12 -0
  52. package/nitrogen/generated/ios/c++/HybridOneFetchSpecSwift.cpp +11 -0
  53. package/nitrogen/generated/ios/c++/HybridOneFetchSpecSwift.hpp +115 -0
  54. package/nitrogen/generated/ios/swift/FetchBlobRef.swift +39 -0
  55. package/nitrogen/generated/ios/swift/FetchFormPart.swift +112 -0
  56. package/nitrogen/generated/ios/swift/FetchHeader.swift +34 -0
  57. package/nitrogen/generated/ios/swift/FetchNativeRequest.swift +121 -0
  58. package/nitrogen/generated/ios/swift/FetchNativeResponse.swift +55 -0
  59. package/nitrogen/generated/ios/swift/Func_void_FetchNativeResponse.swift +46 -0
  60. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_ArrayBuffer_.swift +46 -0
  61. package/nitrogen/generated/ios/swift/HybridOneFetchSpec.swift +57 -0
  62. package/nitrogen/generated/ios/swift/HybridOneFetchSpec_cxx.swift +180 -0
  63. package/nitrogen/generated/shared/c++/FetchBlobRef.hpp +91 -0
  64. package/nitrogen/generated/shared/c++/FetchFormPart.hpp +106 -0
  65. package/nitrogen/generated/shared/c++/FetchHeader.hpp +87 -0
  66. package/nitrogen/generated/shared/c++/FetchNativeRequest.hpp +122 -0
  67. package/nitrogen/generated/shared/c++/FetchNativeResponse.hpp +102 -0
  68. package/nitrogen/generated/shared/c++/HybridOneFetchSpec.cpp +23 -0
  69. package/nitrogen/generated/shared/c++/HybridOneFetchSpec.hpp +71 -0
  70. package/package.json +10 -10
  71. package/src/platform/README.md +38 -0
  72. package/src/platform/fetch/index.native.ts +345 -0
  73. package/src/platform/fetch/index.ts +2 -0
  74. package/src/platform/specs/OneFetch.nitro.ts +67 -0
  75. package/src/polyfills-mobile.ts +9 -0
  76. package/types/platform/fetch/index.d.ts +2 -0
  77. package/types/platform/fetch/index.d.ts.map +1 -0
  78. package/types/platform/fetch/index.native.d.ts +2 -0
  79. package/types/platform/fetch/index.native.d.ts.map +1 -0
  80. package/types/platform/specs/OneFetch.nitro.d.ts +44 -0
  81. package/types/platform/specs/OneFetch.nitro.d.ts.map +1 -0
@@ -0,0 +1,250 @@
1
+ package com.margelo.nitro.one
2
+
3
+ import android.net.Uri
4
+ import android.webkit.MimeTypeMap
5
+ import com.facebook.react.modules.blob.BlobModule
6
+ import com.facebook.react.modules.network.CookieJarContainer
7
+ import com.facebook.react.modules.network.ForwardingCookieHandler
8
+ import com.facebook.react.modules.network.OkHttpClientProvider
9
+ import com.margelo.nitro.NitroModules
10
+ import com.margelo.nitro.core.ArrayBuffer
11
+ import java.io.IOException
12
+ import java.io.InputStream
13
+ import java.util.concurrent.ConcurrentHashMap
14
+ import java.util.concurrent.Executors
15
+ import okhttp3.Call
16
+ import okhttp3.Callback
17
+ import okhttp3.OkHttpClient
18
+ import okhttp3.CookieJar
19
+ import okhttp3.Headers
20
+ import okhttp3.JavaNetCookieJar
21
+ import okhttp3.MediaType
22
+ import okhttp3.MediaType.Companion.toMediaTypeOrNull
23
+ import okhttp3.MultipartBody
24
+ import okhttp3.Request
25
+ import okhttp3.RequestBody
26
+ import okhttp3.RequestBody.Companion.toRequestBody
27
+ import okhttp3.Response
28
+ import okhttp3.internal.http.HttpMethod
29
+ import okio.BufferedSink
30
+
31
+ // the global fetch on native, over an OkHttp client built the way react
32
+ // native's NetworkingModule builds its own: from OkHttpClientProvider, so an
33
+ // app's OkHttpClientFactory (interceptors, certificate pinning) applies, with
34
+ // its cookie jar backed by the same CookieManager store react native uses. the response head goes to js first, then every chunk as the
35
+ // socket delivers it, so response.body streams. file: and content: urls are
36
+ // read from disk, as react native's fetch reads them.
37
+ class HybridOneFetch : HybridOneFetchSpec() {
38
+ // cancel actions for live requests; whoever removes an id owns its
39
+ // terminal event, so a cancelled request never reports
40
+ private val active = ConcurrentHashMap<Double, () -> Unit>()
41
+ private val local = Executors.newCachedThreadPool()
42
+
43
+ private val client: OkHttpClient by lazy {
44
+ OkHttpClientProvider.createClient().also {
45
+ (it.cookieJar as? CookieJarContainer)
46
+ ?.setCookieJar(JavaNetCookieJar(ForwardingCookieHandler()))
47
+ }
48
+ }
49
+ private val clientWithoutCookies: OkHttpClient by lazy {
50
+ client.newBuilder().cookieJar(CookieJar.NO_COOKIES).build()
51
+ }
52
+
53
+ private val context
54
+ get() = NitroModules.applicationContext
55
+ ?: throw IllegalStateException("fetch: the react context is not ready")
56
+
57
+ override fun start(
58
+ id: Double,
59
+ request: FetchNativeRequest,
60
+ onResponse: (response: FetchNativeResponse) -> Unit,
61
+ onChunk: (chunk: ArrayBuffer) -> Unit,
62
+ onComplete: () -> Unit,
63
+ onError: (message: String) -> Unit
64
+ ) {
65
+ val scheme = Uri.parse(request.url).scheme
66
+ if (scheme == "file" || scheme == "content") {
67
+ readLocal(id, request.url, onResponse, onChunk, onComplete, onError)
68
+ return
69
+ }
70
+ val built = try {
71
+ val builder = Request.Builder().url(request.url)
72
+ for (header in request.headers) builder.addHeader(header.name, header.value)
73
+ val type = request.headers
74
+ .lastOrNull { it.name.equals("content-type", ignoreCase = true) }
75
+ ?.value?.toMediaTypeOrNull()
76
+ builder.method(request.method, body(request, type))
77
+ builder.build()
78
+ } catch (error: IllegalArgumentException) {
79
+ onError(error.message ?: "invalid request")
80
+ return
81
+ }
82
+ val call = (if (request.omitCredentials) clientWithoutCookies else client).newCall(built)
83
+ active[id] = { call.cancel() }
84
+ call.enqueue(object : Callback {
85
+ override fun onFailure(call: Call, e: IOException) {
86
+ if (active.remove(id) != null) onError(e.message ?: e.javaClass.simpleName)
87
+ }
88
+
89
+ override fun onResponse(call: Call, response: Response) {
90
+ response.use {
91
+ if (!active.containsKey(id)) return
92
+ val headers = response.headers.map { (name, value) -> FetchHeader(name, value) }
93
+ onResponse(
94
+ FetchNativeResponse(
95
+ response.code.toDouble(),
96
+ response.message,
97
+ response.request.url.toString(),
98
+ response.priorResponse != null,
99
+ headers.toTypedArray()
100
+ )
101
+ )
102
+ pump(id, response.body?.byteStream(), onChunk, onComplete, onError)
103
+ }
104
+ }
105
+ })
106
+ }
107
+
108
+ override fun cancel(id: Double) {
109
+ active.remove(id)?.invoke()
110
+ }
111
+
112
+ override fun storeBlob(bytes: ArrayBuffer): String = blobModule().store(bytes.toByteArray())
113
+
114
+ private fun blobModule(): BlobModule =
115
+ context.getNativeModule(BlobModule::class.java)
116
+ ?: throw IllegalStateException("fetch: react native's BlobModule is not loaded")
117
+
118
+ // the request body. js-owned bytes are copied now, during the call;
119
+ // blobs, files and multipart parts are read on the network thread. every
120
+ // length is known up front where react native's was, so uploads carry a
121
+ // content-length rather than going out chunked.
122
+ private fun body(request: FetchNativeRequest, type: MediaType?): RequestBody? {
123
+ request.body?.let { return it.toByteArray().toRequestBody(type) }
124
+ request.blob?.let { return blobBody(it, type) }
125
+ val form = request.form
126
+ val boundary = request.boundary
127
+ if (form != null && boundary != null) return multipart(form, boundary)
128
+ return if (HttpMethod.requiresRequestBody(request.method)) ByteArray(0).toRequestBody(type)
129
+ else null
130
+ }
131
+
132
+ private fun blobBody(blob: FetchBlobRef, type: MediaType?) = object : RequestBody() {
133
+ override fun contentType() = type
134
+ override fun contentLength() = blob.size.toLong()
135
+ override fun writeTo(sink: BufferedSink) {
136
+ sink.write(resolve(blob))
137
+ }
138
+ }
139
+
140
+ private fun uriBody(uri: String, type: MediaType?) = object : RequestBody() {
141
+ override fun contentType() = type
142
+ override fun contentLength() =
143
+ context.contentResolver.openAssetFileDescriptor(Uri.parse(uri), "r")?.use { it.length }
144
+ ?: -1L
145
+ override fun writeTo(sink: BufferedSink) {
146
+ open(uri).use { input -> input.copyTo(sink.outputStream()) }
147
+ }
148
+ }
149
+
150
+ private fun resolve(blob: FetchBlobRef): ByteArray =
151
+ blobModule().resolve(blob.blobId, blob.offset.toInt(), blob.size.toInt())
152
+ ?: throw IOException("fetch: blob ${blob.blobId} is no longer in the store")
153
+
154
+ private fun open(uri: String): InputStream =
155
+ context.contentResolver.openInputStream(Uri.parse(uri))
156
+ ?: throw IOException("fetch: could not open $uri")
157
+
158
+ // multipart/form-data per RFC 7578 through okhttp's MultipartBody, as
159
+ // react native builds it, under the boundary js already put in the
160
+ // content-type header
161
+ private fun multipart(parts: Array<FetchFormPart>, boundary: String): RequestBody {
162
+ val builder = MultipartBody.Builder(boundary).setType(MultipartBody.FORM)
163
+ for (part in parts) {
164
+ var disposition = "form-data; name=\"${escape(part.name)}\""
165
+ val value = part.value
166
+ if (value != null) {
167
+ builder.addPart(Headers.headersOf("Content-Disposition", disposition), value.toRequestBody())
168
+ continue
169
+ }
170
+ val filename = part.filename ?: part.uri?.let { Uri.parse(it).lastPathSegment }
171
+ if (filename != null) disposition += "; filename=\"${escape(filename)}\""
172
+ val type = (part.type ?: "application/octet-stream").toMediaTypeOrNull()
173
+ val uri = part.uri
174
+ val blob = part.blob
175
+ val body = when {
176
+ uri != null -> uriBody(uri, type)
177
+ blob != null -> blobBody(blob, type)
178
+ else -> throw IOException("fetch: FormData part ${part.name} has no value")
179
+ }
180
+ builder.addPart(Headers.headersOf("Content-Disposition", disposition), body)
181
+ }
182
+ return builder.build()
183
+ }
184
+
185
+ private fun escape(value: String) =
186
+ value.replace("\"", "%22").replace("\r", "%0D").replace("\n", "%0A")
187
+
188
+ private fun readLocal(
189
+ id: Double,
190
+ url: String,
191
+ onResponse: (response: FetchNativeResponse) -> Unit,
192
+ onChunk: (chunk: ArrayBuffer) -> Unit,
193
+ onComplete: () -> Unit,
194
+ onError: (message: String) -> Unit
195
+ ) {
196
+ active[id] = {}
197
+ local.execute {
198
+ val input = try {
199
+ open(url)
200
+ } catch (error: Exception) {
201
+ if (active.remove(id) != null) onError(error.message ?: "could not open $url")
202
+ return@execute
203
+ }
204
+ input.use {
205
+ val uri = Uri.parse(url)
206
+ val type = context.contentResolver.getType(uri)
207
+ ?: MimeTypeMap.getSingleton().getMimeTypeFromExtension(
208
+ MimeTypeMap.getFileExtensionFromUrl(url)
209
+ )
210
+ val headers = type?.let { arrayOf(FetchHeader("content-type", it)) } ?: emptyArray()
211
+ if (!active.containsKey(id)) return@execute
212
+ onResponse(FetchNativeResponse(200.0, "", url, false, headers))
213
+ pump(id, input, onChunk, onComplete, onError)
214
+ }
215
+ }
216
+ }
217
+
218
+ private fun pump(
219
+ id: Double,
220
+ input: InputStream?,
221
+ onChunk: (chunk: ArrayBuffer) -> Unit,
222
+ onComplete: () -> Unit,
223
+ onError: (message: String) -> Unit
224
+ ) {
225
+ val buffer = ByteArray(CHUNK)
226
+ try {
227
+ while (input != null) {
228
+ val read = input.read(buffer)
229
+ if (read == -1) break
230
+ if (!active.containsKey(id)) return
231
+ if (read > 0) onChunk(ArrayBuffer.copy(buffer.copyOf(read)))
232
+ }
233
+ } catch (error: IOException) {
234
+ if (active.remove(id) != null) onError(error.message ?: error.javaClass.simpleName)
235
+ return
236
+ }
237
+ if (active.remove(id) != null) onComplete()
238
+ }
239
+
240
+ override fun dispose() {
241
+ active.values.forEach { it() }
242
+ active.clear()
243
+ local.shutdownNow()
244
+ super.dispose()
245
+ }
246
+
247
+ companion object {
248
+ private const val CHUNK = 16 * 1024
249
+ }
250
+ }
@@ -0,0 +1,24 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: () => from[key],
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+ var fetch_exports = {};
22
+ __export(fetch_exports, { installFetch: () => installFetch });
23
+ module.exports = __toCommonJS(fetch_exports);
24
+ function installFetch() {}