vxrn 2.0.0-beta.99.1 → 2.6.0

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 (210) hide show
  1. package/dist/backgroundComputation.mjs +145 -0
  2. package/dist/backgroundComputation.mjs.map +1 -0
  3. package/dist/backgroundComputation.native.js +163 -0
  4. package/dist/backgroundComputation.native.js.map +1 -0
  5. package/dist/backgroundComputationNative.mjs +16 -0
  6. package/dist/backgroundComputationNative.mjs.map +1 -0
  7. package/dist/backgroundComputationNative.native.js +18 -0
  8. package/dist/backgroundComputationNative.native.js.map +1 -0
  9. package/dist/config/getBaseViteConfigOnly.mjs +6 -10
  10. package/dist/config/getBaseViteConfigOnly.mjs.map +1 -1
  11. package/dist/config/getBaseViteConfigOnly.native.js +6 -10
  12. package/dist/config/getBaseViteConfigOnly.native.js.map +1 -1
  13. package/dist/config/getOptimizeDeps.mjs +2 -1
  14. package/dist/config/getOptimizeDeps.mjs.map +1 -1
  15. package/dist/config/getOptimizeDeps.native.js +2 -1
  16. package/dist/config/getOptimizeDeps.native.js.map +1 -1
  17. package/dist/config/getViteServerConfig.mjs +13 -0
  18. package/dist/config/getViteServerConfig.mjs.map +1 -1
  19. package/dist/config/getViteServerConfig.native.js +15 -1
  20. package/dist/config/getViteServerConfig.native.js.map +1 -1
  21. package/dist/constants/defaults.mjs +4 -0
  22. package/dist/constants/defaults.mjs.map +1 -1
  23. package/dist/constants/defaults.native.js +4 -0
  24. package/dist/constants/defaults.native.js.map +1 -1
  25. package/dist/exports/build.native.js +1 -1
  26. package/dist/exports/build.native.js.map +1 -1
  27. package/dist/exports/clean.native.js +1 -1
  28. package/dist/exports/clean.native.js.map +1 -1
  29. package/dist/exports/createServer.native.js +2 -2
  30. package/dist/exports/createServer.native.js.map +1 -1
  31. package/dist/exports/dev.mjs +3 -0
  32. package/dist/exports/dev.mjs.map +1 -1
  33. package/dist/exports/dev.native.js +6 -3
  34. package/dist/exports/dev.native.js.map +1 -1
  35. package/dist/exports/loadEnv.native.js +1 -1
  36. package/dist/exports/loadEnv.native.js.map +1 -1
  37. package/dist/exports/patch.native.js +1 -1
  38. package/dist/exports/patch.native.js.map +1 -1
  39. package/dist/exports/prebuild.mjs +0 -22
  40. package/dist/exports/prebuild.mjs.map +1 -1
  41. package/dist/exports/prebuild.native.js +1 -23
  42. package/dist/exports/prebuild.native.js.map +1 -1
  43. package/dist/exports/prebuildWithoutExpo.mjs +1116 -178
  44. package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
  45. package/dist/exports/prebuildWithoutExpo.native.js +1592 -243
  46. package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
  47. package/dist/exports/runAndroid.native.js +1 -1
  48. package/dist/exports/runAndroid.native.js.map +1 -1
  49. package/dist/exports/runIos.native.js +1 -1
  50. package/dist/exports/runIos.native.js.map +1 -1
  51. package/dist/exports/serve.native.js +1 -1
  52. package/dist/exports/serve.native.js.map +1 -1
  53. package/dist/exports/serveStaticAssets.native.js +1 -1
  54. package/dist/exports/serveStaticAssets.native.js.map +1 -1
  55. package/dist/index.js +4 -1
  56. package/dist/index.mjs +4 -1
  57. package/dist/index.native.js +4 -1
  58. package/dist/native-source-contract.mjs +3 -0
  59. package/dist/native-source-contract.native.js +3 -0
  60. package/dist/patches/builtInDepPatches.mjs +0 -13
  61. package/dist/patches/builtInDepPatches.mjs.map +1 -1
  62. package/dist/patches/builtInDepPatches.native.js +0 -13
  63. package/dist/patches/builtInDepPatches.native.js.map +1 -1
  64. package/dist/plugins/autoDepOptimizePlugin.mjs +3 -2
  65. package/dist/plugins/autoDepOptimizePlugin.mjs.map +1 -1
  66. package/dist/plugins/autoDepOptimizePlugin.native.js +6 -3
  67. package/dist/plugins/autoDepOptimizePlugin.native.js.map +1 -1
  68. package/dist/plugins/backgroundComputationPlugin.mjs +27 -0
  69. package/dist/plugins/backgroundComputationPlugin.mjs.map +1 -0
  70. package/dist/plugins/backgroundComputationPlugin.native.js +32 -0
  71. package/dist/plugins/backgroundComputationPlugin.native.js.map +1 -0
  72. package/dist/plugins/reactNativeCommonJsPlugin.native.js +3 -3
  73. package/dist/plugins/reactNativeCommonJsPlugin.native.js.map +1 -1
  74. package/dist/plugins/reactNativeDevAssetPlugin.mjs +2 -1
  75. package/dist/plugins/reactNativeDevAssetPlugin.mjs.map +1 -1
  76. package/dist/plugins/reactNativeDevAssetPlugin.native.js +3 -2
  77. package/dist/plugins/reactNativeDevAssetPlugin.native.js.map +1 -1
  78. package/dist/plugins/reactNativeDevServer.mjs +87 -24
  79. package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
  80. package/dist/plugins/reactNativeDevServer.native.js +162 -45
  81. package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
  82. package/dist/plugins/workletImportsPlugin.mjs +9 -30
  83. package/dist/plugins/workletImportsPlugin.mjs.map +1 -1
  84. package/dist/plugins/workletImportsPlugin.native.js +10 -35
  85. package/dist/plugins/workletImportsPlugin.native.js.map +1 -1
  86. package/dist/rn-commands/bundle/buildBundle.mjs +3 -3
  87. package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
  88. package/dist/rn-commands/bundle/buildBundle.native.js +3 -3
  89. package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
  90. package/dist/runtime/hmr-client.native.js +3 -7
  91. package/dist/runtime/hmr-client.native.js.map +1 -1
  92. package/dist/runtime/hmr-runtime.native.js +32 -40
  93. package/dist/runtime/hmr-runtime.native.js.map +1 -1
  94. package/dist/serve/node.native.js +2 -2
  95. package/dist/serve/node.native.js.map +1 -1
  96. package/dist/swift-package-id.mjs +3 -0
  97. package/dist/swift-package-id.native.js +3 -0
  98. package/dist/user-interface/index.native.js +6 -6
  99. package/dist/user-interface/index.native.js.map +1 -1
  100. package/dist/utils/compileNativeDevBytecode.mjs +93 -0
  101. package/dist/utils/compileNativeDevBytecode.mjs.map +1 -0
  102. package/dist/utils/compileNativeDevBytecode.native.js +98 -0
  103. package/dist/utils/compileNativeDevBytecode.native.js.map +1 -0
  104. package/dist/utils/createNativeDevEngine.mjs +227 -20
  105. package/dist/utils/createNativeDevEngine.mjs.map +1 -1
  106. package/dist/utils/createNativeDevEngine.native.js +249 -37
  107. package/dist/utils/createNativeDevEngine.native.js.map +1 -1
  108. package/dist/utils/execSync.native.js +1 -1
  109. package/dist/utils/execSync.native.js.map +1 -1
  110. package/dist/utils/getServerEntry.native.js +2 -2
  111. package/dist/utils/getServerEntry.native.js.map +1 -1
  112. package/dist/utils/nativeRun.mjs +32 -16
  113. package/dist/utils/nativeRun.mjs.map +1 -1
  114. package/dist/utils/nativeRun.native.js +43 -18
  115. package/dist/utils/nativeRun.native.js.map +1 -1
  116. package/dist/utils/nativeSourceContract.mjs +1823 -0
  117. package/dist/utils/nativeSourceContract.mjs.map +1 -0
  118. package/dist/utils/nativeSourceContract.native.js +2425 -0
  119. package/dist/utils/nativeSourceContract.native.js.map +1 -0
  120. package/dist/utils/patches.native.js +15 -24
  121. package/dist/utils/patches.native.js.map +1 -1
  122. package/dist/utils/printServerUrls.native.js +1 -1
  123. package/dist/utils/printServerUrls.native.js.map +1 -1
  124. package/dist/utils/scanDepsToOptimize.mjs +7 -1
  125. package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
  126. package/dist/utils/scanDepsToOptimize.native.js +27 -2
  127. package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
  128. package/dist/utils/swiftPackageId.mjs +31 -2
  129. package/dist/utils/swiftPackageId.mjs.map +1 -1
  130. package/dist/utils/swiftPackageId.native.js +50 -2
  131. package/dist/utils/swiftPackageId.native.js.map +1 -1
  132. package/dist/vxrn-vite-plugin.native.js +1 -1
  133. package/dist/vxrn-vite-plugin.native.js.map +1 -1
  134. package/expo-plugin.cjs +792 -2
  135. package/native-project-patches.cjs +201 -10
  136. package/package.json +34 -15
  137. package/src/backgroundComputation.ts +220 -0
  138. package/src/backgroundComputationNative.ts +23 -0
  139. package/src/config/getBaseViteConfigOnly.ts +8 -9
  140. package/src/config/getOptimizeDeps.ts +3 -1
  141. package/src/config/getViteServerConfig.ts +16 -0
  142. package/src/config/glbAssets.test.ts +228 -0
  143. package/src/constants/defaults.ts +6 -0
  144. package/src/exports/dev.ts +5 -1
  145. package/src/exports/expoPlugin.test.mjs +337 -15
  146. package/src/exports/prebuild.ts +0 -31
  147. package/src/exports/prebuildWithoutExpo.test.ts +1588 -48
  148. package/src/exports/prebuildWithoutExpo.ts +1573 -213
  149. package/src/index.ts +8 -0
  150. package/src/native-source-contract.ts +16 -0
  151. package/src/patches/builtInDepPatches.ts +0 -21
  152. package/src/plugins/autoDepOptimizePlugin.ts +7 -2
  153. package/src/plugins/backgroundComputationPlugin.test.ts +77 -0
  154. package/src/plugins/backgroundComputationPlugin.ts +29 -0
  155. package/src/plugins/reactNativeDevAssetPlugin.ts +5 -1
  156. package/src/plugins/reactNativeDevServer.test.ts +74 -0
  157. package/src/plugins/reactNativeDevServer.ts +145 -28
  158. package/src/plugins/rnCodegenPlugin.test.ts +30 -0
  159. package/src/plugins/workletImportsPlugin.ts +19 -37
  160. package/src/rn-commands/bundle/buildBundle.ts +5 -3
  161. package/src/swift-package-id.ts +1 -0
  162. package/src/utils/compileNativeDevBytecode.test.ts +168 -0
  163. package/src/utils/compileNativeDevBytecode.ts +117 -0
  164. package/src/utils/createNativeDevEngine.test.ts +643 -18
  165. package/src/utils/createNativeDevEngine.ts +278 -48
  166. package/src/utils/nativeRun.test.ts +125 -23
  167. package/src/utils/nativeRun.ts +51 -23
  168. package/src/utils/nativeSourceArtifacts.test.ts +39 -0
  169. package/src/utils/nativeSourceContract.test.ts +600 -0
  170. package/src/utils/nativeSourceContract.ts +1897 -0
  171. package/src/utils/scanDepsToOptimize.test.ts +80 -0
  172. package/src/utils/scanDepsToOptimize.ts +18 -7
  173. package/src/utils/swiftPackageId.ts +25 -1
  174. package/types/backgroundComputation.d.ts +28 -0
  175. package/types/backgroundComputation.d.ts.map +1 -0
  176. package/types/backgroundComputationNative.d.ts +2 -0
  177. package/types/backgroundComputationNative.d.ts.map +1 -0
  178. package/types/config/getBaseViteConfigOnly.d.ts.map +1 -1
  179. package/types/config/getOptimizeDeps.d.ts.map +1 -1
  180. package/types/config/getViteServerConfig.d.ts.map +1 -1
  181. package/types/constants/defaults.d.ts.map +1 -1
  182. package/types/exports/dev.d.ts.map +1 -1
  183. package/types/exports/prebuild.d.ts.map +1 -1
  184. package/types/exports/prebuildWithoutExpo.d.ts +6 -0
  185. package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
  186. package/types/index.d.ts +2 -0
  187. package/types/index.d.ts.map +1 -1
  188. package/types/native-source-contract.d.ts +2 -0
  189. package/types/native-source-contract.d.ts.map +1 -0
  190. package/types/patches/builtInDepPatches.d.ts.map +1 -1
  191. package/types/plugins/autoDepOptimizePlugin.d.ts.map +1 -1
  192. package/types/plugins/backgroundComputationPlugin.d.ts +3 -0
  193. package/types/plugins/backgroundComputationPlugin.d.ts.map +1 -0
  194. package/types/plugins/reactNativeDevAssetPlugin.d.ts.map +1 -1
  195. package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
  196. package/types/plugins/workletImportsPlugin.d.ts.map +1 -1
  197. package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
  198. package/types/swift-package-id.d.ts +2 -0
  199. package/types/swift-package-id.d.ts.map +1 -0
  200. package/types/utils/compileNativeDevBytecode.d.ts +3 -0
  201. package/types/utils/compileNativeDevBytecode.d.ts.map +1 -0
  202. package/types/utils/createNativeDevEngine.d.ts +7 -22
  203. package/types/utils/createNativeDevEngine.d.ts.map +1 -1
  204. package/types/utils/nativeRun.d.ts.map +1 -1
  205. package/types/utils/nativeSourceContract.d.ts +121 -0
  206. package/types/utils/nativeSourceContract.d.ts.map +1 -0
  207. package/types/utils/scanDepsToOptimize.d.ts +1 -0
  208. package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
  209. package/types/utils/swiftPackageId.d.ts +1 -0
  210. package/types/utils/swiftPackageId.d.ts.map +1 -1
