peachsim 0.1.2186 → 0.1.2187

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 (93) hide show
  1. package/dist-lib/agent-daemon-client.cjs +1 -1
  2. package/dist-lib/agent-events.cjs +1 -1
  3. package/dist-lib/attached-projects.cjs +1 -1
  4. package/dist-lib/auth/shared-session.cjs +1 -1
  5. package/dist-lib/backend-origin.cjs +1 -1
  6. package/dist-lib/beta.cjs +1 -1
  7. package/dist-lib/beta.mjs +1 -1
  8. package/dist-lib/bridge-constants.cjs +1 -1
  9. package/dist-lib/bridge-contract-input.cjs +1 -1
  10. package/dist-lib/bridge-contract-input.mjs +1 -1
  11. package/dist-lib/bridge-contract.cjs +1 -1
  12. package/dist-lib/bridge-contract.mjs +1 -1
  13. package/dist-lib/bundle-channel.cjs +2706 -2381
  14. package/dist-lib/capture-contract.cjs +1 -1
  15. package/dist-lib/capture-contract.mjs +1 -1
  16. package/dist-lib/cloud-contract.cjs +1 -1
  17. package/dist-lib/cloud-contract.mjs +1 -1
  18. package/dist-lib/cloud-test-args.cjs +1 -1
  19. package/dist-lib/cloud-test-args.mjs +1 -1
  20. package/dist-lib/cloud.cjs +1 -1
  21. package/dist-lib/cloud.mjs +1 -1
  22. package/dist-lib/config.cjs +1 -1
  23. package/dist-lib/config.mjs +1 -1
  24. package/dist-lib/detox/index.cjs +1 -1
  25. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  26. package/dist-lib/expo-swift-bundle.cjs +3227 -3220
  27. package/dist-lib/expo-swift-metadata.cjs +1 -1
  28. package/dist-lib/expo-swift-metadata.mjs +1 -1
  29. package/dist-lib/home-paths.cjs +1 -1
  30. package/dist-lib/host/bridge-host.cjs +4538 -4213
  31. package/dist-lib/host/fetch-proxy-handler.cjs +6 -5
  32. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  33. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  34. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  35. package/dist-lib/host/websocket-proxy.cjs +1 -1
  36. package/dist-lib/index.cjs +429 -279
  37. package/dist-lib/jump-to-source-babel.cjs +1 -1
  38. package/dist-lib/jump-to-source-native.cjs +1 -1
  39. package/dist-lib/kotlin-host.cjs +645 -284
  40. package/dist-lib/menu.cjs +1 -1
  41. package/dist-lib/menu.mjs +1 -1
  42. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  43. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  44. package/dist-lib/metro-production-bundle.cjs +1 -1
  45. package/dist-lib/metro-production-bundle.mjs +1 -1
  46. package/dist-lib/metro.cjs +730 -580
  47. package/dist-lib/native-app-identity-project.cjs +2 -2
  48. package/dist-lib/native-app-identity-project.mjs +2 -2
  49. package/dist-lib/native-app-identity.cjs +1 -1
  50. package/dist-lib/native-app-identity.mjs +1 -1
  51. package/dist-lib/native-firebase-metadata.cjs +1 -1
  52. package/dist-lib/native-firebase-metadata.mjs +1 -1
  53. package/dist-lib/pdfium-raster.cjs +1 -1
  54. package/dist-lib/pdfium-raster.mjs +1 -1
  55. package/dist-lib/plist.cjs +1 -1
  56. package/dist-lib/plist.mjs +1 -1
  57. package/dist-lib/profiles.cjs +1 -1
  58. package/dist-lib/public-brand.cjs +1 -1
  59. package/dist-lib/public-origins-lib-esm.json +24 -24
  60. package/dist-lib/public-origins-lib.json +99 -59
  61. package/dist-lib/react-native-host-modules.cjs +1 -1
  62. package/dist-lib/react-native-host-modules.mjs +1 -1
  63. package/dist-lib/reap-browser.cjs +1 -1
  64. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  65. package/dist-lib/sdk.cjs +1 -1
  66. package/dist-lib/sdk.mjs +1 -1
  67. package/dist-lib/skills.cjs +5196 -4871
  68. package/dist-lib/swift-compile.cjs +2 -2
  69. package/dist-lib/swift-compile.mjs +2 -2
  70. package/dist-lib/swift-package.cjs +1 -1
  71. package/dist-lib/swift-package.mjs +1 -1
  72. package/dist-lib/swift-submit.cjs +1 -1
  73. package/dist-lib/swift-submit.mjs +1 -1
  74. package/dist-lib/swift-toolchain.cjs +1 -1
  75. package/dist-lib/swift.cjs +1 -1
  76. package/dist-lib/vite-swift.cjs +2 -2
  77. package/dist-lib/vite.cjs +6 -5
  78. package/dist-lib/worklet-executable.cjs +1 -1
  79. package/dist-lib/worklet-executable.mjs +1 -1
  80. package/kotlin/sdk.tar.gz +0 -0
  81. package/package.json +1 -1
  82. package/sdk/ios/System/Library/Frameworks/CFNetwork.framework/Headers/CFNetwork.h +10 -0
  83. package/src/android-autolinking.ts +45 -4
  84. package/src/android-bridge-packages.ts +2 -2
  85. package/src/android-gradle-sources.ts +143 -0
  86. package/src/androidAutolinkingContract.ts +8 -0
  87. package/src/androidGradleContract.ts +14 -0
  88. package/src/expo-kotlin-host.ts +3 -0
  89. package/src/java-module-abi.ts +145 -0
  90. package/src/javaAbiContract.ts +14 -0
  91. package/src/kotlin-host.ts +55 -3
  92. package/src/nitro-source.ts +2 -167
  93. package/src/react-native-autolinking.ts +153 -0
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -12474,7 +12474,7 @@ var darwinRecordsRegion = (quoted) => quoted.length ? ["-Wl,--start-lib", ...quo
12474
12474
  var REACTOR_FLAG = '"-Xclang-linker", "-mexec-model=reactor",\n';
12475
12475
  var MULTI_MANIFEST_VERSION = 68;
12476
12476
  var SWIFT_HEADER_PRODUCTS_TARGET = "PeachHeaderProducts";
12477
- var compilerSourceDigest = true ? "0d2e8d6fb4545fb31a692a87bd3215ef3a9a64a8c3e1b2fc1f2a3e79511325ec" : swiftCompilerSourceDigest(__sootsim_import_meta_dirname);
12477
+ var compilerSourceDigest = true ? "08a3436f8de8fff57c3ffe7822dc37ac9addd391678cb64d73212534a6e94aa1" : swiftCompilerSourceDigest(__sootsim_import_meta_dirname);
12478
12478
  function swiftArtifactHash(input, release, moduleRoot) {
12479
12479
  const hash = (0, import_node_crypto13.createHash)("sha256");
12480
12480
  hash.update(`swift-compile
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/swift-compile.ts
4
4
  import {
@@ -12454,7 +12454,7 @@ var darwinRecordsRegion = (quoted) => quoted.length ? ["-Wl,--start-lib", ...quo
12454
12454
  var REACTOR_FLAG = '"-Xclang-linker", "-mexec-model=reactor",\n';
12455
12455
  var MULTI_MANIFEST_VERSION = 68;
12456
12456
  var SWIFT_HEADER_PRODUCTS_TARGET = "PeachHeaderProducts";
12457
- var compilerSourceDigest = true ? "0d2e8d6fb4545fb31a692a87bd3215ef3a9a64a8c3e1b2fc1f2a3e79511325ec" : swiftCompilerSourceDigest(import.meta.dirname);
12457
+ var compilerSourceDigest = true ? "08a3436f8de8fff57c3ffe7822dc37ac9addd391678cb64d73212534a6e94aa1" : swiftCompilerSourceDigest(import.meta.dirname);
12458
12458
  function swiftArtifactHash(input, release, moduleRoot) {
12459
12459
  const hash = createHash13("sha256");
12460
12460
  hash.update(`swift-compile
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/swift-package.ts
4
4
  function swiftManifestSettings(target) {
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (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
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -17269,7 +17269,7 @@ var darwinRecordsRegion = (quoted) => quoted.length ? ["-Wl,--start-lib", ...quo
17269
17269
  var REACTOR_FLAG = '"-Xclang-linker", "-mexec-model=reactor",\n';
17270
17270
  var MULTI_MANIFEST_VERSION = 68;
17271
17271
  var SWIFT_HEADER_PRODUCTS_TARGET = "PeachHeaderProducts";
17272
- var compilerSourceDigest = true ? "0d2e8d6fb4545fb31a692a87bd3215ef3a9a64a8c3e1b2fc1f2a3e79511325ec" : swiftCompilerSourceDigest(__sootsim_import_meta_dirname);
17272
+ var compilerSourceDigest = true ? "08a3436f8de8fff57c3ffe7822dc37ac9addd391678cb64d73212534a6e94aa1" : swiftCompilerSourceDigest(__sootsim_import_meta_dirname);
17273
17273
  function swiftArtifactHash(input, release, moduleRoot) {
17274
17274
  const hash = (0, import_node_crypto13.createHash)("sha256");
17275
17275
  hash.update(`swift-compile
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -5391,7 +5391,7 @@ var FOUNDATION_IMPLICIT_MODULES = [
5391
5391
  var FOUNDATION_IMPLICIT_FLAGS = FOUNDATION_IMPLICIT_MODULES.map(
5392
5392
  (module2) => `, "-Xfrontend", "-import-module", "-Xfrontend", "${module2}"`
5393
5393
  ).join("");
5394
- var compilerSourceDigest = true ? "0d2e8d6fb4545fb31a692a87bd3215ef3a9a64a8c3e1b2fc1f2a3e79511325ec" : swiftCompilerSourceDigest2(__sootsim_import_meta_dirname);
5394
+ var compilerSourceDigest = true ? "08a3436f8de8fff57c3ffe7822dc37ac9addd391678cb64d73212534a6e94aa1" : swiftCompilerSourceDigest2(__sootsim_import_meta_dirname);
5395
5395
  var CORE_FOUNDATION_HANDLE_IMPORTS = [
5396
5396
  "CFAllocator",
5397
5397
  "CFArray",
@@ -5444,8 +5444,6 @@ init_define_SWIFT_COVERAGE_SOURCE_DIGESTS();
5444
5444
 
5445
5445
  // src/nitro-source.ts
5446
5446
  init_define_SWIFT_COVERAGE_SOURCE_DIGESTS();
5447
- var import_node_child_process7 = require("node:child_process");
5448
- var import_node_util6 = require("node:util");
5449
5447
 
5450
5448
  // src/nitro-dependencies.ts
5451
5449
  init_define_SWIFT_COVERAGE_SOURCE_DIGESTS();
@@ -5592,7 +5590,10 @@ var RN_FMT_12_DEPENDENCIES = [
5592
5590
  }
5593
5591
  ];
5594
5592
 
5595
- // src/nitro-source.ts
5593
+ // src/react-native-autolinking.ts
5594
+ init_define_SWIFT_COVERAGE_SOURCE_DIGESTS();
5595
+ var import_node_child_process7 = require("node:child_process");
5596
+ var import_node_util6 = require("node:util");
5596
5597
  var run5 = (0, import_node_util6.promisify)(import_node_child_process7.execFile);
5597
5598
 
5598
5599
  // src/workspace-root.ts
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = '', __sootsim_import_meta_filename = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; __sootsim_import_meta_filename = __filename; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.2186 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.2187 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/worklet-executable.ts
4
4
  import { parse } from "acorn";
package/kotlin/sdk.tar.gz CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peachsim",
3
- "version": "0.1.2186",
3
+ "version": "0.1.2187",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for peach.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -26,4 +26,14 @@ CFN_EXPORT const CFStringRef kCFStreamPropertySSLPeerCertificates CF_DEPRECATED(
26
26
  CFN_EXPORT const CFStringRef kCFStreamSSLAllowsExpiredCertificates CF_DEPRECATED(10_4, 10_6, 2_0, 4_0);
27
27
  CFN_EXPORT const CFStringRef kCFStreamSSLAllowsExpiredRoots CF_DEPRECATED(10_4, 10_6, 2_0, 4_0);
28
28
  CFN_EXPORT const CFStringRef kCFStreamSSLAllowsAnyRoot CF_DEPRECATED(10_4, 10_6, 2_0, 4_0);
29
+ CFN_EXPORT const CFStringRef kCFStreamPropertySSLContext CF_AVAILABLE(10_9, 5_0);
30
+ CFN_EXPORT const CFStringRef kCFStreamPropertyNoCellular CF_AVAILABLE(10_8, 5_0);
31
+ CFN_EXPORT const CFStringRef kCFStreamPropertyConnectionIsCellular CF_AVAILABLE(10_8, 6_0);
32
+ CFN_EXPORT const CFStringRef kCFStreamPropertyAllowExpensiveNetworkAccess API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
33
+ CFN_EXPORT const CFStringRef kCFStreamPropertyConnectionIsExpensive API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
34
+ CFN_EXPORT const CFStringRef kCFStreamPropertyAllowConstrainedNetworkAccess API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
35
+ CFN_EXPORT const CFStringRef kCFStreamPropertyProxyLocalBypass CF_AVAILABLE(10_4, 2_0);
36
+ CFN_EXPORT const CFStringRef kCFStreamPropertySocketRemoteHost CF_AVAILABLE(10_3, 2_0);
37
+ CFN_EXPORT const CFStringRef kCFStreamPropertySocketRemoteNetService CF_AVAILABLE(10_3, 2_0);
38
+ CFN_EXPORT const CFStringRef kCFStreamPropertySocketExtendedBackgroundIdleMode CF_AVAILABLE(10_11, 9_0);
29
39
  CF_EXTERN_C_END
@@ -1,5 +1,4 @@
1
- // use the app's Expo resolver so transitive dependencies, exclusions and
2
- // plugin-only Android packages follow the same autolinking as Gradle.
1
+ // use each native autolinker for its module families and platform exclusions.
3
2
  import { execFile } from 'node:child_process'
4
3
  import fs from 'node:fs'
5
4
  import { createRequire } from 'node:module'
@@ -8,6 +7,8 @@ import { promisify } from 'node:util'
8
7
  import { readAndroidAutolinkedPackages } from './androidAutolinkingContract'
9
8
  import { PEACH_FORKED_SCRIPT_ENV } from './forked-script-contract'
10
9
  import { isRecord } from './is-record'
10
+ import { reactNativeAutolinkingConfig } from './react-native-autolinking'
11
+ import type { AndroidAutolinkedDependency } from './androidAutolinkingContract'
11
12
 
12
13
  const run = promisify(execFile)
13
14
 
@@ -71,6 +72,46 @@ async function resolveAndroidModules(
71
72
  export async function collectAndroidAutolinkedPackages(
72
73
  appRoot: string,
73
74
  ): Promise<string[]> {
74
- const modules = await resolveExpoAndroidAutolinking(appRoot)
75
- return readAndroidAutolinkedPackages(modules.map((entry) => entry.packageName))
75
+ const [modules, dependencies] = await Promise.all([
76
+ resolveExpoAndroidAutolinking(appRoot),
77
+ resolveReactNativeAndroidAutolinking(appRoot),
78
+ ])
79
+ return readAndroidAutolinkedPackages([
80
+ ...modules.map((entry) => entry.packageName),
81
+ ...dependencies.map((entry) => entry.name),
82
+ ])
83
+ }
84
+
85
+ export async function resolveReactNativeAndroidAutolinking(
86
+ appRoot: string,
87
+ ): Promise<AndroidAutolinkedDependency[]> {
88
+ const config = await reactNativeAutolinkingConfig(appRoot, 'android')
89
+ if (!isRecord(config) || !isRecord(config.dependencies))
90
+ throw new Error(`${appRoot}: React Native autolinking config has no dependencies`)
91
+ const linked: AndroidAutolinkedDependency[] = []
92
+ for (const [name, dependency] of Object.entries(config.dependencies)) {
93
+ if (!isRecord(dependency) || !isRecord(dependency.platforms))
94
+ throw new Error(
95
+ `${appRoot}: React Native autolinking dependency ${name} is malformed`,
96
+ )
97
+ const android = dependency.platforms.android
98
+ if (android == null) continue
99
+ if (!isRecord(android) || typeof dependency.root !== 'string')
100
+ throw new Error(
101
+ `${appRoot}: React Native autolinking dependency ${name} has no Android project`,
102
+ )
103
+ const string = (field: string): string | null => {
104
+ const value = android[field]
105
+ if (value == null || typeof value === 'string') return value ?? null
106
+ throw new Error(`${appRoot}: Android dependency ${name} has invalid ${field}`)
107
+ }
108
+ linked.push({
109
+ name,
110
+ root: dependency.root,
111
+ sourceDir: string('sourceDir'),
112
+ packageImportPath: string('packageImportPath'),
113
+ packageInstance: string('packageInstance'),
114
+ })
115
+ }
116
+ return linked
76
117
  }
@@ -50,7 +50,7 @@ export interface BridgeSelection {
50
50
  const qualified = (file: { package: string }, name: string) =>
51
51
  file.package ? `${file.package}.${name}` : name
52
52
 
53
- function readMethod(value: unknown): BridgeMethod {
53
+ export function readBridgeMethod(value: unknown): BridgeMethod {
54
54
  if (
55
55
  !isRecord(value) ||
56
56
  typeof value.name !== 'string' ||
@@ -117,7 +117,7 @@ export function readBridgeFiles(output: string): BridgeFile[] {
117
117
  !Array.isArray(entry.methods)
118
118
  )
119
119
  throw new Error('bridge-modules printed an invalid module')
120
- return { name: entry.name, methods: entry.methods.map(readMethod) }
120
+ return { name: entry.name, methods: entry.methods.map(readBridgeMethod) }
121
121
  }),
122
122
  }
123
123
  })
@@ -0,0 +1,143 @@
1
+ import { execFile } from 'node:child_process'
2
+ import { randomBytes } from 'node:crypto'
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+ import { promisify } from 'node:util'
6
+ import { PEACH_FORKED_SCRIPT_ENV } from './forked-script-contract'
7
+ import { isRecord } from './is-record'
8
+ import { kotlinHome } from './kotlin-toolchain'
9
+ import type {
10
+ AndroidGradleSourceRequest,
11
+ AndroidGradleSources,
12
+ } from './androidGradleContract'
13
+
14
+ const run = promisify(execFile)
15
+ const modelQuery = `
16
+ import groovy.json.JsonOutput
17
+ import groovy.json.JsonSlurper
18
+
19
+ def request = new JsonSlurper().parseText(new String(Base64.decoder.decode('__PEACH_REQUEST__'), 'UTF-8'))
20
+ gradle.projectsEvaluated {
21
+ if (gradle.rootProject.projectDir.canonicalPath != request.root) return
22
+ def selected = []
23
+ request.projects.eachWithIndex { directory, index ->
24
+ def matches = gradle.rootProject.allprojects.findAll { it.projectDir.canonicalPath == directory }
25
+ if (matches.size() != 1) throw new GradleException('Expected one Android project for ' + directory)
26
+ def project = matches[0]
27
+ if (project.pluginManager.hasPlugin('org.jetbrains.kotlin.multiplatform')) {
28
+ throw new GradleException('Kotlin multiplatform source selection is not supported: ' + project.path)
29
+ }
30
+ def library = project.pluginManager.hasPlugin('com.android.library')
31
+ if (!library && !project.pluginManager.hasPlugin('com.android.application')) {
32
+ throw new GradleException('Project has no Android application or library plugin: ' + project.path)
33
+ }
34
+ def android = project.extensions.getByName('android')
35
+ def variants = library ? android.libraryVariants : android.applicationVariants
36
+ def variant = variants.find { it.name == request.variant }
37
+ if (variant == null) throw new GradleException('Android variant ' + request.variant + ' is absent: ' + project.path)
38
+ def generators = []
39
+ def buildConfig = variant.generateBuildConfigProvider
40
+ if (buildConfig != null) generators.add(buildConfig)
41
+ if (project.pluginManager.hasPlugin('com.facebook.react')) {
42
+ generators.add(project.tasks.named('generateCodegenArtifactsFromSchema'))
43
+ }
44
+ def kotlin = project.tasks.findByName('compile' + variant.name.capitalize() + 'Kotlin')
45
+ def kotlinSources = kotlin == null ? project.files() : kotlin.sources
46
+ def javaSources = variant.javaCompileProvider.get().source
47
+ def query = project.tasks.register(request.task) {
48
+ dependsOn(generators)
49
+ dependsOn(kotlinSources.buildDependencies, javaSources.buildDependencies)
50
+ doLast {
51
+ def files = (kotlinSources.files + javaSources.files).unique()
52
+ def unknown = files.find { !it.name.endsWith('.kt') && !it.name.endsWith('.java') }
53
+ if (unknown != null) throw new GradleException('Unsupported Android source: ' + unknown)
54
+ new File(request.output, index.toString() + '.json').text = JsonOutput.toJson([
55
+ projectDir:project.projectDir.canonicalPath,
56
+ projectPath:project.path,
57
+ variant:variant.name,
58
+ applicationId:library ? null : variant.applicationId,
59
+ kotlin:files.findAll { it.name.endsWith('.kt') }.collect { it.absolutePath }.sort(),
60
+ java:files.findAll { it.name.endsWith('.java') }.collect { it.absolutePath }.sort()
61
+ ])
62
+ }
63
+ }
64
+ selected.add(query)
65
+ }
66
+ gradle.rootProject.tasks.register(request.task + 'All') { dependsOn(selected) }
67
+ }
68
+ `
69
+
70
+ export async function resolveAndroidGradleSources(
71
+ request: AndroidGradleSourceRequest,
72
+ ): Promise<AndroidGradleSources[]> {
73
+ let { root } = request
74
+ const { projects: projectDirs, variant } = request
75
+ if (projectDirs.length === 0) return []
76
+ if (!path.isAbsolute(root) || projectDirs.some((dir) => !path.isAbsolute(dir)))
77
+ throw new Error('Android Gradle source selection requires absolute project paths')
78
+ if (!variant) throw new Error('Android Gradle source selection requires a variant')
79
+ root = fs.realpathSync(root)
80
+ const projects = [...new Set(projectDirs.map((dir) => fs.realpathSync(dir)))]
81
+ const parent = path.join(kotlinHome(), 'gradle-sources')
82
+ fs.mkdirSync(parent, { recursive: true })
83
+ const work = fs.mkdtempSync(path.join(parent, '.query-'))
84
+ const task = `peachAndroidSources${randomBytes(8).toString('hex')}`
85
+ const script = path.join(work, 'sources.gradle')
86
+ const encoded = Buffer.from(
87
+ JSON.stringify({ root, projects, variant, output: work, task }),
88
+ ).toString('base64')
89
+ fs.writeFileSync(script, modelQuery.replace('__PEACH_REQUEST__', encoded))
90
+ try {
91
+ await run(
92
+ 'bash',
93
+ [
94
+ path.join(root, 'gradlew'),
95
+ '--init-script',
96
+ script,
97
+ `${task}All`,
98
+ '--no-daemon',
99
+ '--no-configuration-cache',
100
+ '--max-workers=1',
101
+ '--console=plain',
102
+ ],
103
+ {
104
+ cwd: root,
105
+ timeout: 300_000,
106
+ maxBuffer: 8 * 1024 * 1024,
107
+ env: { ...process.env, [PEACH_FORKED_SCRIPT_ENV]: '1' },
108
+ },
109
+ )
110
+ return projects.map((projectDir, index): AndroidGradleSources => {
111
+ const value: unknown = JSON.parse(
112
+ fs.readFileSync(path.join(work, `${index}.json`), 'utf8'),
113
+ )
114
+ if (
115
+ !isRecord(value) ||
116
+ value.projectDir !== projectDir ||
117
+ value.variant !== variant ||
118
+ typeof value.projectPath !== 'string' ||
119
+ (value.applicationId !== null && typeof value.applicationId !== 'string')
120
+ )
121
+ throw new Error('Gradle printed an invalid Android project source model')
122
+ const sources = (field: 'kotlin' | 'java'): string[] => {
123
+ const list = value[field]
124
+ if (
125
+ !Array.isArray(list) ||
126
+ !list.every((file) => typeof file === 'string' && path.isAbsolute(file))
127
+ )
128
+ throw new Error(`Gradle printed invalid Android ${field} source paths`)
129
+ return list.map(String)
130
+ }
131
+ return {
132
+ projectDir,
133
+ projectPath: value.projectPath,
134
+ variant,
135
+ applicationId: value.applicationId,
136
+ kotlin: sources('kotlin'),
137
+ java: sources('java'),
138
+ }
139
+ })
140
+ } finally {
141
+ fs.rmSync(work, { recursive: true, force: true })
142
+ }
143
+ }
@@ -6,6 +6,14 @@ import {
6
6
 
7
7
  const FOOTER = '__peachAndroidAutolinkedPackages'
8
8
 
9
+ export interface AndroidAutolinkedDependency {
10
+ name: string
11
+ root: string
12
+ sourceDir: string | null
13
+ packageImportPath: string | null
14
+ packageInstance: string | null
15
+ }
16
+
9
17
  export function readAndroidAutolinkedPackages(value: unknown): string[] {
10
18
  if (
11
19
  !Array.isArray(value) ||
@@ -0,0 +1,14 @@
1
+ export interface AndroidGradleSourceRequest {
2
+ root: string
3
+ projects: readonly string[]
4
+ variant: string
5
+ }
6
+
7
+ export interface AndroidGradleSources {
8
+ projectDir: string
9
+ projectPath: string
10
+ variant: string
11
+ applicationId: string | null
12
+ kotlin: string[]
13
+ java: string[]
14
+ }
@@ -15,6 +15,7 @@ import { peachAnsweredNativePackages } from './answeredNativePackages'
15
15
  import { isLoopbackHost } from './backend-origin'
16
16
  import { isRecord } from './is-record'
17
17
  import { peachKotlinModuleRoot } from './kotlin-module'
18
+ import type { AndroidGradleSourceRequest } from './androidGradleContract'
18
19
  import type { ExpoKotlinCompilationResult } from './expoKotlinContract'
19
20
  import type { IncomingMessage, ServerResponse } from 'node:http'
20
21
 
@@ -24,6 +25,8 @@ export interface ExpoKotlinModules {
24
25
  // the registration names Android's ExpoModulesPackageList passes, in order
25
26
  modules: { classifier: string; name: string | null }[]
26
27
  sources: string[]
28
+ javaSpecs?: string[]
29
+ gradleSources?: AndroidGradleSourceRequest
27
30
  // the app's own legacy React Native modules, hosted beside the Expo ones
28
31
  bridge: BridgeSelection | null
29
32
  }
@@ -0,0 +1,145 @@
1
+ import { execFile } from 'node:child_process'
2
+ import { createHash } from 'node:crypto'
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+ import { promisify } from 'node:util'
6
+ import { readBridgeMethod } from './android-bridge-packages'
7
+ import { isRecord } from './is-record'
8
+ import { kotlinHome } from './kotlin-toolchain'
9
+ import type { JavaModuleSpec, JavaModuleSpecs } from './javaAbiContract'
10
+ import type { KotlinToolchainInstallation } from './kotlinSdkContract'
11
+
12
+ const run = promisify(execFile)
13
+ export const JAVA_BINDINGS_INITIALIZER = 'initializeJavaBindings'
14
+
15
+ export async function readJavaModuleSpecs(
16
+ files: string[],
17
+ sdkRoot: string,
18
+ toolchain: KotlinToolchainInstallation,
19
+ ): Promise<JavaModuleSpecs> {
20
+ const digest = createHash('sha256')
21
+ const parent = path.join(kotlinHome(), 'java-specs')
22
+ fs.mkdirSync(parent, { recursive: true })
23
+ const work = fs.mkdtempSync(path.join(parent, '.read-'))
24
+ try {
25
+ const origins = new Map<string, string>()
26
+ for (const [index, file] of files.entries()) {
27
+ const bytes = fs.readFileSync(file)
28
+ digest.update(file).update('\0').update(bytes).update('\0')
29
+ const target = path.join(work, String(index), path.basename(file))
30
+ fs.mkdirSync(path.dirname(target))
31
+ fs.writeFileSync(target, bytes)
32
+ origins.set(target, file)
33
+ }
34
+ const { stdout } = await run(
35
+ path.join(toolchain.javaHome, 'bin', 'java'),
36
+ [
37
+ '-cp',
38
+ [
39
+ path.join(sdkRoot, 'tools.jar'),
40
+ path.resolve(path.dirname(toolchain.kotlinc), '../lib/kotlin-compiler.jar'),
41
+ path.resolve(path.dirname(toolchain.kotlinc), '../lib/kotlin-stdlib.jar'),
42
+ ].join(path.delimiter),
43
+ 'dev.peach.tools.javaabi.JavaModuleSpecsKt',
44
+ ...origins.keys(),
45
+ ],
46
+ { maxBuffer: 16 * 1024 * 1024 },
47
+ )
48
+ const specs = stdout
49
+ .split('\n')
50
+ .filter(Boolean)
51
+ .map((line): JavaModuleSpec => {
52
+ const row: unknown = JSON.parse(line)
53
+ if (
54
+ !isRecord(row) ||
55
+ typeof row.file !== 'string' ||
56
+ typeof row.className !== 'string' ||
57
+ (row.name !== null && typeof row.name !== 'string') ||
58
+ typeof row.source !== 'string' ||
59
+ !Array.isArray(row.methods)
60
+ )
61
+ throw new Error('Java module reader printed an invalid spec')
62
+ const file = origins.get(row.file)
63
+ if (!file) throw new Error('Java module reader named an unknown input')
64
+ return {
65
+ file,
66
+ className: row.className,
67
+ name: row.name,
68
+ source: row.source,
69
+ methods: row.methods.map(readBridgeMethod),
70
+ }
71
+ })
72
+ return { sha256: digest.digest('hex'), specs }
73
+ } finally {
74
+ fs.rmSync(work, { recursive: true, force: true })
75
+ }
76
+ }
77
+
78
+ export async function compileJavaModuleAbi(input: {
79
+ specs: JavaModuleSpecs
80
+ work: string
81
+ hash: string
82
+ toolchain: KotlinToolchainInstallation
83
+ libraries: string[]
84
+ sdkRoot: string
85
+ sdkLibrary: string
86
+ language: string
87
+ }): Promise<string> {
88
+ const { specs, work, hash, toolchain, libraries, sdkRoot, sdkLibrary, language } = input
89
+ const directory = path.join(work, 'java-abi')
90
+ fs.mkdirSync(directory)
91
+ const sources = specs.specs.map((spec, index) => {
92
+ const target = path.join(directory, `Spec${index}.kt`)
93
+ fs.writeFileSync(target, spec.source)
94
+ return target
95
+ })
96
+ const initializer = path.join(directory, 'Bindings.kt')
97
+ fs.writeFileSync(
98
+ initializer,
99
+ [
100
+ 'package dev.peach.jni',
101
+ `internal fun ${JAVA_BINDINGS_INITIALIZER}() { error("Java bindings require the compiler plugin") }`,
102
+ ].join('\n'),
103
+ )
104
+ const name = `peach-java-abi-${hash}`
105
+ await run(
106
+ toolchain.kotlinc,
107
+ [
108
+ '-J-Xmx2g',
109
+ '-Xwasm-target=js',
110
+ '-libraries',
111
+ libraries.join(path.delimiter),
112
+ `-Xplugin=${path.join(sdkRoot, 'plugin.jar')}`,
113
+ `-Xfriend-modules=${sdkLibrary}`,
114
+ '-language-version',
115
+ language,
116
+ '-api-version',
117
+ language,
118
+ '-nowarn',
119
+ '-ir-output-dir',
120
+ directory,
121
+ '-ir-output-name',
122
+ name,
123
+ ...sources,
124
+ initializer,
125
+ ],
126
+ { maxBuffer: 16 * 1024 * 1024 },
127
+ )
128
+ const library = path.join(directory, 'java-abi.klib')
129
+ await run(
130
+ path.join(toolchain.javaHome, 'bin', 'java'),
131
+ [
132
+ '-cp',
133
+ [
134
+ path.join(sdkRoot, 'tools.jar'),
135
+ path.resolve(path.dirname(toolchain.kotlinc), '../lib/kotlin-compiler.jar'),
136
+ path.resolve(path.dirname(toolchain.kotlinc), '../lib/kotlin-stdlib.jar'),
137
+ ].join(path.delimiter),
138
+ 'dev.peach.tools.platform.JavaPlatformTypesKt',
139
+ path.join(directory, `${name}.klib`),
140
+ library,
141
+ ],
142
+ { maxBuffer: 16 * 1024 * 1024 },
143
+ )
144
+ return library
145
+ }
@@ -0,0 +1,14 @@
1
+ import type { BridgeMethod } from './android-bridge-packages'
2
+
3
+ export interface JavaModuleSpec {
4
+ file: string
5
+ className: string
6
+ name: string | null
7
+ source: string
8
+ methods: BridgeMethod[]
9
+ }
10
+
11
+ export interface JavaModuleSpecs {
12
+ sha256: string
13
+ specs: JavaModuleSpec[]
14
+ }