peachsim 0.1.629 → 0.1.631

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 (128) hide show
  1. package/README.md +8 -4
  2. package/cli/app-fonts.ts +23 -4
  3. package/cli/bridge-flow-runner.ts +45 -31
  4. package/cli/cli-update.ts +2 -7
  5. package/cli/cloud-test-tunnel.ts +16 -3
  6. package/cli/command-registry.ts +1 -0
  7. package/cli/commands/compat.ts +11 -60
  8. package/cli/commands/config.ts +1 -1
  9. package/cli/commands/control.ts +40 -8
  10. package/cli/commands/daemon-mac-app.ts +4 -2
  11. package/cli/commands/daemon.ts +4 -4
  12. package/cli/commands/detect.ts +289 -26
  13. package/cli/commands/device.ts +2 -3
  14. package/cli/commands/inspect/actions.ts +125 -90
  15. package/cli/commands/inspect/core.ts +1 -1
  16. package/cli/commands/inspect.ts +10 -1
  17. package/cli/commands/maestro.ts +3 -1
  18. package/cli/commands/platform.ts +1 -1
  19. package/cli/commands/project-report.ts +386 -0
  20. package/cli/commands/projectReportContract.ts +42 -0
  21. package/cli/commands/report-issue.ts +38 -54
  22. package/cli/commands/screenshot-layers.ts +1 -1
  23. package/cli/commands/screenshot.ts +1 -1
  24. package/cli/commands/setup.ts +6 -4
  25. package/cli/commands/skills.ts +0 -31
  26. package/cli/commands/telemetry.ts +8 -3
  27. package/cli/commands/test.ts +347 -134
  28. package/cli/drivers/playwright-provisioning.ts +3 -2
  29. package/cli/drivers/playwright-sim-host.ts +25 -9
  30. package/cli/main.ts +19 -3
  31. package/cli/outbound-endpoints.ts +2 -5
  32. package/cli/privacy.ts +1 -2
  33. package/cli/runtime-diagnostics.ts +51 -0
  34. package/cli/telemetry.ts +78 -7
  35. package/detox/index.ts +77 -51
  36. package/dist-lib/agent-daemon-client.cjs +1 -1
  37. package/dist-lib/agent-events.cjs +1 -1
  38. package/dist-lib/agent-identity.cjs +1 -1
  39. package/dist-lib/agent-sessions.cjs +1 -1
  40. package/dist-lib/attached-projects.cjs +1 -1
  41. package/dist-lib/auth/shared-session.cjs +1 -1
  42. package/dist-lib/backend-origin.cjs +1 -1
  43. package/dist-lib/beta.cjs +1 -1
  44. package/dist-lib/beta.mjs +1 -1
  45. package/dist-lib/bridge-constants.cjs +1 -1
  46. package/dist-lib/bridge-contract-input.cjs +1 -1
  47. package/dist-lib/bridge-contract-input.mjs +1 -1
  48. package/dist-lib/bridge-contract.cjs +1 -1
  49. package/dist-lib/bridge-contract.mjs +1 -1
  50. package/dist-lib/capture-contract.cjs +1 -1
  51. package/dist-lib/capture-contract.mjs +1 -1
  52. package/dist-lib/cli-constants.cjs +1 -1
  53. package/dist-lib/cloud-contract.cjs +1 -1
  54. package/dist-lib/cloud-contract.mjs +1 -1
  55. package/dist-lib/cloud-test-args.cjs +1 -1
  56. package/dist-lib/cloud-test-args.mjs +1 -1
  57. package/dist-lib/cloud.cjs +1 -1
  58. package/dist-lib/cloud.mjs +1 -1
  59. package/dist-lib/config.cjs +1 -1
  60. package/dist-lib/detox/index.cjs +130 -33
  61. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  62. package/dist-lib/home-paths.cjs +8 -5
  63. package/dist-lib/host/bridge-host.cjs +353 -290
  64. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  65. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  66. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  67. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  68. package/dist-lib/host/websocket-proxy.cjs +1 -1
  69. package/dist-lib/index.cjs +257 -121
  70. package/dist-lib/jump-to-source-babel.cjs +1 -1
  71. package/dist-lib/jump-to-source-native.cjs +1 -1
  72. package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
  73. package/dist-lib/menu.cjs +11 -1
  74. package/dist-lib/menu.mjs +11 -1
  75. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  76. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  77. package/dist-lib/metro-production-bundle.cjs +1 -1
  78. package/dist-lib/metro-production-bundle.mjs +1 -1
  79. package/dist-lib/metro.cjs +132 -9
  80. package/dist-lib/native-app-identity.cjs +278 -0
  81. package/dist-lib/native-app-identity.mjs +245 -0
  82. package/dist-lib/profiles.cjs +1 -1
  83. package/dist-lib/public-brand.cjs +1 -1
  84. package/dist-lib/react-native-host-modules.cjs +1 -1
  85. package/dist-lib/react-native-host-modules.mjs +1 -1
  86. package/dist-lib/render-mode.cjs +1 -1
  87. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  88. package/dist-lib/sdk.cjs +112 -87
  89. package/dist-lib/sdk.mjs +111 -87
  90. package/dist-lib/skills.cjs +1270 -709
  91. package/dist-lib/swift-compile.cjs +1 -1
  92. package/dist-lib/swift-compile.mjs +1 -1
  93. package/dist-lib/swift-package.cjs +1 -1
  94. package/dist-lib/swift-package.mjs +1 -1
  95. package/dist-lib/swift-submit.cjs +1 -1
  96. package/dist-lib/swift-submit.mjs +1 -1
  97. package/dist-lib/swift.cjs +672 -275
  98. package/dist-lib/vite-swift.cjs +1 -1
  99. package/dist-lib/vite.cjs +11 -28
  100. package/kotlin/README.md +32 -4
  101. package/kotlin/fixtures/counter/Counter.kt +26 -0
  102. package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
  103. package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
  104. package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
  105. package/kotlin/fork/LICENSE +178 -0
  106. package/kotlin/fork/NOTICE +25 -0
  107. package/kotlin/fork/README.md +59 -0
  108. package/kotlin/fork/build.sh +128 -0
  109. package/kotlin/fork/compose-worker-globals.patch +96 -0
  110. package/kotlin/fork/fork.json +33 -0
  111. package/kotlin/fork/publish.ts +77 -0
  112. package/kotlin/fork/skiko-worker-clock.patch +33 -0
  113. package/kotlin/toolchain.json +288 -0
  114. package/package.json +13 -5
  115. package/skills/contrast/SKILL.md +1 -0
  116. package/src/automatic-update-policy.ts +17 -0
  117. package/src/home-paths.ts +11 -9
  118. package/src/host/bridge-host.ts +3 -1
  119. package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
  120. package/src/menu.ts +11 -0
  121. package/src/metro-plugin.ts +18 -0
  122. package/src/native-app-identity.ts +376 -0
  123. package/src/native-firebase-config.ts +90 -0
  124. package/src/screenshots/frame-compose.ts +1 -1
  125. package/src/screenshots/registry.ts +1 -1
  126. package/src/screenshots/schema.ts +2 -2
  127. package/src/vite-plugin-one.ts +11 -28
  128. package/src/vite-plugin.ts +6 -1
