peachsim 0.1.1635 → 0.1.1641

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 (142) hide show
  1. package/README.md +10 -1
  2. package/cli/app-config.ts +14 -5
  3. package/cli/app-stubs.ts +96 -22
  4. package/cli/bridge-flow-runner.ts +2 -2
  5. package/cli/cloud-client.ts +60 -40
  6. package/cli/cloud-session.ts +16 -0
  7. package/cli/commands/assert.ts +17 -4
  8. package/cli/commands/box.ts +33 -19
  9. package/cli/commands/doctor.ts +37 -20
  10. package/cli/commands/flow.ts +1 -1
  11. package/cli/commands/inspect/actions.ts +3 -2
  12. package/cli/commands/inspect/core.ts +0 -8
  13. package/cli/commands/inspect/shared.ts +9 -4
  14. package/cli/commands/inspect.ts +65 -61
  15. package/cli/commands/platform.ts +2 -1
  16. package/cli/commands/preview.ts +1 -1
  17. package/cli/commands/record.ts +154 -68
  18. package/cli/commands/swift.ts +18 -4
  19. package/cli/commands/three-mode.ts +4 -38
  20. package/cli/commands/upload.ts +55 -49
  21. package/cli/drivers/playwright-sim-host.ts +65 -42
  22. package/cli/flow-live-status.ts +0 -2
  23. package/cli/main.ts +2 -2
  24. package/cli/outbound-endpoints.ts +7 -5
  25. package/cli/pause-aware-timeout.ts +4 -0
  26. package/cli/ws-bridge.ts +19 -16
  27. package/detox/attempt-events.cjs +99 -6
  28. package/detox/attempt-events.d.cts +7 -0
  29. package/detox/expectations.ts +7 -3
  30. package/detox/index.ts +259 -139
  31. package/detox/jest-environment.cjs +5 -1
  32. package/detox/motion-change.cjs +170 -21
  33. package/detox/motion-change.d.cts +32 -0
  34. package/detox/navigation-lifecycle.ts +35 -3
  35. package/dist-lib/agent-daemon-client.cjs +1 -1
  36. package/dist-lib/agent-events.cjs +1 -1
  37. package/dist-lib/attached-projects.cjs +1 -1
  38. package/dist-lib/auth/shared-session.cjs +1 -1
  39. package/dist-lib/backend-origin.cjs +17 -7
  40. package/dist-lib/beta.cjs +1 -1
  41. package/dist-lib/beta.mjs +1 -1
  42. package/dist-lib/bridge-constants.cjs +1 -1
  43. package/dist-lib/bridge-contract-input.cjs +1 -1
  44. package/dist-lib/bridge-contract-input.mjs +1 -1
  45. package/dist-lib/bridge-contract.cjs +1 -1
  46. package/dist-lib/bridge-contract.mjs +1 -1
  47. package/dist-lib/bundle-channel.cjs +5014 -2268
  48. package/dist-lib/capture-contract.cjs +1 -1
  49. package/dist-lib/capture-contract.mjs +1 -1
  50. package/dist-lib/cloud-contract.cjs +1 -1
  51. package/dist-lib/cloud-contract.mjs +1 -1
  52. package/dist-lib/cloud-test-args.cjs +1 -1
  53. package/dist-lib/cloud-test-args.mjs +1 -1
  54. package/dist-lib/cloud.cjs +1 -1
  55. package/dist-lib/cloud.mjs +1 -1
  56. package/dist-lib/config.cjs +1 -1
  57. package/dist-lib/config.mjs +1 -1
  58. package/dist-lib/detox/index.cjs +1036 -166
  59. package/dist-lib/detox/jest-environment.cjs +5 -1
  60. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  61. package/dist-lib/expo-swift-bundle.cjs +4613 -1963
  62. package/dist-lib/expo-swift-metadata.cjs +9 -7
  63. package/dist-lib/expo-swift-metadata.mjs +9 -7
  64. package/dist-lib/home-paths.cjs +1 -1
  65. package/dist-lib/host/bridge-host.cjs +58072 -16400
  66. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  67. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  68. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  69. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  70. package/dist-lib/host/websocket-proxy.cjs +1 -1
  71. package/dist-lib/index.cjs +2790 -143
  72. package/dist-lib/jump-to-source-babel.cjs +1 -1
  73. package/dist-lib/jump-to-source-native.cjs +1 -1
  74. package/dist-lib/kotlin-host.cjs +1 -1
  75. package/dist-lib/menu.cjs +1 -1
  76. package/dist-lib/menu.mjs +1 -1
  77. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  78. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  79. package/dist-lib/metro-production-bundle.cjs +1 -1
  80. package/dist-lib/metro-production-bundle.mjs +1 -1
  81. package/dist-lib/metro.cjs +2579 -95
  82. package/dist-lib/native-app-identity-project.cjs +243 -53
  83. package/dist-lib/native-app-identity-project.mjs +243 -53
  84. package/dist-lib/native-app-identity.cjs +29 -30
  85. package/dist-lib/native-app-identity.mjs +29 -30
  86. package/dist-lib/native-firebase-metadata.cjs +1 -1
  87. package/dist-lib/native-firebase-metadata.mjs +1 -1
  88. package/dist-lib/plist.cjs +1 -1
  89. package/dist-lib/plist.mjs +1 -1
  90. package/dist-lib/profiles.cjs +1 -1
  91. package/dist-lib/public-brand.cjs +1 -1
  92. package/dist-lib/react-native-host-modules.cjs +2 -2
  93. package/dist-lib/react-native-host-modules.mjs +2 -2
  94. package/dist-lib/scripts/dev-server-scanner.cjs +8 -6
  95. package/dist-lib/sdk.cjs +4 -3
  96. package/dist-lib/sdk.mjs +4 -3
  97. package/dist-lib/skills.cjs +66475 -23097
  98. package/dist-lib/swift-compile.cjs +452 -260
  99. package/dist-lib/swift-compile.mjs +451 -252
  100. package/dist-lib/swift-package.cjs +1 -1
  101. package/dist-lib/swift-package.mjs +1 -1
  102. package/dist-lib/swift-submit.cjs +14 -7
  103. package/dist-lib/swift-submit.mjs +14 -7
  104. package/dist-lib/swift-toolchain.cjs +316 -41
  105. package/dist-lib/swift.cjs +1 -1
  106. package/dist-lib/vite-swift.cjs +8188 -5636
  107. package/dist-lib/vite.cjs +2857 -12
  108. package/dist-lib/worklet-executable.cjs +14 -2
  109. package/dist-lib/worklet-executable.mjs +14 -2
  110. package/package.json +1 -1
  111. package/src/backend-origin.ts +21 -6
  112. package/src/expo-swift-host.ts +5 -2
  113. package/src/expoKotlinContract.ts +4 -7
  114. package/src/expoSwiftContract.ts +4 -6
  115. package/src/host/staged-host-files.ts +9 -0
  116. package/src/native-app-identity-project.ts +1 -4
  117. package/src/native-app-identity.ts +1 -4
  118. package/src/nativeAppIconContract.ts +1 -4
  119. package/src/output-lock-stdio.ts +36 -0
  120. package/src/react-native-bridge-modules.ts +106 -78
  121. package/src/react-native-host-modules.ts +4 -1
  122. package/src/settings-bundle.ts +1 -4
  123. package/src/swift-compile.ts +224 -139
  124. package/src/swift-distribution.lock.json +23 -12
  125. package/src/swift-distribution.ts +103 -4
  126. package/src/swift-host.ts +95 -30
  127. package/src/swift-icu.ts +16 -10
  128. package/src/swift-objc-compile.ts +547 -0
  129. package/src/swift-objc-metadata.ts +204 -0
  130. package/src/swift-objc-sdk.ts +883 -19
  131. package/src/swift-objc-standin.ts +126 -14
  132. package/src/swift-package-manifest.ts +42 -1
  133. package/src/swift-packages.ts +35 -21
  134. package/src/swift-root-lock.ts +153 -0
  135. package/src/swift-standin-emit.ts +40 -7
  136. package/src/swift-standins.ts +404 -138
  137. package/src/swift-submit.ts +18 -7
  138. package/src/swift-toolchain.ts +378 -46
  139. package/src/swiftContract.ts +12 -0
  140. package/src/worker-system-chunks.ts +11 -12
  141. package/src/worklet-executable.ts +19 -1
  142. package/src/xcode-project.ts +280 -33
