peachsim 0.1.628 → 0.1.630

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 (111) hide show
  1. package/README.md +8 -4
  2. package/cli/bridge-flow-runner.ts +10 -3
  3. package/cli/cli-update.ts +2 -7
  4. package/cli/cloud-test-tunnel.ts +16 -3
  5. package/cli/commands/config.ts +1 -1
  6. package/cli/commands/control.ts +28 -3
  7. package/cli/commands/daemon-mac-app.ts +4 -2
  8. package/cli/commands/daemon.ts +4 -4
  9. package/cli/commands/device.ts +2 -3
  10. package/cli/commands/inspect/actions.ts +125 -90
  11. package/cli/commands/inspect/core.ts +5 -0
  12. package/cli/commands/inspect.ts +27 -13
  13. package/cli/commands/platform.ts +1 -1
  14. package/cli/commands/screenshot-layers.ts +1 -1
  15. package/cli/commands/screenshot.ts +1 -1
  16. package/cli/commands/skills.ts +0 -31
  17. package/cli/drivers/playwright-provisioning.ts +3 -2
  18. package/cli/drivers/playwright-sim-host.ts +25 -9
  19. package/cli/main.ts +8 -2
  20. package/cli/outbound-endpoints.ts +0 -4
  21. package/detox/index.ts +74 -43
  22. package/dist-lib/agent-daemon-client.cjs +1 -1
  23. package/dist-lib/agent-events.cjs +1 -1
  24. package/dist-lib/agent-identity.cjs +1 -1
  25. package/dist-lib/agent-sessions.cjs +1 -1
  26. package/dist-lib/attached-projects.cjs +1 -1
  27. package/dist-lib/auth/shared-session.cjs +1 -1
  28. package/dist-lib/backend-origin.cjs +1 -1
  29. package/dist-lib/beta.cjs +1 -1
  30. package/dist-lib/beta.mjs +1 -1
  31. package/dist-lib/bridge-constants.cjs +1 -1
  32. package/dist-lib/bridge-contract-input.cjs +1 -1
  33. package/dist-lib/bridge-contract-input.mjs +1 -1
  34. package/dist-lib/bridge-contract.cjs +1 -1
  35. package/dist-lib/bridge-contract.mjs +1 -1
  36. package/dist-lib/capture-contract.cjs +1 -1
  37. package/dist-lib/capture-contract.mjs +1 -1
  38. package/dist-lib/cli-constants.cjs +1 -1
  39. package/dist-lib/cloud-contract.cjs +1 -1
  40. package/dist-lib/cloud-contract.mjs +1 -1
  41. package/dist-lib/cloud-test-args.cjs +1 -1
  42. package/dist-lib/cloud-test-args.mjs +1 -1
  43. package/dist-lib/cloud.cjs +1 -1
  44. package/dist-lib/cloud.mjs +1 -1
  45. package/dist-lib/config.cjs +1 -1
  46. package/dist-lib/detox/index.cjs +129 -27
  47. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  48. package/dist-lib/home-paths.cjs +1 -1
  49. package/dist-lib/host/bridge-host.cjs +290 -315
  50. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  51. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  52. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  53. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  54. package/dist-lib/host/websocket-proxy.cjs +1 -1
  55. package/dist-lib/index.cjs +253 -121
  56. package/dist-lib/jump-to-source-babel.cjs +1 -1
  57. package/dist-lib/jump-to-source-native.cjs +1 -1
  58. package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
  59. package/dist-lib/menu.cjs +1 -1
  60. package/dist-lib/menu.mjs +1 -1
  61. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  62. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  63. package/dist-lib/metro-production-bundle.cjs +1 -1
  64. package/dist-lib/metro-production-bundle.mjs +1 -1
  65. package/dist-lib/metro.cjs +132 -9
  66. package/dist-lib/native-app-identity.cjs +278 -0
  67. package/dist-lib/native-app-identity.mjs +245 -0
  68. package/dist-lib/profiles.cjs +1 -1
  69. package/dist-lib/public-brand.cjs +1 -1
  70. package/dist-lib/react-native-host-modules.cjs +1 -1
  71. package/dist-lib/react-native-host-modules.mjs +1 -1
  72. package/dist-lib/render-mode.cjs +1 -1
  73. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  74. package/dist-lib/sdk.cjs +110 -87
  75. package/dist-lib/sdk.mjs +110 -87
  76. package/dist-lib/skills.cjs +841 -643
  77. package/dist-lib/swift-compile.cjs +1 -1
  78. package/dist-lib/swift-compile.mjs +1 -1
  79. package/dist-lib/swift-package.cjs +1 -1
  80. package/dist-lib/swift-package.mjs +1 -1
  81. package/dist-lib/swift-submit.cjs +1 -1
  82. package/dist-lib/swift-submit.mjs +1 -1
  83. package/dist-lib/swift.cjs +282 -177
  84. package/dist-lib/vite-swift.cjs +1 -1
  85. package/dist-lib/vite.cjs +11 -28
  86. package/kotlin/README.md +32 -4
  87. package/kotlin/fixtures/counter/Counter.kt +26 -0
  88. package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
  89. package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
  90. package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
  91. package/kotlin/fork/LICENSE +178 -0
  92. package/kotlin/fork/NOTICE +25 -0
  93. package/kotlin/fork/README.md +59 -0
  94. package/kotlin/fork/build.sh +128 -0
  95. package/kotlin/fork/compose-worker-globals.patch +96 -0
  96. package/kotlin/fork/fork.json +33 -0
  97. package/kotlin/fork/publish.ts +77 -0
  98. package/kotlin/fork/skiko-worker-clock.patch +33 -0
  99. package/kotlin/toolchain.json +288 -0
  100. package/package.json +12 -5
  101. package/src/automatic-update-policy.ts +17 -0
  102. package/src/host/bridge-host.ts +3 -1
  103. package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
  104. package/src/metro-plugin.ts +18 -0
  105. package/src/native-app-identity.ts +376 -0
  106. package/src/native-firebase-config.ts +90 -0
  107. package/src/screenshots/frame-compose.ts +5 -2
  108. package/src/screenshots/registry.ts +1 -1
  109. package/src/screenshots/schema.ts +2 -2
  110. package/src/vite-plugin-one.ts +11 -28
  111. package/src/vite-plugin.ts +6 -1
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -29,15 +29,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  ));
30
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
31
 