@@ -0,0 +1,90 @@
1
+ // the native installer reads Expo's googleServicesFile before Firebase starts.
2
+ // expose only FirebaseOptions, never a partner-specific extra configuration.
3
+ import fs from 'node:fs'
4
+ import { createRequire } from 'node:module'
5
+ import path from 'node:path'
6
+ import { isRecord } from './is-record'
7
+ import { parsePlistSource } from './plist'
8
+
9
+ export function readNativeFirebaseConfig(projectRoot: string) {
10
+ const result: Record<string, unknown> = {}
11
+ if (
12
+ ![
13
+ 'app.json',
14
+ 'app.config.js',
15
+ 'app.config.ts',
16
+ 'app.config.cjs',
17
+ 'app.config.mjs',
18
+ ].some((name) => fs.existsSync(path.join(projectRoot, name)))
19
+ )
20
+ return result
21
+ const require = createRequire(path.join(projectRoot, 'package.json'))
22
+ const configModule: unknown = require('@expo/config')
23
+ if (!isRecord(configModule) || typeof configModule.getConfig !== 'function') {
24
+ throw new Error('Expo native configuration is unavailable.')
25
+ }
26
+ const resolved: unknown = Reflect.apply(configModule.getConfig, configModule, [
27
+ projectRoot,
28
+ { skipSDKVersionRequirement: true },
29
+ ])
30
+ const config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {}
31
+ for (const platform of ['ios', 'android']) {
32
+ const native = config[platform]
33
+ if (!isRecord(native) || typeof native.googleServicesFile !== 'string') continue
34
+ try {
35
+ const source = fs.readFileSync(
36
+ path.resolve(projectRoot, native.googleServicesFile),
37
+ 'utf8',
38
+ )
39
+ const parsed: unknown =
40
+ platform === 'ios' ? parsePlistSource(source) : JSON.parse(source)
41
+ if (!isRecord(parsed)) throw new Error('Invalid Google services file.')
42
+ if (platform === 'ios') {
43
+ result[platform] = {
44
+ apiKey: parsed.API_KEY,
45
+ appId: parsed.GOOGLE_APP_ID,
46
+ projectId: parsed.PROJECT_ID,
47
+ databaseURL: parsed.DATABASE_URL,
48
+ gaTrackingId: parsed.TRACKING_ID,
49
+ storageBucket: parsed.STORAGE_BUCKET,
50
+ messagingSenderId: parsed.GCM_SENDER_ID,
51
+ clientId: parsed.CLIENT_ID,
52
+ androidClientID: parsed.ANDROID_CLIENT_ID,
53
+ deepLinkUrlScheme: parsed.REVERSED_CLIENT_ID,
54
+ }
55
+ } else {
56
+ const project = isRecord(parsed.project_info) ? parsed.project_info : {}
57
+ const clients: unknown[] = Array.isArray(parsed.client) ? parsed.client : []
58
+ const client = clients.find((value) => {
59
+ if (!isRecord(value) || !isRecord(value.client_info)) return false
60
+ const android = value.client_info.android_client_info
61
+ return isRecord(android) && android.package_name === native.package
62
+ })
63
+ if (!isRecord(client) || !isRecord(client.client_info))
64
+ throw new Error('No Google services client matches the Android package.')
65
+ const apiKeys: unknown[] = Array.isArray(client.api_key) ? client.api_key : []
66
+ const apiKey = apiKeys.find(
67
+ (value) => isRecord(value) && typeof value.current_key === 'string',
68
+ )
69
+ const oauthClients: unknown[] = Array.isArray(client.oauth_client)
70
+ ? client.oauth_client
71
+ : []
72
+ const oauth = oauthClients.find(
73
+ (value) => isRecord(value) && value.client_type === 3,
74
+ )
75
+ result[platform] = {
76
+ apiKey: isRecord(apiKey) ? apiKey.current_key : undefined,
77
+ appId: client.client_info.mobilesdk_app_id,
78
+ projectId: project.project_id,
79
+ databaseURL: project.firebase_url,
80
+ storageBucket: project.storage_bucket,
81
+ messagingSenderId: project.project_number,
82
+ clientId: isRecord(oauth) ? oauth.client_id : undefined,
83
+ }
84
+ }
85
+ } catch (error) {
86
+ result[platform] = { error: error instanceof Error ? error.message : String(error) }
87
+ }
88
+ }
89
+ return result
90
+ }
@@ -19,7 +19,7 @@ import {
19
19
  resolveDeviceFrameGeometry,
20
20
  type CornerRadii,
21
21
  type DeviceModel,
22
- } from 'peach-engine/settings'
22
+ } from 'peach-engine/settings/devices'
23
23
  import { launchReapedChrome } from '../../../../scripts/lib/reap-browser'