@@ -5,8 +5,8 @@ const path = require('node:path')
5
5
  function hasNitroWebImage(root) {
6
6
  const projectRequire = createRequire(path.join(root, 'package.json'))
7
7
  try {
8
- const nativeRoot = path.dirname(projectRequire.resolve('@vxrn/native/package.json'))
9
- projectRequire.resolve('react-native-nitro-web-image/package.json', { paths: [nativeRoot] })
8
+ const oneRoot = path.dirname(projectRequire.resolve('one/package.json'))
9
+ projectRequire.resolve('react-native-nitro-web-image/package.json', { paths: [oneRoot] })
10
10
  return true
11
11
  } catch {
12
12
  return false
@@ -36,6 +36,30 @@ function injectNitroWebImageModularHeaderIntoPodfile(podfile) {
36
36
  */
37
37
  const FMT_CXX17_MARKER = '# [vxrn/one] fmt c++17 fix'
38
38
 
39
+ const WEBGPU_HEADERS_MARKER = '# [vxrn/one] webgpu isolated package headers'
40
+
41
+ function injectWebGPUHeaderPathsIntoPodfile(podfile) {
42
+ if (podfile.includes(WEBGPU_HEADERS_MARKER)) return podfile
43
+ const match = podfile.match(/post_install\s+do\s+\|installer\|/)
44
+ if (!match) throw new Error('[vxrn] Podfile lost its post_install anchor')
45
+ const patch = `
46
+ ${WEBGPU_HEADERS_MARKER}
47
+ installer.pods_project.targets.each do |target|
48
+ next unless target.name == 'react-native-webgpu'
49
+
50
+ target.build_configurations.each do |build_config|
51
+ paths = Array(build_config.build_settings['HEADER_SEARCH_PATHS'] || '$(inherited)')
52
+ paths |= %w[cpp/rnwgpu cpp/rnwgpu/api cpp/rnwgpu/api/descriptors cpp/jsi].map do |directory|
53
+ "$(PODS_TARGET_SRCROOT)/#{directory}"
54
+ end
55
+ build_config.build_settings['HEADER_SEARCH_PATHS'] = paths
56
+ end
57
+ end
58
+ `
59
+ const insertAt = match.index + match[0].length
60
+ return podfile.slice(0, insertAt) + '\n' + patch + podfile.slice(insertAt)
61
+ }
62
+
39
63
  function injectFmtCxx17FixIntoPodfile(podfile) {
40
64
  if (podfile.includes(FMT_CXX17_MARKER)) {
41
65
  return podfile
@@ -171,8 +195,14 @@ function replaceAppBuildGradleReactBlock(appBuildGradleContents) {
171
195
  return appBuildGradleContents
172
196
  }
173
197
 
198
+ // replace our resolver declarations together with the react block on re-prebuild.
199
+ const prefix = appBuildGradleContentLines
200
+ .slice(0, reactBlockStartIndex)
201
+ .join('\n')
202
+ .replaceAll(ANDROID_APP_BUILD_GRADLE_RESOLVERS, '')
203
+ .trimEnd()
174
204
  return [
175
- ...appBuildGradleContentLines.slice(0, reactBlockStartIndex),
205
+ prefix,
176
206
  ANDROID_APP_BUILD_GRADLE_REACT_BLOCK,
177
207
  ...appBuildGradleContentLines.slice(reactBlockEndIndex + 1),
178
208
  ].join('\n')
@@ -180,8 +210,7 @@ function replaceAppBuildGradleReactBlock(appBuildGradleContents) {
180
210
 
181
211
  // TODO: Get the content of this block from @react-native-community/template (for example, get https://registry.npmjs.org/@react-native-community/template/0.76.6, find the tarball, download it into a tmp dir, extract it, read template/android/app/build.gradle, parse out the react block) to ensure it stays up to date.
182
212
  // Note that we need to add patches marked with [vxrn/one], not just copy the block from the template as is.
183
- const ANDROID_APP_BUILD_GRADLE_REACT_BLOCK = `
184
- def resolveNodePackage = { packageName ->
213
+ const ANDROID_APP_BUILD_GRADLE_RESOLVERS = `def resolveNodePackage = { packageName ->
185
214
  providers.exec {
186
215
  workingDir(rootDir)
187
216
  commandLine("node", "--print", "require.resolve('" + packageName + "')")
@@ -193,7 +222,10 @@ def resolveReactNativeDependency = { packageName ->
193
222
  workingDir(rootDir)
194
223
  commandLine("node", "--print", "require('module').createRequire(require.resolve('react-native/package.json')).resolve('" + packageName + "')")
195
224
  }.standardOutput.asText.get().trim()
196
- }
225
+ }`
226
+
227
+ const ANDROID_APP_BUILD_GRADLE_REACT_BLOCK = `
228
+ ${ANDROID_APP_BUILD_GRADLE_RESOLVERS}
197
229
 
198
230
  react {
199
231
  // [vxrn/one] the bundle command should find the entry file automatically,
@@ -211,9 +243,11 @@ react {
211
243
  // the application has its own node_modules directory.
212
244
  reactNativeDir = file(resolveNodePackage("react-native/package.json")).parentFile
213
245
  codegenDir = file(resolveReactNativeDependency("@react-native/codegen/package.json")).parentFile
214
- // [vxrn/one] cli.js is not in react-native's exports map since 0.87, so
215
- // resolve the exported package.json and step to the sibling cli.js on disk
216
- cliFile = new File(file(resolveNodePackage("react-native/package.json")).parentFile, "cli.js")
246
+ // [vxrn/one] vxrn owns the cli even when the app has no hoisted cli package
247
+ cliFile = file(providers.exec {
248
+ workingDir(rootDir)
249
+ commandLine("node", "--print", "require('module').createRequire(require.resolve('vxrn/package.json')).resolve('@react-native-community/cli/build/bin.js')")
250
+ }.standardOutput.asText.get().trim())
217
251
  // [vxrn/one] resolve hermesc from the same react-native installation
218
252
  hermesCommand = new File(file(resolveReactNativeDependency("hermes-compiler/package.json")).parentFile, "hermesc/%OS-BIN%/hermesc").absolutePath
219
253
 
@@ -292,6 +326,55 @@ function insertBeforeBundlePhaseRunner(input, codeToAdd) {
292
326
  return input
293
327
  }
294
328
 
329
+ function insertAfterBundlePhaseRunner(input, codeToAdd) {
330
+ for (const anchor of BUNDLE_PHASE_RUNNER_ANCHORS) {
331
+ const match = anchor.exec(input)
332
+ if (!match) continue
333
+ const lineEnd = input.indexOf('\n', match.index + match[0].length)
334
+ const insertAt = lineEnd === -1 ? input.length : lineEnd + 1
335
+ return input.slice(0, insertAt) + codeToAdd + '\n' + input.slice(insertAt)
336
+ }
337
+
338
+ if (!warnedMissingBundlePhaseRunnerAnchor) {
339
+ warnedMissingBundlePhaseRunnerAnchor = true
340
+ console.warn(
341
+ '[vxrn] could not find the `"$NODE_BINARY" .../scripts/react-native-xcode.sh` line in the iOS bundle phase; the One.Updates embedded manifest was not applied. The React Native template may have changed shape.'
342
+ )
343
+ }
344
+ return input
345
+ }
346
+
347
+ /**
348
+ * Write the One.Updates embedded manifest beside the release bundle after
349
+ * React Native's bundling runs. The id and timestamp are generated at build
350
+ * time; the runtime version is baked in by prebuild.
351
+ */
352
+ const EMBEDDED_UPDATES_MANIFEST_MARKER =
353
+ '# [vxrn/one] the embedded update manifest lands beside the release bundle'
354
+
355
+ function addEmbeddedUpdatesManifestToBundleReactNativeShellScript(input, runtimeVersion) {
356
+ if (input.includes(EMBEDDED_UPDATES_MANIFEST_MARKER)) {
357
+ return input
358
+ }
359
+
360
+ const runtime = String(runtimeVersion).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
361
+ const codeToAdd = [
362
+ '',
363
+ EMBEDDED_UPDATES_MANIFEST_MARKER,
364
+ 'ONE_UPDATES_RESOURCES="$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH"',
365
+ 'if [ -f "$ONE_UPDATES_RESOURCES/main.jsbundle" ]; then',
366
+ ` "\${NODE_BINARY:-node}" -e 'const fs = require("fs"); const manifest = { id: require("crypto").randomUUID(), createdAt: new Date().toISOString(), runtimeVersion: "${runtime}" }; fs.writeFileSync(process.argv[1], JSON.stringify(manifest));' "$ONE_UPDATES_RESOURCES/one-updates-embedded.json"`,
367
+ // react-native-xcode.sh exits 0 when hermesc fails, so a release build
368
+ // would otherwise ship with no bundle and nothing for the launcher to run.
369
+ 'elif [[ "$CONFIGURATION" != *Debug* && -z "$SKIP_BUNDLING" ]]; then',
370
+ ' echo "error: [one] release build has no main.jsbundle: the bundle phase failed" >&2',
371
+ ' exit 1',
372
+ 'fi',
373
+ ].join('\n')
374
+
375
+ return insertAfterBundlePhaseRunner(input, codeToAdd)
376
+ }
377
+
295
378
  /**
296
379
  * React Native v0.76 defaults the CLI_PATH to an internal scripts/bundle.js for iOS (see: https://github.com/facebook/react-native/blob/v0.76.0/packages/react-native/scripts/react-native-xcode.sh#L93), which loads the bundle command directly from `@react-native/community-cli-plugin`, and will ignore the override of the bundle command in `react-native.config.cjs`.
297
380
  * We need to set it back to the main CLI endpoint so the override of the bundle command in `react-native.config.cjs` can take effect.
@@ -305,7 +388,7 @@ function addSetCliPathToBundleReactNativeShellScript(input) {
305
388
 
306
389
  const codeToAdd = `
307
390
  ${SET_CLI_PATH_MARKER}
308
- export CLI_PATH="$("\${NODE_BINARY:-node}" --print "require('path').dirname(require.resolve('react-native/package.json')) + '/cli.js'")"
391
+ export CLI_PATH="$("\${NODE_BINARY:-node}" --print "require('module').createRequire(require.resolve('vxrn/package.json')).resolve('@react-native-community/cli/build/bin.js')")"
309
392
  `.trim()
310
393
 
311
394
  return insertBeforeBundlePhaseRunner(input, codeToAdd)
@@ -572,13 +655,121 @@ function injectOneSwiftPackagesIntoPodfile(podfile) {
572
655
  return podfile.slice(0, insertAt) + '\n' + lines.join('\n') + podfile.slice(insertAt)
573
656
  }
574
657
 
658
+ // one notifications host entries, written by both one prebuild and
659
+ // vxrn/expo-plugin. the ios keys and android class names are read by one's
660
+ // native code, so they change together with it.
661
+ const ONE_NOTIFICATIONS = {
662
+ enabledInfoPlistKey: 'OneNativeNotificationsEnabled',
663
+ pushInfoPlistKey: 'OneNativeNotificationsPush',
664
+ apsEnvironment: 'development',
665
+ androidPermissions: [
666
+ 'android.permission.POST_NOTIFICATIONS',
667
+ 'android.permission.RECEIVE_BOOT_COMPLETED',
668
+ ],
669
+ receiver: 'dev.onejs.onenative.OneNativeNotificationsReceiver',
670
+ receiverAction: 'android.intent.action.BOOT_COMPLETED',
671
+ pushService: 'dev.onejs.onenative.OneNativePushService',
672
+ pushServiceAction: 'com.google.firebase.MESSAGING_EVENT',
673
+ pushGradleProperty: 'oneNativePush',
674
+ }
675
+
676
+ // One.Updates: the Info.plist keys the launcher reads, and the release
677
+ // bundleURL both prebuilds point at it. the app target reaches the launcher's
678
+ // c entry point through its bridging header: it cannot import One, whose c++
679
+ // umbrella does not rebuild under the app's flags.
680
+ const ONE_UPDATES = {
681
+ urlInfoPlistKey: 'OneUpdatesURL',
682
+ runtimeVersionInfoPlistKey: 'OneUpdatesRuntimeVersion',
683
+ bridgingHeaderImport: '#import "OneUpdatesLauncherBridge.h"',
684
+ }
685
+
686
+ const RELEASE_BUNDLE_URL =
687
+ /(#else\n\s*)(return )?Bundle\.main\.url\(forResource: "main", withExtension: "jsbundle"\)(\n#endif)/
688
+
689
+ function pointReleaseBundleURLAtOneUpdates(appDelegate) {
690
+ if (appDelegate.includes('OneUpdatesBundleURL()')) {
691
+ return appDelegate
692
+ }
693
+ if (!RELEASE_BUNDLE_URL.test(appDelegate)) {
694
+ throw new Error(
695
+ '[vxrn] AppDelegate.swift changed shape: cannot point the release bundleURL at One.Updates'
696
+ )
697
+ }
698
+ return appDelegate.replace(RELEASE_BUNDLE_URL, '$1$2OneUpdatesBundleURL()$3')
699
+ }
700
+
701
+ // the launch screen hold: the app's react native delegate keeps the launch
702
+ // storyboard over the root view until react native's first content, through
703
+ // the OneHoldLaunchScreen c entry point in the bridging header.
704
+ const ONE_LAUNCH_SCREEN = {
705
+ bridgingHeaderImport: '#import "OneLaunchScreen.h"',
706
+ }
707
+
708
+ const REACT_NATIVE_DELEGATE_CLASS =
709
+ /^class ReactNativeDelegate: (ExpoReactNativeFactoryDelegate|RCTDefaultReactNativeFactoryDelegate) \{\n/m
710
+
711
+ function holdLaunchScreenOverRootView(appDelegate) {
712
+ if (appDelegate.includes('OneHoldLaunchScreen(')) {
713
+ return appDelegate
714
+ }
715
+ const match = appDelegate.match(REACT_NATIVE_DELEGATE_CLASS)
716
+ if (!match) {
717
+ throw new Error(
718
+ '[vxrn] AppDelegate.swift changed shape: cannot hold the launch screen over the react native root'
719
+ )
720
+ }
721
+ // expo's delegate re-declares the hook over UIView; react native's takes
722
+ // its RCTRootView.
723
+ const rootViewType = match[1] === 'ExpoReactNativeFactoryDelegate' ? 'UIView' : 'RCTRootView'
724
+ return appDelegate.replace(
725
+ match[0],
726
+ `${match[0]} // [vxrn/one] the launch screen stays over the root until react native's first content
727
+ override func customize(_ rootView: ${rootViewType}) {
728
+ super.customize(rootView)
729
+ OneHoldLaunchScreen(rootView)
730
+ }
731
+
732
+ `
733
+ )
734
+ }
735
+
736
+ // the android half of the launch screen hold: MainActivity hands its content
737
+ // to OneLaunchScreen right after super.onCreate, which every prebuilt
738
+ // activity has once addReactNativeScreensFix ran.
739
+ const SUPER_ON_CREATE = /^([ \t]*)super\.onCreate\(null\)$/m
740
+
741
+ function holdLaunchScreenInMainActivity(mainActivity) {
742
+ if (mainActivity.includes('OneLaunchScreen.hold(this)')) {
743
+ return mainActivity
744
+ }
745
+ if (!SUPER_ON_CREATE.test(mainActivity)) {
746
+ throw new Error(
747
+ '[vxrn] MainActivity.kt changed shape: cannot hold the launch screen after super.onCreate'
748
+ )
749
+ }
750
+ return mainActivity
751
+ .replace(/package\s+[\w.]+/, '$&\nimport com.margelo.nitro.one.OneLaunchScreen')
752
+ .replace(
753
+ SUPER_ON_CREATE,
754
+ "$1super.onCreate(null)\n$1// [vxrn/one] the launch screen stays until react native's first content\n$1OneLaunchScreen.hold(this)"
755
+ )
756
+ }
757
+
575
758
  module.exports = {
759
+ injectWebGPUHeaderPathsIntoPodfile,
760
+ holdLaunchScreenInMainActivity,
761
+ ONE_NOTIFICATIONS,
762
+ ONE_UPDATES,
763
+ pointReleaseBundleURLAtOneUpdates,
764
+ ONE_LAUNCH_SCREEN,
765
+ holdLaunchScreenOverRootView,
576
766
  hasNitroWebImage,
577
767
  injectNitroWebImageModularHeaderIntoPodfile,
578
768
  injectOneSwiftPackagesIntoPodfile,
579
769
  addSetCliPathToBundleReactNativeShellScript,
580
770
  addPodHermescToBundleReactNativeShellScript,
581
771
  addDepsPatchToBundleReactNativeShellScript,
772
+ addEmbeddedUpdatesManifestToBundleReactNativeShellScript,
582
773
  injectFmtCxx17FixIntoPodfile,
583
774
  injectHermesMinificationPatchIntoPodfile,
584
775
  injectReactNativeScreensGammaIntoPodfile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vxrn",
3
- "version": "2.0.0-beta.99.1",
3
+ "version": "2.6.0",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -30,6 +30,22 @@
30
30
  "./vite-plugin": {
31
31
  "types": "./types/vxrn-vite-plugin.d.ts",
32
32
  "default": "./dist/vxrn-vite-plugin.mjs"
33
+ },
34
+ "./native-source-contract": {
35
+ "types": "./types/native-source-contract.d.ts",
36
+ "default": "./dist/native-source-contract.mjs"
37
+ },
38
+ "./swift-package-id": {
39
+ "types": "./types/swift-package-id.d.ts",
40
+ "default": "./dist/swift-package-id.mjs"
41
+ },
42
+ "./background-computation": {
43
+ "types": "./types/backgroundComputation.d.ts",
44
+ "default": "./dist/backgroundComputation.mjs"
45
+ },
46
+ "./background-computation-native": {
47
+ "types": "./types/backgroundComputationNative.d.ts",
48
+ "default": "./dist/backgroundComputationNative.mjs"
33
49
  }
34
50
  },
35
51
  "module": "dist",
@@ -62,18 +78,18 @@
62
78
  "@jridgewell/remapping": "^2.3.0",
63
79
  "@jridgewell/trace-mapping": "^0.3.25",
64
80
  "@react-native/codegen": "^0.87.1",
81
+ "@react-native-community/cli": "^20.2.0",
65
82
  "@react-native-community/cli-config": "^20.2.0",
66
83
  "@react-native/dev-middleware": "^0.87.1",
67
- "@vxrn/compiler": "2.0.0-beta.99.1",
68
- "@vxrn/debug": "2.0.0-beta.99.1",
69
- "@vxrn/query-string": "2.0.0-beta.99.1",
70
- "@vxrn/resolve": "2.0.0-beta.99.1",
71
- "@vxrn/safe-area": "2.0.0-beta.99.1",
72
- "@vxrn/url-parse": "2.0.0-beta.99.1",
73
- "@vxrn/utils": "2.0.0-beta.99.1",
74
- "@vxrn/vendor": "2.0.0-beta.99.1",
75
- "@vxrn/vite-flow": "2.0.0-beta.99.1",
76
- "@vxrn/vite-plugin-metro": "2.0.0-beta.99.1",
84
+ "@vxrn/compiler": "2.6.0",
85
+ "@vxrn/debug": "2.6.0",
86
+ "@vxrn/query-string": "2.6.0",
87
+ "@vxrn/resolve": "2.6.0",
88
+ "@vxrn/url-parse": "2.6.0",
89
+ "@vxrn/utils": "2.6.0",
90
+ "@vxrn/vendor": "2.6.0",
91
+ "@vxrn/vite-flow": "2.6.0",
92
+ "@vxrn/vite-plugin-metro": "2.6.0",
77
93
  "citty": "^0.1.6",
78
94
  "dotenv": "^17.2.1",
79
95
  "dotenv-expand": "^12.0.2",
@@ -95,26 +111,29 @@
95
111
  "pkg-types": "^1.0.3",
96
112
  "rolldown": "^1.2.8",
97
113
  "semver": "^7.6.3",
98
- "sharp": "^0.35.4",
114
+ "sharp": "^0.35.5",
99
115
  "vite": "^8.2.2",
100
- "ws": "^8.21.0"
116
+ "ws": "^8.21.0",
117
+ "sucrase": "3.35.1"
101
118
  },
102
119
  "devDependencies": {
103
120
  "@biomejs/biome": "2.3.3",
104
121
  "@jridgewell/gen-mapping": "^0.3.5",
105
- "@react-native-community/cli": "^20.2.0",
106
- "@tamagui/build": "3.0.0-beta.1432.1",
122
+ "@tamagui/build": "3.0.3",
107
123
  "@types/find-node-modules": "^2.1.2",
108
124
  "@types/node": "^24.10.0",
109
125
  "@types/ws": "^8.18.1",
110
126
  "depcheck": "^1.4.7",
127
+ "hermes-compiler": "250829098.0.17",
111
128
  "metro-source-map": "0.84.4",
112
129
  "react-native": "0.87.1",
130
+ "typescript": "7.0.2",
113
131
  "vitest": "^4.1.0"
114
132
  },
115
133
  "publishConfig": {
116
134
  "access": "public"
117
135
  },
136
+ "releaseSourceCommit": "9822993504bd9422425d1d6ee9bfbe96f84c909c",
118
137
  "repository": {
119
138
  "type": "git",
120
139
  "url": "git+https://github.com/onejs/one.git",
@@ -0,0 +1,220 @@
1
+ import MagicString from 'magic-string'
2
+ import { parse } from 'sucrase/dist/parser/index.js'
3
+ import { IdentifierRole } from 'sucrase/dist/parser/tokenizer/index.js'
4
+ import { TokenType } from 'sucrase/dist/parser/tokenizer/types.js'
5
+
6
+ export type BackgroundModule = {
7
+ id: string
8
+ source: string
9
+ calculate: string
10
+ name: string
11
+ platform: 'web' | 'native'
12
+ }
13
+
14
+ export type BackgroundTransformOptions = {
15
+ platform: 'web' | 'native'
16
+ resolve: (source: string, importer: string) => string
17
+ nativeModule?: (module: BackgroundModule) => string
18
+ workerFactory?: (module: BackgroundModule) => string
19
+ }
20
+
21
+ const marker = '.__one_background_worker_'
22
+ const hex = (name: string) =>
23
+ [...new TextEncoder().encode(name)]
24
+ .map((byte) => byte.toString(16).padStart(2, '0'))
25
+ .join('')
26
+
27
+ // file-shaped worker entries survive Vite's query stripping and package graphs.
28
+ export function loadBackgroundComputationModule(
29
+ id: string
30
+ ): BackgroundModule | undefined {
31
+ const match = id.match(/^(.*?)\.__one_background_worker_([a-f0-9]+)\.js(?:\?.*)?$/)
32
+ if (!match) return
33
+ const [, calculate, encoded] = match
34
+ const name = new TextDecoder().decode(
35
+ Uint8Array.from(encoded.match(/../g)!, (byte) => Number.parseInt(byte, 16))
36
+ )
37
+ return {
38
+ id,
39
+ calculate,
40
+ name,
41
+ platform: 'web',
42
+ source: `import { ${name} as calculate } from ${JSON.stringify(calculate)};
43
+ self.onmessage = ({ data: { revision, input } }) => {
44
+ try {
45
+ const value = calculate(input);
46
+ if (value instanceof Promise) throw new TypeError('background computations must be synchronous');
47
+ self.postMessage({ ok: true, result: { revision, value } });
48
+ } catch (error) {
49
+ self.postMessage({ ok: false, revision, error: String(error) });
50
+ }
51
+ };`,
52
+ }
53
+ }
54
+
55
+ // hosts supply path resolution and worker transport; selection and protocol stay here.
56
+ export function transformBackgroundComputations(
57
+ source: string,
58
+ id: string,
59
+ options: BackgroundTransformOptions
60
+ ) {
61
+ if (!source.includes('defineBackgroundComputation') || id.includes(marker)) return
62
+ const file = parse(
63
+ source,
64
+ !/\.[cm]?ts(?:\?|$)/.test(id),
65
+ /\.[cm]?tsx?(?:\?|$)/.test(id),
66
+ false
67
+ )
68
+ const { tokens } = file
69
+ const text = (index: number) =>
70
+ tokens[index] ? source.slice(tokens[index].start, tokens[index].end) : ''
71
+ const imports = new Map<string, { source: string; name: string }>()
72
+ const definitions = new Set<string>()
73
+ for (let index = 0; index < tokens.length; index++) {
74
+ if (text(index) !== 'import' || tokens[index].isType || text(index + 1) !== '{')
75
+ continue
76
+ const start = index + 2
77
+ let end = start
78
+ while (end < tokens.length && text(end) !== '}') end++
79
+ if (text(end + 1) !== 'from' || tokens[end + 2]?.type !== TokenType.string) continue
80
+ const specifier = text(end + 2).slice(1, -1)
81
+ for (let binding = start; binding < end; binding++) {
82
+ if (tokens[binding].isType || tokens[binding].type !== TokenType.name) continue
83
+ const name = text(binding)
84
+ const local = text(binding + 1) === 'as' ? text(binding + 2) : name
85
+ imports.set(local, { source: specifier, name })
86
+ if (specifier === 'one/background' && name === 'defineBackgroundComputation')
87
+ definitions.add(local)
88
+ if (local !== name) binding += 2
89
+ }
90
+ index = end + 2
91
+ }
92
+ if (!definitions.size) return
93
+ const code = new MagicString(source)
94
+ const modules: BackgroundModule[] = []
95
+ for (let index = 0; index < tokens.length; index++) {
96
+ const token = tokens[index]
97
+ if (token.identifierRole !== IdentifierRole.Access || !definitions.has(text(index)))
98
+ continue
99
+ let opening = index + 1
100
+ while (tokens[opening]?.isType) opening++
101
+ if (text(opening) !== '(') continue
102
+ let binding = index - 2
103
+ while (tokens[binding]?.isType) binding--
104
+ if (
105
+ token.scopeDepth !== 0 ||
106
+ text(index - 1) !== '=' ||
107
+ tokens[binding]?.identifierRole !== IdentifierRole.TopLevelDeclaration
108
+ )
109
+ throw new Error(
110
+ `[one background] ${id}: definitions must be module-scope variables`
111
+ )
112
+ const argument = tokens[opening + 1]
113
+ const calculate =
114
+ argument?.type === TokenType.name ? imports.get(text(opening + 1)) : undefined
115
+ if (!calculate || !calculate.source.startsWith('.') || text(opening + 2) !== ')')
116
+ throw new Error(
117
+ `[one background] ${id}: defineBackgroundComputation requires one named import from a relative pure module at module scope`
118
+ )
119
+ const resolved = options.resolve(calculate.source, id)
120
+ if (options.platform === 'native') {
121
+ const local = `__oneBackgroundCalculate${modules.length}`
122
+ const module: BackgroundModule = {
123
+ id: `${resolved}.__one_background_native_${hex(calculate.name)}.js`,
124
+ source: `export { ${calculate.name} } from ${JSON.stringify(resolved)};`,
125
+ calculate: resolved,
126
+ name: calculate.name,
127
+ platform: 'native',
128
+ }
129
+ const selected = options.nativeModule
130
+ ? options.nativeModule(module)
131
+ : `${calculate.source}?one-background=${encodeURIComponent(calculate.name)}`
132
+ code.prepend(
133
+ `import { ${calculate.name} as ${local} } from ${JSON.stringify(selected)};\n`
134
+ )
135
+ code.overwrite(argument.start, argument.end, local)
136
+ modules.push(module)
137
+ } else {
138
+ const module = loadBackgroundComputationModule(
139
+ `${resolved}${marker}${hex(calculate.name)}.js`
140
+ )!
141
+ const factory = options.workerFactory
142
+ ? options.workerFactory(module)
143
+ : `() => new Worker(new URL(${JSON.stringify(module.id)}, import.meta.url), { type: 'module' })`
144
+ code.appendLeft(tokens[opening + 2].start, `, ${factory}`)
145
+ modules.push(module)
146
+ }
147
+ }
148
+ if (!modules.length) return
149
+ return { code: code.toString(), map: code.generateMap({ hires: true }), modules }
150
+ }
151
+
152
+ // selected graphs expose __exportN; both native hosts use this runtime cache wrapper.
153
+ export function createBackgroundWorkletModule(
154
+ bundle: string,
155
+ names: readonly string[],
156
+ key: string
157
+ ) {
158
+ const loader = `__oneLoadWorkletModule_${key}`
159
+ return `function ${loader}() {
160
+ 'worklet';
161
+ const cache = globalThis.__oneWorkletImportCache || (globalThis.__oneWorkletImportCache = new WeakMap());
162
+ let namespace = cache.get(${loader});
163
+ if (namespace === undefined) {
164
+ ${bundle}
165
+ namespace = __oneWorkletBundle;
166
+ cache.set(${loader}, namespace);
167
+ }
168
+ return namespace;
169
+ }\n${names
170
+ .map(
171
+ (name, index) => `function __oneExport${index}(...args) {
172
+ 'worklet';
173
+ return (0, ${loader}().__export${index})(...args);
174
+ }
175
+ export { __oneExport${index} as ${name} };`
176
+ )
177
+ .join('\n')}`
178
+ }
179
+
180
+ export function assertBackgroundDependency(source: string) {
181
+ const name = source.replaceAll('\\', '/')
182
+ if (
183
+ name.startsWith('node:') ||
184
+ /(?:^|\/node_modules\/)(?:react|react-native|react-native-worklets|react-native-reanimated|@react-native)(?:\/|$)/.test(
185
+ name
186
+ )
187
+ )
188
+ throw new Error(
189
+ `[one background] runtime dependency ${source} is not pure JavaScript`
190
+ )
191
+ }
192
+
193
+ export type BackgroundGraphModule = {
194
+ id: number
195
+ code: string
196
+ dependencies: readonly (number | null)[]
197
+ }
198
+
199
+ // graph hosts supply compiled CommonJS factories; runtime loading is isolated from the app.
200
+ export function bundleBackgroundGraph(
201
+ modules: readonly BackgroundGraphModule[],
202
+ entry: number,
203
+ names: readonly string[]
204
+ ) {
205
+ return `var __oneWorkletBundle = (function () {
206
+ const factories = { ${modules.map((module) => `${module.id}: function(global, _require, _importDefault, _importAll, module, exports, _dependencyMap) {\n${module.code}\n}`).join(',\n')} };
207
+ const dependencies = ${JSON.stringify(Object.fromEntries(modules.map((module) => [module.id, module.dependencies])))};
208
+ const cache = Object.create(null);
209
+ function require(id) {
210
+ if (cache[id]) return cache[id].exports;
211
+ const module = cache[id] = { exports: {} };
212
+ factories[id](globalThis, require, importDefault, importAll, module, module.exports, dependencies[id]);
213
+ return module.exports;
214
+ }
215
+ function importDefault(id) { const value = require(id); return value && value.__esModule ? value.default : value; }
216
+ function importAll(id) { const value = require(id); return value && value.__esModule ? value : Object.assign({ default: value }, value); }
217
+ const namespace = require(${entry});
218
+ return { ${names.map((name, index) => `__export${index}: namespace[${JSON.stringify(name)}]`).join(', ')} };
219
+ })();`
220
+ }
@@ -0,0 +1,23 @@
1
+ import {
2
+ getClosureVariables,
3
+ JS_GLOBALS,
4
+ transformHermesLoops,
5
+ } from '@vxrn/compiler/worklet-utils'
6
+ import { parseSync } from 'oxc-parser'
7
+
8
+ // native compiler hosts validate the complete loader before worklet serialization.
9
+ export function prepareBackgroundWorkletModule(source: string, id: string) {
10
+ const code = transformHermesLoops(source, id)?.code ?? source
11
+ const parsed = parseSync(id, code, { lang: 'js' })
12
+ if (parsed.errors.length) throw new Error(parsed.errors[0].message)
13
+ const captures = getClosureVariables(
14
+ parsed.program.body[0],
15
+ new Set([...JS_GLOBALS, 'arguments'])
16
+ )
17
+ if (captures.length) {
18
+ throw new Error(
19
+ `[worklet imports] ${id} requires unsupported runtime globals: ${captures.join(', ')}`
20
+ )
21
+ }
22
+ return code
23
+ }
@@ -8,7 +8,6 @@ import type { VXRNOptionsFilled } from './getOptionsFilled'
8
8
 
9
9
  export const dedupe = [
10
10
  'one',
11
- '@vxrn/safe-area',
12
11
  'react',
13
12
  'react-dom',
14
13
  'react-dom/client',
@@ -21,11 +20,11 @@ export const dedupe = [
21
20
  '@react-navigation/bottom-tabs',
22
21
  '@tamagui/core',
23
22
  '@tamagui/web',
23
+ '@tamagui/adapt',
24
24
  '@tamagui/react-native-web',
25
25
  '@tamagui/react-native-web-lite',
26
26
  'tamagui',
27
27
  'react-native-reanimated',
28
- 'escape-string-regexp',
29
28
  ]
30
29
 
31
30
  /**
@@ -65,6 +64,7 @@ export async function getBaseViteConfig(
65
64
 
66
65
  return {
67
66
  mode,
67
+ assetsInclude: ['**/*.glb'],
68
68
 
69
69
  // we load the config ourselves
70
70
  // if you disable this is disables auto-reloading config changes
@@ -103,19 +103,18 @@ export async function getBaseViteConfig(
103
103
  // react native 0.87 removed @react-native/assets-registry, but libraries
104
104
  // like react-native-svg still import its registry
105
105
  find: /^(react-native\/asset-registry|@react-native\/assets-registry\/registry)$/,
106
- replacement: resolvePath('react-native-web/dist/modules/AssetRegistry', root),
106
+ replacement: 'react-native-web/dist/modules/AssetRegistry',
107
107
  },
108
108
  {
109
109
  find: 'react-native/package.json',
110
- replacement: resolvePath('react-native-web/package.json', root),
110
+ replacement: 'react-native-web/package.json',
111
111
  },
112
+ // named by package so it resolves (from the root, through dedupe) only
113
+ // once something imports react-native: an app with no react-native
114
+ // imports needs no react-native-web.
112
115
  {
113
116
  find: 'react-native',
114
- replacement: resolvePath('react-native-web', root),
115
- },
116
- {
117
- find: 'react-native-safe-area-context',
118
- replacement: resolvePath('@vxrn/safe-area', root),
117
+ replacement: 'react-native-web',
119
118
  },
120
119
  // bundle size optimizations
121
120
  {