32
- // src/vite-plugin-kotlin.ts
33
- var vite_plugin_kotlin_exports = {};
34
- __export(vite_plugin_kotlin_exports, {
32
+ // src/kotlin-host.ts
33
+ var kotlin_host_exports = {};
34
+ __export(kotlin_host_exports, {
35
35
  KOTLIN_ARTIFACT_PREFIX: () => KOTLIN_ARTIFACT_PREFIX,
36
+ KOTLIN_PACKAGE_PATH: () => KOTLIN_PACKAGE_PATH,
36
37
  kotlinArtifact: () => kotlinArtifact,
37
38
  kotlinSources: () => kotlinSources,
38
- serveKotlinArtifact: () => serveKotlinArtifact
39
+ peachKotlinModuleRoot: () => peachKotlinModuleRoot,
40
+ serveKotlinArtifact: () => serveKotlinArtifact,
41
+ serveKotlinRequest: () => serveKotlinRequest
39
42
  });
40
- module.exports = __toCommonJS(vite_plugin_kotlin_exports);
43
+ module.exports = __toCommonJS(kotlin_host_exports);
41
44
  var import_node_child_process = require("node:child_process");
42
45
  var import_node_crypto = require("node:crypto");
43
46
  var import_node_fs = __toESM(require("node:fs"), 1);
@@ -61,7 +64,7 @@ function isRecord(value) {
61
64
  return typeof value === "object" && value !== null && !Array.isArray(value);
62
65
  }
63
66
 
64
- // src/vite-plugin-kotlin.ts
67
+ // src/kotlin-host.ts
65
68
  var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
66
69
  var KOTLIN_ARTIFACT_PREFIX = "/__peach/kotlin-artifact/";
67
70
  function readToolchain(moduleRoot) {
@@ -75,17 +78,34 @@ function readToolchain(moduleRoot) {
75
78
  );
76
79
  return { url: value.url, sha256: value.sha256 };
77
80
  };
78
- if (!isRecord(parsed) || !isRecord(parsed.compiler) || !Array.isArray(parsed.libraries))
81
+ if (!isRecord(parsed) || !isRecord(parsed.compiler) || !Array.isArray(parsed.libraries) || !Array.isArray(parsed.composeLibraries) || !Array.isArray(parsed.composeJsLibraries) || !isRecord(parsed.composeRuntime) || typeof parsed.composeRuntime.name !== "string")
79
82
  throw new Error("peachsim kotlin/toolchain.json has no compiler and libraries");
80
83
  const version = parsed.compiler.version;
81
84
  if (typeof version !== "string")
82
85
  throw new Error("peachsim kotlin/toolchain.json has no compiler version");
86
+ const libraries = (values) => values.map((library) => {
87
+ if (!isRecord(library) || typeof library.name !== "string")
88
+ throw new Error("peachsim kotlin/toolchain.json names a library without a name");
89
+ return { ...download(library), name: library.name };
90
+ });
83
91
  return {
84
92
  compiler: { ...download(parsed.compiler), version },
85
- libraries: parsed.libraries.map((library) => {
86
- if (!isRecord(library) || typeof library.name !== "string")
87
- throw new Error("peachsim kotlin/toolchain.json names a library without a name");
88
- return { ...download(library), name: library.name };
93
+ libraries: libraries(parsed.libraries),
94
+ composeLibraries: libraries(parsed.composeLibraries),
95
+ composeRuntime: {
96
+ ...download(parsed.composeRuntime),
97
+ name: parsed.composeRuntime.name
98
+ },
99
+ composeJsLibraries: parsed.composeJsLibraries.map((library) => {
100
+ if (!isRecord(library) || typeof library.name !== "string" || typeof library.module !== "string" || typeof library.file !== "string" || typeof library.archiveEntry !== "string")
101
+ throw new Error("peachsim kotlin/toolchain.json has an incomplete JS library");
102
+ return {
103
+ ...download(library),
104
+ name: library.name,
105
+ module: library.module,
106
+ file: library.file,
107
+ archiveEntry: library.archiveEntry
108
+ };
89
109
  })
90
110
  };
91
111
  }
@@ -207,7 +227,7 @@ function entrySource(ids) {
207
227
  " } else {",
208
228
  ' reply.put("ok", true).put("value", dispatch.call(module, method, argsJson))',
209
229
  " }",
210
- " } catch (error: Exception) {",
230
+ " } catch (error: Throwable) {",
211
231
  ' reply.put("ok", false).put("code", "E_NATIVE_SOURCE").put("error", "$module.$method: ${error.message}")',
212
232
  " }",
213
233
  " reply.toString().toJsString()",
@@ -215,7 +235,7 @@ function entrySource(ids) {
215
235
  ""
216
236
  ].join("\n");
217
237
  }
218
- var BUILD_FORMAT = 1;
238
+ var BUILD_FORMAT = 4;
219
239
  var builds = /* @__PURE__ */ new Map();
220
240
  function buildsDir() {
221
241
  return import_node_path2.default.join(kotlinHome(), "builds");
@@ -228,8 +248,11 @@ async function kotlinArtifact(root, moduleRoot, origin) {
228
248
  if (sources.length === 0) throw new Error(`${root} holds no Kotlin sources`);
229
249
  const generated = {};
230
250
  const ids = [];
251
+ let usesCompose = false;
231
252
  for (const file of sources) {
232
- const contract = nativeSourceContract(file, import_node_fs.default.readFileSync(file, "utf8"));
253
+ const source = import_node_fs.default.readFileSync(file, "utf8");
254
+ if (/\bandroidx\.compose\./.test(source)) usesCompose = true;
255
+ const contract = nativeSourceContract(file, source);
233
256
  if (contract.modules.length === 0) continue;
234
257
  const id = kotlinSourceId(root, file);
235
258
  ids.push(id);
@@ -244,25 +267,52 @@ async function kotlinArtifact(root, moduleRoot, origin) {
244
267
  for (const [name, text] of Object.entries(generated))
245
268
  digest.update(`${name}\0${text}\0`);
246
269
  const hash = digest.digest("hex").slice(0, 24);
247
- const artifact = { url: `${origin}${KOTLIN_ARTIFACT_PREFIX}${hash}/app.mjs`, hash };
270
+ const artifact = {
271
+ url: `${origin}${KOTLIN_ARTIFACT_PREFIX}${hash}/app.mjs`,
272
+ hash
273
+ };
248
274
  const out = import_node_path2.default.join(buildsDir(), hash);
249
275
  if (import_node_fs.default.existsSync(import_node_path2.default.join(out, "js", "app.wasm"))) return artifact;
250
276
  const pending = builds.get(hash);
251
277
  if (pending) return pending;
252
278
  const build = (async () => {
253
- const { kotlinc, libraries } = await ensureToolchain(toolchain);
279
+ const ready = await ensureToolchain(toolchain);
280
+ const { kotlinc } = ready;
281
+ const libraries = [...ready.libraries];
282
+ const composeRuntime = import_node_path2.default.join(
283
+ kotlinHome(),
284
+ toolchain.compiler.version,
285
+ toolchain.composeRuntime.name
286
+ );
287
+ if (usesCompose) {
288
+ for (const library of toolchain.composeLibraries) {
289
+ const target = import_node_path2.default.join(kotlinHome(), toolchain.compiler.version, library.name);
290
+ await fetchVerified(library, target);
291
+ libraries.push(target);
292
+ }
293
+ await fetchVerified(toolchain.composeRuntime, composeRuntime);
294
+ }
254
295
  import_node_fs.default.mkdirSync(buildsDir(), { recursive: true });
255
296
  const work = import_node_fs.default.mkdtempSync(import_node_path2.default.join(buildsDir(), `${hash}-`));
256
297
  const generatedDir = import_node_path2.default.join(work, "generated");
257
298
  import_node_fs.default.mkdirSync(generatedDir);
258
299
  for (const [name, text] of Object.entries(generated))
259
300
  import_node_fs.default.writeFileSync(import_node_path2.default.join(generatedDir, name), text);
260
- const common = ["-Xwasm-target=js", "-libraries", libraries.join(import_node_path2.default.delimiter)];
301
+ const common = [
302
+ // the full upstream Compose graph exceeds kotlinc's 512 mib default heap.
303
+ "-J-Xmx2g",
304
+ "-Xwasm-target=js",
305
+ "-libraries",
306
+ libraries.join(import_node_path2.default.delimiter)
307
+ ];
261
308
  try {
262
309
  await run(
263
310
  kotlinc,
264
311
  [
265
312
  ...common,
313
+ ...usesCompose ? [
314
+ `-Xplugin=${import_node_path2.default.resolve(import_node_path2.default.dirname(kotlinc), "../lib/compose-compiler-plugin.jar")}`
315
+ ] : [],
266
316
  "-language-version",
267
317
  language,
268
318
  "-api-version",
@@ -293,6 +343,43 @@ async function kotlinArtifact(root, moduleRoot, origin) {
293
343
  ],
294
344
  { maxBuffer: 16 * 1024 * 1024 }
295
345
  );
346
+ if (usesCompose)
347
+ await run("unzip", [
348
+ "-q",
349
+ "-j",
350
+ composeRuntime,
351
+ "skiko.mjs",
352
+ "skiko.wasm",
353
+ "-d",
354
+ import_node_path2.default.join(work, "js")
355
+ ]);
356
+ if (usesCompose) {
357
+ for (const library of toolchain.composeJsLibraries) {
358
+ for (const file of import_node_fs.default.readdirSync(import_node_path2.default.join(work, "js"))) {
359
+ if (!file.endsWith(".mjs")) continue;
360
+ const target = import_node_path2.default.join(work, "js", file);
361
+ const source = import_node_fs.default.readFileSync(target, "utf8");
362
+ let next = source;
363
+ for (const quote of ["'", '"'])
364
+ next = next.replaceAll(
365
+ `from ${quote}${library.module}${quote}`,
366
+ `from ${quote}./${library.file}${quote}`
367
+ );
368
+ if (next === source) continue;
369
+ const archive = import_node_path2.default.join(
370
+ kotlinHome(),
371
+ toolchain.compiler.version,
372
+ library.name
373
+ );
374
+ await fetchVerified(library, archive);
375
+ const { stdout } = await run("tar", ["-xOf", archive, library.archiveEntry], {
376
+ maxBuffer: 16 * 1024 * 1024
377
+ });
378
+ import_node_fs.default.writeFileSync(import_node_path2.default.join(work, "js", library.file), stdout);
379
+ import_node_fs.default.writeFileSync(target, next);
380
+ }
381
+ }
382
+ }
296
383
  } catch (error) {
297
384
  import_node_fs.default.rmSync(work, { recursive: true, force: true });
298
385
  const output = isRecord(error) ? `${String(error.stderr ?? "")}${String(error.stdout ?? "")}` : "";
@@ -347,10 +434,34 @@ function serveKotlinArtifact(pathname, res) {
347
434
  res.end(import_node_fs.default.readFileSync(target));
348
435
  return true;
349
436
  }
437
+ var KOTLIN_PACKAGE_PATH = "/__peach/kotlin-package";
438
+ function peachKotlinModuleRoot(root) {
439
+ const peachsimPackage = (0, import_node_module.createRequire)(import_node_path2.default.join(root, "package.json")).resolve(
440
+ "peachsim/package.json"
441
+ );
442
+ return import_node_path2.default.join(import_node_path2.default.dirname(peachsimPackage), "kotlin");
443
+ }
444
+ async function serveKotlinRequest(pathname, res, app) {
445
+ if (serveKotlinArtifact(pathname, res)) return true;
446
+ if (pathname !== KOTLIN_PACKAGE_PATH) return false;
447
+ res.setHeader("access-control-allow-origin", "*");
448
+ try {
449
+ const artifact = await kotlinArtifact(app.root, app.moduleRoot, app.origin);
450
+ res.setHeader("content-type", "application/json");
451
+ res.end(JSON.stringify({ ...artifact, hmrPath: app.hmrPath }));
452
+ } catch (error) {
453
+ res.statusCode = 500;
454
+ res.end(error instanceof Error ? error.message : String(error));
455
+ }
456
+ return true;
457
+ }
350
458
  // Annotate the CommonJS export names for ESM import in node:
351
459
  0 && (module.exports = {
352
460
  KOTLIN_ARTIFACT_PREFIX,
461
+ KOTLIN_PACKAGE_PATH,
353
462
  kotlinArtifact,
354
463
  kotlinSources,
355
- serveKotlinArtifact
464
+ peachKotlinModuleRoot,
465
+ serveKotlinArtifact,
466
+ serveKotlinRequest
356
467
  });
package/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "Peach";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/is-record.ts
4
4
  function isRecord(value) {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -528,6 +528,113 @@ function appendRNXMetroModuleIdentityFooter(bundleText, identity) {
528
528
  ${RNXSIM_METRO_SOURCE_MAP_COMMENT}${detached.sourceMappingUrl}`;
529
529
  }
530
530
 
531
+ // src/native-firebase-config.ts
532
+ var import_node_fs2 = __toESM(require("node:fs"), 1);
533
+ var import_node_module = require("node:module");
534
+ var import_node_path2 = __toESM(require("node:path"), 1);
535
+
536
+ // src/is-record.ts
537
+ function isRecord(value) {
538
+ return typeof value === "object" && value !== null && !Array.isArray(value);
539
+ }
540
+
541
+ // src/plist.ts
542
+ var import_plist = __toESM(require("@expo/plist"), 1);
543
+ function resolvePlistParser(value) {
544
+ if (!isRecord(value)) return null;
545
+ const direct = value.parse;
546
+ if (typeof direct === "function") {
547
+ return (source) => Reflect.apply(direct, value, [source]);
548
+ }
549
+ const nested = value.default;
550
+ if (!isRecord(nested)) return null;
551
+ const nestedParse = nested.parse;
552
+ return typeof nestedParse === "function" ? (source) => Reflect.apply(nestedParse, nested, [source]) : null;
553
+ }
554
+ var parsePlist = resolvePlistParser(import_plist.default);
555
+ function parsePlistSource(source) {
556
+ return parsePlist?.(source) ?? null;
557
+ }
558
+
559
+ // src/native-firebase-config.ts
560
+ function readNativeFirebaseConfig(projectRoot) {
561
+ const result = {};
562
+ if (![
563
+ "app.json",
564
+ "app.config.js",
565
+ "app.config.ts",
566
+ "app.config.cjs",
567
+ "app.config.mjs"
568
+ ].some((name) => import_node_fs2.default.existsSync(import_node_path2.default.join(projectRoot, name))))
569
+ return result;
570
+ const require2 = (0, import_node_module.createRequire)(import_node_path2.default.join(projectRoot, "package.json"));
571
+ const configModule = require2("@expo/config");
572
+ if (!isRecord(configModule) || typeof configModule.getConfig !== "function") {
573
+ throw new Error("Expo native configuration is unavailable.");
574
+ }
575
+ const resolved = Reflect.apply(configModule.getConfig, configModule, [
576
+ projectRoot,
577
+ { skipSDKVersionRequirement: true }
578
+ ]);
579
+ const config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {};
580
+ for (const platform of ["ios", "android"]) {
581
+ const native = config[platform];
582
+ if (!isRecord(native) || typeof native.googleServicesFile !== "string") continue;
583
+ try {
584
+ const source = import_node_fs2.default.readFileSync(
585
+ import_node_path2.default.resolve(projectRoot, native.googleServicesFile),
586
+ "utf8"
587
+ );
588
+ const parsed = platform === "ios" ? parsePlistSource(source) : JSON.parse(source);
589
+ if (!isRecord(parsed)) throw new Error("Invalid Google services file.");
590
+ if (platform === "ios") {
591
+ result[platform] = {
592
+ apiKey: parsed.API_KEY,
593
+ appId: parsed.GOOGLE_APP_ID,
594
+ projectId: parsed.PROJECT_ID,
595
+ databaseURL: parsed.DATABASE_URL,
596
+ gaTrackingId: parsed.TRACKING_ID,
597
+ storageBucket: parsed.STORAGE_BUCKET,
598
+ messagingSenderId: parsed.GCM_SENDER_ID,
599
+ clientId: parsed.CLIENT_ID,
600
+ androidClientID: parsed.ANDROID_CLIENT_ID,
601
+ deepLinkUrlScheme: parsed.REVERSED_CLIENT_ID
602
+ };
603
+ } else {
604
+ const project = isRecord(parsed.project_info) ? parsed.project_info : {};
605
+ const clients = Array.isArray(parsed.client) ? parsed.client : [];
606
+ const client = clients.find((value) => {
607
+ if (!isRecord(value) || !isRecord(value.client_info)) return false;
608
+ const android = value.client_info.android_client_info;
609
+ return isRecord(android) && android.package_name === native.package;
610
+ });
611
+ if (!isRecord(client) || !isRecord(client.client_info))
612
+ throw new Error("No Google services client matches the Android package.");
613
+ const apiKeys = Array.isArray(client.api_key) ? client.api_key : [];
614
+ const apiKey = apiKeys.find(
615
+ (value) => isRecord(value) && typeof value.current_key === "string"
616
+ );
617
+ const oauthClients = Array.isArray(client.oauth_client) ? client.oauth_client : [];
618
+ const oauth = oauthClients.find(
619
+ (value) => isRecord(value) && value.client_type === 3
620
+ );
621
+ result[platform] = {
622
+ apiKey: isRecord(apiKey) ? apiKey.current_key : void 0,
623
+ appId: client.client_info.mobilesdk_app_id,
624
+ projectId: project.project_id,
625
+ databaseURL: project.firebase_url,
626
+ storageBucket: project.storage_bucket,
627
+ messagingSenderId: project.project_number,
628
+ clientId: isRecord(oauth) ? oauth.client_id : void 0
629
+ };
630
+ }
631
+ } catch (error) {
632
+ result[platform] = { error: error instanceof Error ? error.message : String(error) };
633
+ }
634
+ }
635
+ return result;
636
+ }
637
+
531
638
  // src/runtime-assets.ts
532
639
  var import_fs = __toESM(require("fs"), 1);
533
640
  var import_path = __toESM(require("path"), 1);
@@ -539,28 +646,28 @@ function isValidRuntimeVersion(value) {
539
646
  }
540
647
 
541
648
  // src/home-paths.ts
542
- var import_node_fs2 = __toESM(require("node:fs"), 1);
649
+ var import_node_fs3 = __toESM(require("node:fs"), 1);
543
650
  var import_node_os = require("node:os");
544
- var import_node_path2 = __toESM(require("node:path"), 1);
651
+ var import_node_path3 = __toESM(require("node:path"), 1);
545
652
  var PEACH_HOME_ENV = "PEACH_HOME";
546
653
  var ACTIVE_RUNTIME_FILE = "active";
547
654
  function rnxHomeDir() {
548
655
  const override = process.env[PEACH_HOME_ENV];
549
- if (override && override.length > 0) return import_node_path2.default.resolve(override);
550
- return import_node_path2.default.join((0, import_node_os.homedir)(), ".peach");
656
+ if (override && override.length > 0) return import_node_path3.default.resolve(override);
657
+ return import_node_path3.default.join((0, import_node_os.homedir)(), ".peach");
551
658
  }
552
659
  function runtimesDir() {
553
- return import_node_path2.default.join(rnxHomeDir(), "runtimes");
660
+ return import_node_path3.default.join(rnxHomeDir(), "runtimes");
554
661
  }
555
662
  function runtimeDir(version) {
556
- return import_node_path2.default.join(runtimesDir(), version);
663
+ return import_node_path3.default.join(runtimesDir(), version);
557
664
  }
558
665
  function activeRuntimeFile() {
559
- return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
666
+ return import_node_path3.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
560
667
  }
561
668
  function readActiveRuntime() {
562
669
  try {
563
- const value = import_node_fs2.default.readFileSync(activeRuntimeFile(), "utf8").trim();
670
+ const value = import_node_fs3.default.readFileSync(activeRuntimeFile(), "utf8").trim();
564
671
  return value.length > 0 ? value : null;
565
672
  } catch {
566
673
  return null;
@@ -873,6 +980,22 @@ function withRNX(config) {
873
980
  });
874
981
  return;
875
982
  }
983
+ if ((req.url || "").split("?")[0] === "/__peach-native-firebase-config") {
984
+ try {
985
+ res.setHeader("Content-Type", "application/json");
986
+ res.setHeader("Cache-Control", "no-store");
987
+ res.setHeader("Access-Control-Allow-Origin", "*");
988
+ res.end(JSON.stringify(readNativeFirebaseConfig(cfgProjectRoot)));
989
+ } catch (error) {
990
+ res.statusCode = 400;
991
+ res.end(
992
+ JSON.stringify({
993
+ error: error instanceof Error ? error.message : String(error)
994
+ })
995
+ );
996
+ }
997
+ return;
998
+ }
876
999
  const url = req.url || "";
877
1000
  const pathname = url.split("?")[0];
878
1001
  const runtimeRoot = resolveRuntimeRootForRequestHost(req.headers?.host);