24
24
 
25
25
  const METALLIC_RING_SHADOW =
@@ -6,7 +6,7 @@
6
6
  // this module re-exports those tokens plus the composer-specific
7
7
  // `FrameComposeSpec` shape.
8
8
 
9
- import type { DeviceModel } from 'peach-engine/settings'
9
+ import type { DeviceModel } from 'peach-engine/settings/devices'
10
10
 
11
11
  export {
12
12
  BACKGROUND_PRESETS,
@@ -1,7 +1,8 @@
1
1
  import { readFileSync } from 'fs'
2
2
  import path from 'path'
3
- import { devices, type DeviceModel } from 'peach-engine/settings'
3
+ import { devices, type DeviceModel } from 'peach-engine/settings/devices'
4
4
  import yaml from 'yaml'
5
+ import { isRecord } from '../is-record'
5
6
  import {
6
7
  cloneBackgroundSpec,
7
8
  DEFAULT_FRAME_SHADOW,
@@ -16,7 +17,6 @@ import {
16
17
  type PosePresetName,
17
18
  type TextPresetName,
18
19
  } from './registry'
19
- import { isRecord } from '../is-record'
20
20
 
21
21
  export type CaptureMode = 'raw' | 'framed' | 'raw+framed'
22
22
  export type CapturePathMode = 'auto' | 'plan' | 'flow'
@@ -41,8 +41,8 @@ const loadSwiftHost = () => (swiftHost ??= import('peachsim/vite-swift'))
41
41
  // the Kotlin host (toolchain fetch, compile, artifact serving) loads the same
42
42
  // way, on the first /__peach/kotlin request from an Android device
43
43
  const KOTLIN_ROUTE_PREFIX = '/__peach/kotlin'
44
- let kotlinHost: Promise<typeof import('peachsim/vite-kotlin')> | undefined
45
- const loadKotlinHost = () => (kotlinHost ??= import('peachsim/vite-kotlin'))
44
+ let kotlinHost: Promise<typeof import('peachsim/kotlin-host')> | undefined
45
+ const loadKotlinHost = () => (kotlinHost ??= import('peachsim/kotlin-host'))
46
46
 
47
47
  export function rnxPlugin(options: PeachPluginOptions = {}): Plugin {
48
48
  const prefix = options.prefix || '/__soot'
@@ -140,34 +140,17 @@ export function rnxPlugin(options: PeachPluginOptions = {}): Plugin {
140
140
  if (!pathname.startsWith(KOTLIN_ROUTE_PREFIX)) return next()
141
141
  loadKotlinHost()
142
142
  .then(async (host) => {
143
- if (host.serveKotlinArtifact(pathname, res)) return
144
- if (pathname !== '/__peach/kotlin-package') return next()
145
143
  if (!kotlinModuleRoot) {
146
- const moduleRoot = path.join(
147
- path.dirname(
148
- createRequire(path.join(server.config.root, 'package.json')).resolve(
149
- 'peachsim/package.json',
150
- ),
151
- ),
152
- 'kotlin',
153
- )
154
- kotlinModuleRoot = moduleRoot
155
- server.watcher.add(path.join(moduleRoot, 'Sources'))
156
- }
157
- try {
158
- const artifact = await host.kotlinArtifact(
159
- server.config.root,
160
- kotlinModuleRoot,
161
- devOrigin(),
162
- )
163
- res.setHeader('access-control-allow-origin', '*')
164
- res.setHeader('content-type', 'application/json')
165
- res.end(JSON.stringify({ ...artifact, hmrPath }))
166
- } catch (error) {
167
- res.statusCode = 500
168
- res.setHeader('access-control-allow-origin', '*')
169
- res.end(error instanceof Error ? error.message : String(error))
144
+ kotlinModuleRoot = host.peachKotlinModuleRoot(server.config.root)
145
+ server.watcher.add(path.join(kotlinModuleRoot, 'Sources'))
170
146
  }
147
+ const served = await host.serveKotlinRequest(pathname, res, {
148
+ root: server.config.root,
149
+ moduleRoot: kotlinModuleRoot,
150
+ origin: devOrigin(),
151
+ hmrPath,
152
+ })
153
+ if (!served) next()
171
154
  })
172
155
  .catch(next)
173
156
  })
@@ -1682,6 +1682,7 @@ export function workletsBabelTransform(
1682
1682
  // scripts/build/bundler-deps.ts so esbuild-based dep prebundles stay in sync.
1683
1683
  let flowBabel: typeof import('@babel/core') | null = null
1684
1684
  let flowStripPlugin: import('@babel/core').PluginItem | null = null
1685
+ let hermesParserPlugin: import('@babel/core').PluginItem | null = null
1685
1686
  let jsxSyntaxPlugin: import('@babel/core').PluginItem | null = null
1686
1687
  function loadFlowBabel(): void {
1687
1688
  if (flowBabel) return
@@ -1689,6 +1690,10 @@ function loadFlowBabel(): void {
1689
1690
  flowStripPlugin = sootsimPluginRequire(
1690
1691
  '@babel/plugin-transform-flow-strip-types',
1691
1692
  ) as import('@babel/core').PluginItem
1693
+ // react native uses Hermes to parse current Flow syntax, including `as` casts.
1694
+ hermesParserPlugin = sootsimPluginRequire(
1695
+ 'babel-plugin-syntax-hermes-parser',
1696
+ ) as import('@babel/core').PluginItem
1692
1697
  jsxSyntaxPlugin = sootsimPluginRequire(
1693
1698
  '@babel/plugin-syntax-jsx',
1694
1699
  ) as import('@babel/core').PluginItem
@@ -1708,7 +1713,7 @@ function flowStripTransform(): Plugin {
1708
1713
  filename: id,
1709
1714
  babelrc: false,
1710
1715
  configFile: false,
1711
- plugins: [flowStripPlugin!, jsxSyntaxPlugin!],
1716
+ plugins: [hermesParserPlugin!, flowStripPlugin!, jsxSyntaxPlugin!],
1712
1717
  sourceMaps: true,
1713
1718
  compact: false,
1714
1719
  })