@@ -43,6 +43,15 @@ function proofBoundPath(root, relative) {
43
43
  return resolved
44
44
  }
45
45
 
46
+ // lifecycle receipts bind every clock and census read to the retained bytes.
47
+ function boundText(root, relative, sha256, label) {
48
+ const bytes = fs.readFileSync(proofBoundPath(root, relative))
49
+ if (proofByteHash(bytes) !== sha256)
50
+ throw new Error(`${label} does not match its recorded hash`)
51
+ return bytes.toString('utf8')
52
+ }
53
+ module.exports.boundText = boundText
54
+
46
55
  function authenticateDiscreteFrameAsset(root, declaration, calibrate = false) {
47
56
  const cadence = parseDiscreteFrameCadence(declaration)
48
57
  const fixture = fs.readFileSync(proofBoundPath(root, cadence.asset.fixturePath))
@@ -309,6 +318,10 @@ function writeDiscreteFrameReceipt(
309
318
  }
310
319
 
311
320
  function authenticateNativeCadenceCensus(root, sourceRoot, life, decoded) {
321
+ const {
322
+ authenticateNativeRefreshSamples,
323
+ } = require('../../peach-conformance/e2e/utils/native-frame-receipt.cjs')
324
+ authenticateNativeRefreshSamples(root, sourceRoot, life)
312
325
  const native = life.nativeFramebuffer
313
326
  if (
314
327
  !native ||
@@ -322,28 +335,71 @@ function authenticateNativeCadenceCensus(root, sourceRoot, life, decoded) {
322
335
  )
323
336
  )
324
337
  throw new Error('native cadence has no source-matched framebuffer consumer')
325
- const frames = fs
326
- .readFileSync(proofBoundPath(root, native.receipt), 'utf8')
338
+ const frames = boundText(
339
+ root,
340
+ native.receipt,
341
+ native.receiptSha256,
342
+ 'native cadence source receipt',
343
+ )
327
344
  .trim()
328
345
  .split('\n')
329
346
  .map(JSON.parse)
330
- const media = fs
331
- .readFileSync(proofBoundPath(root, native.mediaFrames), 'utf8')
347
+ const media = boundText(
348
+ root,
349
+ native.mediaFrames,
350
+ native.mediaFramesSha256,
351
+ 'native cadence sampled surface census',
352
+ )
332
353
  .trim()
333
354
  .split('\n')
334
355
  .map(JSON.parse)
335
356
  if (frames.length !== decoded.observations.length || media.length !== frames.length)
336
- throw new Error('native cadence acquisition and presentation census differ')
357
+ throw new Error('native cadence acquisition and sampled surface census differ')
337
358
  const {
338
359
  decodeNativeFramebuffer,
339
360
  requireNativeRawFrame,
340
361
  } = require('../../peach-conformance/e2e/utils/native-frame-receipt.cjs')
341
362
  const rawRoot = path.dirname(proofBoundPath(root, native.receipt))
363
+ // a callback whose frame a newer one overwrote mid-read keeps no bytes; its
364
+ // superseded receipt fills exactly the gap it leaves in the callback order
365
+ const superseded = new Set(
366
+ boundText(
367
+ root,
368
+ native.superseded,
369
+ native.supersededSha256,
370
+ 'native cadence superseded receipt',
371
+ )
372
+ .split('\n')
373
+ .filter(Boolean)
374
+ .map((line) => {
375
+ const row = JSON.parse(line)
376
+ if (
377
+ !Number.isSafeInteger(row.callbackIndex) ||
378
+ row.seedBeforeRead === row.seedAfterRead
379
+ )
380
+ throw new Error('native superseded receipt is not an overwritten read')
381
+ return row.callbackIndex
382
+ }),
383
+ )
384
+ const reads = boundText(
385
+ root,
386
+ native.reads,
387
+ native.readsSha256,
388
+ 'native cadence observations',
389
+ )
390
+ .split('\n')
391
+ .filter(Boolean)
392
+ .map(JSON.parse)
393
+ let expectedCallback = 0
394
+ for (const read of reads) {
395
+ while (superseded.delete(expectedCallback)) expectedCallback++
396
+ if (read.callbackIndex !== expectedCallback++)
397
+ throw new Error('native cadence observations have invalid callback order')
398
+ }
342
399
  const origin = frames[0].consumerArrival
343
400
  for (const [index, frame] of frames.entries()) {
344
401
  const clock = frame.consumerArrival
345
402
  if (
346
- frame.callbackIndex !== index ||
347
403
  media[index].sourceFrameIndex !== index ||
348
404
  !clock ||
349
405
  clock.domain !== 'host-mach-absolute-time' ||
@@ -374,6 +430,9 @@ function authenticateNativeCadenceCensus(root, sourceRoot, life, decoded) {
374
430
  ),
375
431
  )
376
432
  }
433
+ while (superseded.delete(expectedCallback)) expectedCallback++
434
+ if (superseded.size)
435
+ throw new Error('native superseded receipts fall outside the callback order')
377
436
  }
378
437
 
379
438
  function readDiscreteFrameReceipt(root, sourceRoot, reference, expected) {
@@ -710,10 +769,44 @@ function discreteFrameEvidenceFiles(root, evidence) {
710
769
  const life = JSON.parse(
711
770
  fs.readFileSync(proofBoundPath(root, receipt.lifecycle.path), 'utf8'),
712
771
  )
772
+ // the app's ui frame clock and delivered input are replayed from their
773
+ // own receipts, so their bytes travel bound to the hashes the lifecycle
774
+ // recorded
775
+ for (const [label, auxiliary] of [
776
+ ['ui frame clock', life.uiFrameClock],
777
+ ['delivered input', life.deliveredUIKitInput],
778
+ ]) {
779
+ if (!auxiliary) continue
780
+ const bytes = fs.readFileSync(proofBoundPath(root, auxiliary.sourceReceipt))
781
+ if (proofByteHash(bytes) !== auxiliary.sourceReceiptSha256)
782
+ throw new Error(`native ${label} receipt does not match its recorded hash`)
783
+ paths.add(auxiliary.sourceReceipt)
784
+ }
713
785
  const native = life.nativeFramebuffer
714
786
  if (native) {
715
787
  paths.add(native.receipt)
788
+ paths.add(native.superseded)
716
789
  paths.add(native.mediaFrames)
790
+ paths.add(native.gradingMarkers)
791
+ paths.add(native.gradingPlan)
792
+ paths.add(native.windowResolution)
793
+ paths.add(native.reads)
794
+ for (const receipt of native.finalReads) {
795
+ const text = boundText(
796
+ root,
797
+ receipt.path,
798
+ receipt.sha256,
799
+ 'native sampled end state',
800
+ )
801
+ paths.add(receipt.path)
802
+ for (const row of text.split('\n').filter(Boolean).map(JSON.parse)) {
803
+ const file = proofBoundPath(
804
+ path.dirname(proofBoundPath(root, receipt.path)),
805
+ row.rawPath,
806
+ )
807
+ paths.add(path.relative(root, file).split(path.sep).join('/'))
808
+ }
809
+ }
717
810
  const rows = fs
718
811
  .readFileSync(proofBoundPath(root, native.receipt), 'utf8')
719
812
  .trim()
@@ -104,3 +104,10 @@ export function writeDiscreteFrameReceipt(
104
104
  context: DiscreteProofContext,
105
105
  trace: DiscreteFrameTrace,
106
106
  ): DiscreteProofReference
107
+
108
+ export function boundText(
109
+ root: string,
110
+ relative: string,
111
+ sha256: string,
112
+ label: string,
113
+ ): string
@@ -54,8 +54,12 @@ export function isNodeVisible(node: SootSimNodeInfo | null | undefined): boolean
54
54
  }
55
55
 
56
56
  // a native host is focused when its editor child holds focus.
57
- export function focusIsWithin(focused: SootSimFocusedNodeInfo, nodeId: number): boolean {
58
- return focused.nodeId === nodeId || focused.ancestorNodeIds.includes(nodeId)
57
+ export function focusIsWithin(
58
+ focused: SootSimFocusedNodeInfo,
59
+ node: SootSimNodeInfo,
60
+ ): boolean {
61
+ const nativeNodeId = node.nativeTag ?? node.nodeId
62
+ return focused.nodeId === nativeNodeId || focused.ancestorNodeIds.includes(nativeNodeId)
59
63
  }
60
64
 
61
65
  // the engine owns focus for canvas inputs and hosted native editors.
@@ -64,7 +68,7 @@ export async function isTextInputNodeFocused(
64
68
  page: Page,
65
69
  ): Promise<boolean> {
66
70
  const focused = await page.evaluate(async () => window.__sootsimTest!.getFocusedNode())
67
- return focused !== null && focusIsWithin(focused, node.nodeId)
71
+ return focused !== null && focusIsWithin(focused, node)
68
72
  }
69
73
 
70
74
  async function isNodeFocused(node: SootSimNodeInfo, page: Page): Promise<boolean> {