peachsim 0.1.1635 → 0.1.1640
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.
- package/README.md +5 -1
- package/cli/app-config.ts +14 -5
- package/cli/app-stubs.ts +62 -13
- package/cli/bridge-flow-runner.ts +2 -2
- package/cli/cloud-client.ts +60 -40
- package/cli/commands/doctor.ts +13 -5
- package/cli/commands/flow.ts +1 -1
- package/cli/commands/inspect/shared.ts +9 -4
- package/cli/commands/inspect.ts +65 -47
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/record.ts +97 -47
- package/cli/commands/swift.ts +9 -3
- package/cli/commands/upload.ts +48 -42
- package/cli/drivers/playwright-sim-host.ts +65 -42
- package/cli/main.ts +1 -1
- package/cli/outbound-endpoints.ts +7 -5
- package/cli/pause-aware-timeout.ts +4 -0
- package/cli/ws-bridge.ts +19 -10
- package/detox/attempt-events.cjs +62 -5
- package/detox/attempt-events.d.cts +7 -0
- package/detox/expectations.ts +7 -3
- package/detox/index.ts +121 -47
- package/detox/motion-change.cjs +170 -21
- package/detox/motion-change.d.cts +32 -0
- package/detox/navigation-lifecycle.ts +35 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +8 -7
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +4038 -1983
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +509 -86
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +3551 -1574
- package/dist-lib/expo-swift-metadata.cjs +9 -7
- package/dist-lib/expo-swift-metadata.mjs +9 -7
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +43633 -2635
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2748 -128
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +2547 -83
- package/dist-lib/native-app-identity-project.cjs +237 -50
- package/dist-lib/native-app-identity-project.mjs +237 -50
- package/dist-lib/native-app-identity.cjs +29 -30
- package/dist-lib/native-app-identity.mjs +29 -30
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +2 -2
- package/dist-lib/react-native-host-modules.mjs +2 -2
- package/dist-lib/scripts/dev-server-scanner.cjs +8 -6
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +65403 -22739
- package/dist-lib/swift-compile.cjs +93 -32
- package/dist-lib/swift-compile.mjs +93 -32
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +7 -5
- package/dist-lib/swift-submit.mjs +7 -5
- package/dist-lib/swift-toolchain.cjs +316 -41
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +7335 -5432
- package/dist-lib/vite.cjs +2857 -12
- package/dist-lib/worklet-executable.cjs +14 -2
- package/dist-lib/worklet-executable.mjs +14 -2
- package/package.json +1 -1
- package/src/backend-origin.ts +13 -6
- package/src/expo-swift-host.ts +5 -2
- package/src/expoKotlinContract.ts +4 -7
- package/src/expoSwiftContract.ts +4 -6
- package/src/host/staged-host-files.ts +9 -0
- package/src/native-app-identity-project.ts +1 -4
- package/src/native-app-identity.ts +1 -4
- package/src/nativeAppIconContract.ts +1 -4
- package/src/output-lock-stdio.ts +36 -0
- package/src/react-native-bridge-modules.ts +21 -6
- package/src/react-native-host-modules.ts +4 -1
- package/src/settings-bundle.ts +1 -4
- package/src/swift-compile.ts +91 -33
- package/src/swift-distribution.lock.json +22 -12
- package/src/swift-distribution.ts +103 -4
- package/src/swift-host.ts +89 -26
- package/src/swift-icu.ts +16 -10
- package/src/swift-objc-compile.ts +355 -0
- package/src/swift-objc-sdk.ts +689 -18
- package/src/swift-objc-standin.ts +126 -14
- package/src/swift-package-manifest.ts +39 -1
- package/src/swift-packages.ts +35 -21
- package/src/swift-standin-emit.ts +40 -7
- package/src/swift-standins.ts +404 -138
- package/src/swift-submit.ts +3 -5
- package/src/swift-toolchain.ts +378 -46
- package/src/worker-system-chunks.ts +11 -12
- package/src/worklet-executable.ts +19 -1
- package/src/xcode-project.ts +270 -30
package/dist-lib/detox/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! peach v0.1.
|
|
1
|
+
/*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1147,6 +1147,32 @@ var require_lib = __commonJS({
|
|
|
1147
1147
|
}
|
|
1148
1148
|
});
|
|
1149
1149
|
|
|
1150
|
+
// ../peach-engine/src/platform/adapter.ts
|
|
1151
|
+
var IOS_ADAPTER, ANDROID_ADAPTER, RUNTIME_PLATFORM_ADAPTERS;
|
|
1152
|
+
var init_adapter = __esm({
|
|
1153
|
+
"../peach-engine/src/platform/adapter.ts"() {
|
|
1154
|
+
"use strict";
|
|
1155
|
+
IOS_ADAPTER = Object.freeze({
|
|
1156
|
+
id: "ios",
|
|
1157
|
+
displayName: "iOS",
|
|
1158
|
+
isIOS: true,
|
|
1159
|
+
isAndroid: false,
|
|
1160
|
+
select: (registry) => registry.ios
|
|
1161
|
+
});
|
|
1162
|
+
ANDROID_ADAPTER = Object.freeze({
|
|
1163
|
+
id: "android",
|
|
1164
|
+
displayName: "Android",
|
|
1165
|
+
isIOS: false,
|
|
1166
|
+
isAndroid: true,
|
|
1167
|
+
select: (registry) => registry.android
|
|
1168
|
+
});
|
|
1169
|
+
RUNTIME_PLATFORM_ADAPTERS = Object.freeze({
|
|
1170
|
+
ios: IOS_ADAPTER,
|
|
1171
|
+
android: ANDROID_ADAPTER
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1150
1176
|
// detox/motion-change.cjs
|
|
1151
1177
|
var require_motion_change = __commonJS({
|
|
1152
1178
|
"detox/motion-change.cjs"(exports2, module2) {
|
|
@@ -1220,29 +1246,48 @@ var require_motion_change = __commonJS({
|
|
|
1220
1246
|
var SETTLE_BLIP_MAXIMUM_CHANGE_PERCENT = 0.6;
|
|
1221
1247
|
var GESTURE_MOTION_MIN_TRANSITIONS = 120;
|
|
1222
1248
|
var GESTURE_TRAVEL_RATIO_RANGE = Object.freeze({ min: 0.8, max: 1.25 });
|
|
1249
|
+
var GESTURE_QUARTER_TRAVEL_RATIO_RANGE = Object.freeze({ min: 0.5, max: 2 });
|
|
1223
1250
|
function evaluateMotionTransitions(transitions, oracleTarget) {
|
|
1224
1251
|
const key = (transition) => `${transition.fromLabel}\0${transition.toLabel}`;
|
|
1225
1252
|
const oracle = transitions.filter((transition) => transition.target === oracleTarget);
|
|
1226
1253
|
const sootsim = transitions.filter((transition) => transition.target === "sootsim");
|
|
1227
|
-
const
|
|
1254
|
+
const paired = oracle.length === sootsim.length && new Set(oracle.map(key)).size === oracle.length && oracle.every((transition, index) => key(transition) === key(sootsim[index]));
|
|
1228
1255
|
const measured = transitions.every(
|
|
1229
1256
|
(transition) => transition.dimensionsMatch && transition.changePercent !== null && transition.changePixels !== null && transition.totalPixels !== null
|
|
1230
1257
|
);
|
|
1231
|
-
const moving = oracle.filter((transition) => transition.passedMinimum);
|
|
1232
1258
|
const travel = (list) => list.filter(
|
|
1233
1259
|
(transition) => transition.changePercent >= PAIRED_MOTION_MINIMUM_CHANGE_PERCENT
|
|
1234
1260
|
).reduce((total, transition) => total + transition.changePercent, 0);
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1261
|
+
const movesNear = (list, index) => [index - 1, index, index + 1].some((neighbour) => list[neighbour]?.passedMinimum === true);
|
|
1262
|
+
const pairedChange = (transition) => transition.changePercent >= PAIRED_MOTION_MINIMUM_CHANGE_PERCENT;
|
|
1263
|
+
const settleBlip = (list) => {
|
|
1264
|
+
const index = list.findLastIndex(pairedChange);
|
|
1265
|
+
return index >= 0 && list[index].changePercent < SETTLE_BLIP_MAXIMUM_CHANGE_PERCENT && !(list[index - 1]?.passedMinimum ?? true) ? index : -1;
|
|
1266
|
+
};
|
|
1267
|
+
const oracleBlip = settleBlip(oracle);
|
|
1268
|
+
const sootsimBlip = settleBlip(sootsim);
|
|
1269
|
+
const moving = oracle.filter(
|
|
1270
|
+
(transition, index) => pairedChange(transition) && index !== oracleBlip
|
|
1237
1271
|
);
|
|
1238
|
-
const isSettleBlip = (transition, index) => transition.changePercent < SETTLE_BLIP_MAXIMUM_CHANGE_PERCENT && !(oracle[index - 1]?.passedMinimum ?? true);
|
|
1239
1272
|
const within = (actual, expected, range) => actual >= expected * range.min && actual <= expected * range.max;
|
|
1240
|
-
const
|
|
1241
|
-
(
|
|
1273
|
+
const quarter = (list, index) => list.slice(
|
|
1274
|
+
Math.floor(list.length * index / 4),
|
|
1275
|
+
Math.floor(list.length * (index + 1) / 4)
|
|
1276
|
+
);
|
|
1277
|
+
const follows = oracle.length >= GESTURE_MOTION_MIN_TRANSITIONS ? within(travel(sootsim), travel(oracle), GESTURE_TRAVEL_RATIO_RANGE) && [0, 1, 2, 3].every(
|
|
1278
|
+
(index) => within(
|
|
1279
|
+
travel(quarter(sootsim, index)),
|
|
1280
|
+
travel(quarter(oracle, index)),
|
|
1281
|
+
GESTURE_QUARTER_TRAVEL_RATIO_RANGE
|
|
1282
|
+
)
|
|
1283
|
+
) : oracle.every(
|
|
1284
|
+
(transition, index) => !pairedChange(transition) || index === oracleBlip || movesNear(sootsim, index)
|
|
1285
|
+
) && sootsim.every(
|
|
1286
|
+
(transition, index) => !pairedChange(transition) || index === sootsimBlip || movesNear(oracle, index)
|
|
1242
1287
|
);
|
|
1243
1288
|
return {
|
|
1244
1289
|
moving: moving.length,
|
|
1245
|
-
passed: measured && oracle.length > 0 &&
|
|
1290
|
+
passed: measured && oracle.length > 0 && paired && moving.length > 0 && follows
|
|
1246
1291
|
};
|
|
1247
1292
|
}
|
|
1248
1293
|
var DISPLAY_LINK_INTERVAL_MS = 1e3 / 60;
|
|
@@ -1396,8 +1441,78 @@ var require_motion_change = __commonJS({
|
|
|
1396
1441
|
}
|
|
1397
1442
|
return { mode: "playing", anchorMs: anchor.atMs, holds };
|
|
1398
1443
|
}
|
|
1444
|
+
var PUBLICATION_DENSE_LADDER_MIN_STAGES = 10;
|
|
1445
|
+
var PUBLICATION_MIN_INTERMEDIATE_PASSES = 2;
|
|
1446
|
+
function motionCycleOnsets(event, eventPath) {
|
|
1447
|
+
if (!Array.isArray(event.anchors)) return [];
|
|
1448
|
+
const cycles = event.anchors.filter(
|
|
1449
|
+
(anchor) => typeof anchor === "object" && anchor !== null && anchor.cycle === true
|
|
1450
|
+
);
|
|
1451
|
+
if (cycles.length === 0) return [];
|
|
1452
|
+
const finite = (value, label) => {
|
|
1453
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
1454
|
+
throw new Error(`motion event cycle ${label} has no onset time: ${eventPath}`);
|
|
1455
|
+
return value;
|
|
1456
|
+
};
|
|
1457
|
+
const android = event.captureMode === "android-screenrecord-sequence";
|
|
1458
|
+
const peach = typeof event.driveStart === "object" && event.driveStart !== null;
|
|
1459
|
+
const basisMs = peach ? finite(event.driveStart.virtualTimestampMs, "transition") : android ? finite(event.triggerProducerSeconds, "transition") * 1e3 : finite(event.triggerInVideoSec, "transition") * 1e3;
|
|
1460
|
+
return [
|
|
1461
|
+
{ id: "transition", atMs: basisMs },
|
|
1462
|
+
...cycles.map((anchor) => {
|
|
1463
|
+
if (typeof anchor.id !== "string")
|
|
1464
|
+
throw new Error(`motion event cycle anchor has no id: ${eventPath}`);
|
|
1465
|
+
const atMs = peach ? finite(anchor.virtualTimestampMs, anchor.id) : android ? finite(anchor.producerSeconds, anchor.id) * 1e3 : finite(anchor.detection?.atSec, anchor.id) * 1e3;
|
|
1466
|
+
return { id: anchor.id, atMs };
|
|
1467
|
+
})
|
|
1468
|
+
];
|
|
1469
|
+
}
|
|
1470
|
+
var MOTION_CYCLE_PERIOD_TOLERANCE_MS = 1e3 / 60;
|
|
1471
|
+
function motionCyclePeriods(reference, sootsim) {
|
|
1472
|
+
const ids = (onsets) => onsets.map((onset) => onset.id).join(",");
|
|
1473
|
+
if (ids(reference) !== ids(sootsim))
|
|
1474
|
+
throw new Error(
|
|
1475
|
+
`motion cycle anchors differ between lanes: reference [${ids(reference)}], sootsim [${ids(sootsim)}]`
|
|
1476
|
+
);
|
|
1477
|
+
return reference.slice(1).map((onset, index) => {
|
|
1478
|
+
const referenceMs = onset.atMs - reference[index].atMs;
|
|
1479
|
+
const sootsimMs = sootsim[index + 1].atMs - sootsim[index].atMs;
|
|
1480
|
+
return {
|
|
1481
|
+
id: onset.id,
|
|
1482
|
+
passed: Math.abs(referenceMs - sootsimMs) <= MOTION_CYCLE_PERIOD_TOLERANCE_MS,
|
|
1483
|
+
referenceMs,
|
|
1484
|
+
sootsimMs
|
|
1485
|
+
};
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
function evaluateMotionPublication(stages, transitions, oracleTarget, cycleOnsets) {
|
|
1489
|
+
const cyclePeriods = motionCyclePeriods(cycleOnsets.reference, cycleOnsets.sootsim);
|
|
1490
|
+
const intermediates = stages.slice(1, -1);
|
|
1491
|
+
const intermediatePassed = intermediates.filter((stage) => stage.passedThreshold).length;
|
|
1492
|
+
const stagesByLabel = new Map(stages.map((stage) => [stage.label, stage]));
|
|
1493
|
+
const oracleMovingInto = new Set(
|
|
1494
|
+
transitions.filter(
|
|
1495
|
+
(transition) => transition.target === oracleTarget && (transition.changePercent >= PAIRED_MOTION_MINIMUM_CHANGE_PERCENT || transition.changePixels > 0 && stagesByLabel.get(transition.toLabel)?.oracleFromFirstPercent >= PAIRED_MOTION_MINIMUM_CHANGE_PERCENT && stagesByLabel.get(transition.toLabel)?.oracleFromLastPercent >= PAIRED_MOTION_MINIMUM_CHANGE_PERCENT)
|
|
1496
|
+
).map((transition) => transition.toLabel)
|
|
1497
|
+
);
|
|
1498
|
+
const movingPassed = intermediates.filter(
|
|
1499
|
+
(stage) => stage.passedThreshold && oracleMovingInto.has(stage.label)
|
|
1500
|
+
).length;
|
|
1501
|
+
const needsIntermediates = stages.length >= PUBLICATION_DENSE_LADDER_MIN_STAGES;
|
|
1502
|
+
const first = stages[0];
|
|
1503
|
+
const last = stages[stages.length - 1];
|
|
1504
|
+
return {
|
|
1505
|
+
passed: stages.length > 0 && first.passedThreshold && last.passedThreshold && (!needsIntermediates || movingPassed >= PUBLICATION_MIN_INTERMEDIATE_PASSES) && cyclePeriods.every((period) => period.passed) && evaluateMotionTransitions(transitions, oracleTarget).passed,
|
|
1506
|
+
cyclePeriods,
|
|
1507
|
+
intermediateCount: intermediates.length,
|
|
1508
|
+
intermediatePassed,
|
|
1509
|
+
movingPassed
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1399
1512
|
module2.exports = {
|
|
1400
1513
|
MOTION_CHANGE_DEFINITION: MOTION_CHANGE_DEFINITION2,
|
|
1514
|
+
evaluateMotionPublication,
|
|
1515
|
+
motionCycleOnsets,
|
|
1401
1516
|
measureMotionChange: measureMotionChange2,
|
|
1402
1517
|
measureProofMotionChange,
|
|
1403
1518
|
evaluateMotionTransitions,
|
|
@@ -1757,6 +1872,99 @@ var require_native_frame_receipt = __commonJS({
|
|
|
1757
1872
|
};
|
|
1758
1873
|
}
|
|
1759
1874
|
module2.exports.nativeUIKitInputReceipt = nativeUIKitInputReceipt;
|
|
1875
|
+
function nativeUIFrameClockReceipt(bytes) {
|
|
1876
|
+
if (!Buffer.isBuffer(bytes))
|
|
1877
|
+
throw new Error("ui frame clock receipt must preserve source bytes");
|
|
1878
|
+
const rows = bytes.toString("utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
1879
|
+
if (rows.at(-1)?.kind !== "stopped")
|
|
1880
|
+
throw new Error("ui frame clock receipt was not closed by its recorder");
|
|
1881
|
+
const ticks = [];
|
|
1882
|
+
const workletsTicks = [];
|
|
1883
|
+
for (const row of rows.slice(0, -1)) {
|
|
1884
|
+
if (row.kind === "worklets-frame") {
|
|
1885
|
+
if (!Number.isFinite(row.timestampSeconds) || row.timestampSeconds < 0)
|
|
1886
|
+
throw new Error("invalid worklets frame clock row");
|
|
1887
|
+
if (workletsTicks.length > 0 && row.timestampSeconds <= workletsTicks.at(-1).timestampSeconds)
|
|
1888
|
+
throw new Error("worklets frame clock timestamps must increase");
|
|
1889
|
+
workletsTicks.push({ timestampSeconds: row.timestampSeconds });
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
if (row.kind !== "ui-frame" || !Number.isFinite(row.targetTimestampSeconds) || !Number.isFinite(row.timestampSeconds) || !(row.durationSeconds > 0))
|
|
1893
|
+
throw new Error("invalid ui frame clock row");
|
|
1894
|
+
if (ticks.length > 0 && row.targetTimestampSeconds <= ticks.at(-1).targetTimestampSeconds)
|
|
1895
|
+
throw new Error("ui frame clock target timestamps must increase");
|
|
1896
|
+
ticks.push({
|
|
1897
|
+
targetTimestampSeconds: row.targetTimestampSeconds,
|
|
1898
|
+
timestampSeconds: row.timestampSeconds,
|
|
1899
|
+
durationSeconds: row.durationSeconds
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
if (ticks.length < 2)
|
|
1903
|
+
throw new Error("ui frame clock receipt holds fewer than two ticks");
|
|
1904
|
+
return {
|
|
1905
|
+
domain: "ca-media-time-seconds",
|
|
1906
|
+
source: "cadisplaylink-target-timestamp",
|
|
1907
|
+
sourceReceiptSha256: createHash("sha256").update(bytes).digest("hex"),
|
|
1908
|
+
ticks,
|
|
1909
|
+
workletsTicks
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
module2.exports.nativeUIFrameClockReceipt = nativeUIFrameClockReceipt;
|
|
1913
|
+
function pairedNativeWorkletFrameClock(root, lifecycle) {
|
|
1914
|
+
const { boundText } = require_attempt_events();
|
|
1915
|
+
if (!lifecycle || typeof lifecycle !== "object" || Array.isArray(lifecycle))
|
|
1916
|
+
throw new Error("paired worklets clock needs a retained native lifecycle");
|
|
1917
|
+
const receipt = lifecycle.uiFrameClock;
|
|
1918
|
+
if (!receipt)
|
|
1919
|
+
throw new Error("paired worklets clock needs a retained native UI clock receipt");
|
|
1920
|
+
const inputReceipt = lifecycle.deliveredUIKitInput;
|
|
1921
|
+
if (!inputReceipt)
|
|
1922
|
+
throw new Error("paired worklets clock needs a delivered UIKit touch-up witness");
|
|
1923
|
+
const clock = nativeUIFrameClockReceipt(
|
|
1924
|
+
Buffer.from(
|
|
1925
|
+
boundText(
|
|
1926
|
+
root,
|
|
1927
|
+
receipt.sourceReceipt,
|
|
1928
|
+
receipt.sourceReceiptSha256,
|
|
1929
|
+
"native UI clock receipt"
|
|
1930
|
+
)
|
|
1931
|
+
)
|
|
1932
|
+
);
|
|
1933
|
+
const input = nativeUIKitInputReceipt(
|
|
1934
|
+
Buffer.from(
|
|
1935
|
+
boundText(
|
|
1936
|
+
root,
|
|
1937
|
+
inputReceipt.sourceReceipt,
|
|
1938
|
+
inputReceipt.sourceReceiptSha256,
|
|
1939
|
+
"delivered UIKit input receipt"
|
|
1940
|
+
)
|
|
1941
|
+
)
|
|
1942
|
+
);
|
|
1943
|
+
const up = input.events.find((event) => event.phase === 3);
|
|
1944
|
+
if (input.status !== "witnessed" || !up)
|
|
1945
|
+
throw new Error("paired worklets clock needs a delivered UIKit touch-up witness");
|
|
1946
|
+
const startIndex = clock.ticks.findIndex(
|
|
1947
|
+
(tick2) => tick2.timestampSeconds > up.deliveredAtSeconds
|
|
1948
|
+
);
|
|
1949
|
+
if (startIndex < 1)
|
|
1950
|
+
throw new Error("native UI clock does not bracket delivered touch-up");
|
|
1951
|
+
const timestampsSeconds = clock.ticks.slice(startIndex - 1).map((tick2) => tick2.targetTimestampSeconds);
|
|
1952
|
+
return {
|
|
1953
|
+
provenance: {
|
|
1954
|
+
sourceReceipt: receipt.sourceReceipt,
|
|
1955
|
+
sourceReceiptSha256: receipt.sourceReceiptSha256,
|
|
1956
|
+
inputReceipt: inputReceipt.sourceReceipt,
|
|
1957
|
+
inputReceiptSha256: inputReceipt.sourceReceiptSha256,
|
|
1958
|
+
deliveredTouchUpSeconds: up.deliveredAtSeconds,
|
|
1959
|
+
startIndex,
|
|
1960
|
+
alignment: "inferred-next-ui-frame-after-delivered-touch-up",
|
|
1961
|
+
frameCount: timestampsSeconds.length - 1
|
|
1962
|
+
},
|
|
1963
|
+
// the trigger reads the previous frame; the first delivery reads startIndex.
|
|
1964
|
+
timestampsSeconds
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
module2.exports.pairedNativeWorkletFrameClock = pairedNativeWorkletFrameClock;
|
|
1760
1968
|
async function encodeNativeFramebufferMovie(rawDir, videoPath) {
|
|
1761
1969
|
const fs3 = require("node:fs");
|
|
1762
1970
|
const path5 = require("node:path");
|
|
@@ -1783,6 +1991,27 @@ var require_native_frame_receipt = __commonJS({
|
|
|
1783
1991
|
});
|
|
1784
1992
|
if (times.some((value, index) => index > 0 && value <= times[index - 1]))
|
|
1785
1993
|
throw new Error("nonmonotonic native source arrivals");
|
|
1994
|
+
const reads = rows.map((row) => ({
|
|
1995
|
+
callbackIndex: row.callbackIndex,
|
|
1996
|
+
seedBeforeRead: row.source?.seedBeforeRead,
|
|
1997
|
+
seedAfterRead: row.source?.seedAfterRead,
|
|
1998
|
+
arrival: BigInt(row.consumerArrival.machTicks)
|
|
1999
|
+
}));
|
|
2000
|
+
for (const [index, read] of reads.entries()) {
|
|
2001
|
+
if (!Number.isSafeInteger(read.seedBeforeRead) || !Number.isSafeInteger(read.seedAfterRead))
|
|
2002
|
+
throw new Error(`native callback ${read.callbackIndex} has no surface seed`);
|
|
2003
|
+
const previous = reads[index - 1];
|
|
2004
|
+
if (!previous) continue;
|
|
2005
|
+
const lost = read.seedBeforeRead - previous.seedAfterRead - 1;
|
|
2006
|
+
if (lost > 1) {
|
|
2007
|
+
const gapMs = Number(
|
|
2008
|
+
(read.arrival - previous.arrival) * BigInt(firstClock.timebaseNumer) / BigInt(firstClock.timebaseDenom)
|
|
2009
|
+
) / 1e6;
|
|
2010
|
+
throw new Error(
|
|
2011
|
+
`native recording skipped ${lost} surface updates between callbacks ${previous.callbackIndex} and ${read.callbackIndex} (surface seed ${previous.seedAfterRead} to ${read.seedBeforeRead}, ${gapMs.toFixed(1)}ms between arrivals): no captured frame shows them`
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
1786
2015
|
function selectTime(start, end) {
|
|
1787
2016
|
if (end - start === 1) return String(times[start]);
|
|
1788
2017
|
const middle = Math.floor((start + end) / 2);
|
|
@@ -1979,6 +2208,13 @@ var require_attempt_events = __commonJS({
|
|
|
1979
2208
|
throw new Error("cadence evidence path escapes its root");
|
|
1980
2209
|
return resolved;
|
|
1981
2210
|
}
|
|
2211
|
+
function boundText(root, relative, sha256, label) {
|
|
2212
|
+
const bytes = fs3.readFileSync(proofBoundPath(root, relative));
|
|
2213
|
+
if (proofByteHash(bytes) !== sha256)
|
|
2214
|
+
throw new Error(`${label} does not match its recorded hash`);
|
|
2215
|
+
return bytes.toString("utf8");
|
|
2216
|
+
}
|
|
2217
|
+
module2.exports.boundText = boundText;
|
|
1982
2218
|
function authenticateDiscreteFrameAsset(root, declaration, calibrate = false) {
|
|
1983
2219
|
const cadence = parseDiscreteFrameCadence(declaration);
|
|
1984
2220
|
const fixture = fs3.readFileSync(proofBoundPath(root, cadence.asset.fixturePath));
|
|
@@ -2186,8 +2422,18 @@ var require_attempt_events = __commonJS({
|
|
|
2186
2422
|
)
|
|
2187
2423
|
))
|
|
2188
2424
|
throw new Error("native cadence has no source-matched framebuffer consumer");
|
|
2189
|
-
const frames =
|
|
2190
|
-
|
|
2425
|
+
const frames = boundText(
|
|
2426
|
+
root,
|
|
2427
|
+
native.receipt,
|
|
2428
|
+
native.receiptSha256,
|
|
2429
|
+
"native cadence source receipt"
|
|
2430
|
+
).trim().split("\n").map(JSON.parse);
|
|
2431
|
+
const media = boundText(
|
|
2432
|
+
root,
|
|
2433
|
+
native.mediaFrames,
|
|
2434
|
+
native.mediaFramesSha256,
|
|
2435
|
+
"native cadence presentation census"
|
|
2436
|
+
).trim().split("\n").map(JSON.parse);
|
|
2191
2437
|
if (frames.length !== decoded.observations.length || media.length !== frames.length)
|
|
2192
2438
|
throw new Error("native cadence acquisition and presentation census differ");
|
|
2193
2439
|
const {
|
|
@@ -2195,10 +2441,25 @@ var require_attempt_events = __commonJS({
|
|
|
2195
2441
|
requireNativeRawFrame
|
|
2196
2442
|
} = require_native_frame_receipt();
|
|
2197
2443
|
const rawRoot = path5.dirname(proofBoundPath(root, native.receipt));
|
|
2444
|
+
const superseded = new Set(
|
|
2445
|
+
boundText(
|
|
2446
|
+
root,
|
|
2447
|
+
native.superseded,
|
|
2448
|
+
native.supersededSha256,
|
|
2449
|
+
"native cadence superseded receipt"
|
|
2450
|
+
).split("\n").filter(Boolean).map((line) => {
|
|
2451
|
+
const row = JSON.parse(line);
|
|
2452
|
+
if (!Number.isSafeInteger(row.callbackIndex) || row.seedBeforeRead === row.seedAfterRead)
|
|
2453
|
+
throw new Error("native superseded receipt is not an overwritten read");
|
|
2454
|
+
return row.callbackIndex;
|
|
2455
|
+
})
|
|
2456
|
+
);
|
|
2198
2457
|
const origin = frames[0].consumerArrival;
|
|
2458
|
+
let expectedCallback = 0;
|
|
2199
2459
|
for (const [index, frame] of frames.entries()) {
|
|
2460
|
+
while (superseded.delete(expectedCallback)) expectedCallback++;
|
|
2200
2461
|
const clock = frame.consumerArrival;
|
|
2201
|
-
if (frame.callbackIndex !==
|
|
2462
|
+
if (frame.callbackIndex !== expectedCallback++ || media[index].sourceFrameIndex !== index || !clock || clock.domain !== "host-mach-absolute-time" || clock.domain !== origin.domain || clock.timebaseNumer !== origin.timebaseNumer || clock.timebaseDenom !== origin.timebaseDenom || !Number.isSafeInteger(clock.timebaseNumer) || clock.timebaseNumer <= 0 || !Number.isSafeInteger(clock.timebaseDenom) || clock.timebaseDenom <= 0)
|
|
2202
2463
|
throw new Error("native cadence source census has invalid clock or order");
|
|
2203
2464
|
const pts = (BigInt(clock.machTicks) - BigInt(origin.machTicks)) * BigInt(clock.timebaseNumer) / BigInt(clock.timebaseDenom);
|
|
2204
2465
|
if (pts < 0n || pts !== BigInt(media[index].ptsNanoseconds) || Math.abs(Number(pts) / 1e6 - decoded.observations[index].atMs) > 1e-3)
|
|
@@ -2211,6 +2472,9 @@ var require_attempt_events = __commonJS({
|
|
|
2211
2472
|
)
|
|
2212
2473
|
);
|
|
2213
2474
|
}
|
|
2475
|
+
while (superseded.delete(expectedCallback)) expectedCallback++;
|
|
2476
|
+
if (superseded.size)
|
|
2477
|
+
throw new Error("native superseded receipts fall outside the callback order");
|
|
2214
2478
|
}
|
|
2215
2479
|
function readDiscreteFrameReceipt(root, sourceRoot, reference, expected) {
|
|
2216
2480
|
if (expected.calibration !== true) assertNormalProofAttempt(root);
|
|
@@ -2444,9 +2708,20 @@ var require_attempt_events = __commonJS({
|
|
|
2444
2708
|
const life = JSON.parse(
|
|
2445
2709
|
fs3.readFileSync(proofBoundPath(root, receipt.lifecycle.path), "utf8")
|
|
2446
2710
|
);
|
|
2711
|
+
for (const [label, auxiliary] of [
|
|
2712
|
+
["ui frame clock", life.uiFrameClock],
|
|
2713
|
+
["delivered input", life.deliveredUIKitInput]
|
|
2714
|
+
]) {
|
|
2715
|
+
if (!auxiliary) continue;
|
|
2716
|
+
const bytes = fs3.readFileSync(proofBoundPath(root, auxiliary.sourceReceipt));
|
|
2717
|
+
if (proofByteHash(bytes) !== auxiliary.sourceReceiptSha256)
|
|
2718
|
+
throw new Error(`native ${label} receipt does not match its recorded hash`);
|
|
2719
|
+
paths.add(auxiliary.sourceReceipt);
|
|
2720
|
+
}
|
|
2447
2721
|
const native = life.nativeFramebuffer;
|
|
2448
2722
|
if (native) {
|
|
2449
2723
|
paths.add(native.receipt);
|
|
2724
|
+
paths.add(native.superseded);
|
|
2450
2725
|
paths.add(native.mediaFrames);
|
|
2451
2726
|
const rows = fs3.readFileSync(proofBoundPath(root, native.receipt), "utf8").trim().split("\n").map(JSON.parse);
|
|
2452
2727
|
for (const row of rows) {
|
|
@@ -6348,6 +6623,11 @@ function sameNativeAccessibilityShape(a, b, bounds) {
|
|
|
6348
6623
|
return true;
|
|
6349
6624
|
}
|
|
6350
6625
|
|
|
6626
|
+
// src/is-record.ts
|
|
6627
|
+
function isRecord(value) {
|
|
6628
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6629
|
+
}
|
|
6630
|
+
|
|
6351
6631
|
// cli/commands/inspect/core.ts
|
|
6352
6632
|
function layoutBoundFontFamily(style) {
|
|
6353
6633
|
const raw = typeof style === "object" && style !== null ? style.fontFamily : void 0;
|
|
@@ -7362,9 +7642,12 @@ var AUTOMATION_SIM_IDLE_REAP_TTL_MS = 5 * 6e4;
|
|
|
7362
7642
|
// src/home-paths.ts
|
|
7363
7643
|
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
7364
7644
|
|
|
7365
|
-
// ../peach-engine/src/
|
|
7645
|
+
// ../peach-engine/src/preview/bundle-layout.ts
|
|
7366
7646
|
var import_metro_production_bundle = require("peachsim/metro-production-bundle");
|
|
7367
7647
|
|
|
7648
|
+
// ../peach-engine/src/tenant-bundle-mode.ts
|
|
7649
|
+
var import_metro_production_bundle2 = require("peachsim/metro-production-bundle");
|
|
7650
|
+
|
|
7368
7651
|
// ../peach-engine/src/tenant-runtime-environment.ts
|
|
7369
7652
|
function readBrowserLocation() {
|
|
7370
7653
|
try {
|
|
@@ -7843,7 +8126,7 @@ var PEACH_UPSTREAM_MODULES = {
|
|
|
7843
8126
|
};
|
|
7844
8127
|
|
|
7845
8128
|
// ../peach-engine/src/metro-fingerprint.ts
|
|
7846
|
-
var
|
|
8129
|
+
var import_metro_production_bundle3 = require("peachsim/metro-production-bundle");
|
|
7847
8130
|
var import_react_native_host_modules = require("peachsim/react-native-host-modules");
|
|
7848
8131
|
|
|
7849
8132
|
// src/cloud-contract.ts
|
|
@@ -10636,6 +10919,10 @@ function setPauseAwareTimeout(fn, budgetMs, hostPid) {
|
|
|
10636
10919
|
}
|
|
10637
10920
|
return () => {
|
|
10638
10921
|
timers.delete(timer);
|
|
10922
|
+
if (timers.size === 0 && poll) {
|
|
10923
|
+
clearInterval(poll);
|
|
10924
|
+
poll = void 0;
|
|
10925
|
+
}
|
|
10639
10926
|
};
|
|
10640
10927
|
}
|
|
10641
10928
|
|
|
@@ -10674,7 +10961,10 @@ var BRIDGE_VALUE_FLAGS_TABLE = [
|
|
|
10674
10961
|
{
|
|
10675
10962
|
names: ["--timeout"],
|
|
10676
10963
|
apply: (state, value) => {
|
|
10677
|
-
if (value !== void 0)
|
|
10964
|
+
if (value !== void 0) {
|
|
10965
|
+
state.commandTimeoutMs = Number(value);
|
|
10966
|
+
state.explicitTimeout = true;
|
|
10967
|
+
}
|
|
10678
10968
|
}
|
|
10679
10969
|
},
|
|
10680
10970
|
{
|
|
@@ -10814,7 +11104,7 @@ function createBridge(wsPort, opts = {}) {
|
|
|
10814
11104
|
return {
|
|
10815
11105
|
plane: "local",
|
|
10816
11106
|
async send(cmd, callOpts) {
|
|
10817
|
-
const effectiveTimeoutMs = callOpts?.timeoutMs ?? commandTimeoutMs;
|
|
11107
|
+
const effectiveTimeoutMs = callOpts?.timeoutMs ?? (opts.explicitTimeout ? commandTimeoutMs : callOpts?.defaultTimeoutMs) ?? commandTimeoutMs;
|
|
10818
11108
|
const sendOnce = async (defaultSimId, cmdOverride) => {
|
|
10819
11109
|
await ready;
|
|
10820
11110
|
if (terminalError) throw terminalError;
|
|
@@ -10827,11 +11117,7 @@ function createBridge(wsPort, opts = {}) {
|
|
|
10827
11117
|
const clearTimeoutFn = setPauseAwareTimeout(
|
|
10828
11118
|
() => {
|
|
10829
11119
|
pending.delete(id);
|
|
10830
|
-
reject(
|
|
10831
|
-
new Error(
|
|
10832
|
-
`command timed out after ${Math.round(effectiveTimeoutMs / 1e3)}s`
|
|
10833
|
-
)
|
|
10834
|
-
);
|
|
11120
|
+
reject(new Error(`command timed out after ${effectiveTimeoutMs / 1e3}s`));
|
|
10835
11121
|
},
|
|
10836
11122
|
effectiveTimeoutMs,
|
|
10837
11123
|
lineageBySimId.get(payload.simId)?.hostPid
|
|
@@ -11064,25 +11350,8 @@ function usesDirectLookup(matcher) {
|
|
|
11064
11350
|
return matcher.regexFlags === void 0 && matcher.index === void 0 && matcher.type !== "text";
|
|
11065
11351
|
}
|
|
11066
11352
|
|
|
11067
|
-
// ../peach-engine/src/
|
|
11068
|
-
|
|
11069
|
-
id: "ios",
|
|
11070
|
-
displayName: "iOS",
|
|
11071
|
-
isIOS: true,
|
|
11072
|
-
isAndroid: false,
|
|
11073
|
-
select: (registry) => registry.ios
|
|
11074
|
-
});
|
|
11075
|
-
var ANDROID_ADAPTER = Object.freeze({
|
|
11076
|
-
id: "android",
|
|
11077
|
-
displayName: "Android",
|
|
11078
|
-
isIOS: false,
|
|
11079
|
-
isAndroid: true,
|
|
11080
|
-
select: (registry) => registry.android
|
|
11081
|
-
});
|
|
11082
|
-
var RUNTIME_PLATFORM_ADAPTERS = Object.freeze({
|
|
11083
|
-
ios: IOS_ADAPTER,
|
|
11084
|
-
android: ANDROID_ADAPTER
|
|
11085
|
-
});
|
|
11353
|
+
// ../peach-engine/src/settings/device-spec-bus.ts
|
|
11354
|
+
init_adapter();
|
|
11086
11355
|
|
|
11087
11356
|
// ../peach-engine/src/settings/dynamic-type.ts
|
|
11088
11357
|
function textMetrics(fontSize, lineHeight, leading, ascent) {
|
|
@@ -12097,8 +12366,94 @@ async function dispatchTwoFingerGesture(page, startA, startB, endA, endB, option
|
|
|
12097
12366
|
await page.waitForTimeout(250);
|
|
12098
12367
|
}
|
|
12099
12368
|
|
|
12369
|
+
// ../contrast-runtime-delivery/src/version.ts
|
|
12370
|
+
function isValidRuntimeVersion(value) {
|
|
12371
|
+
return value.length <= 100 && /^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(value);
|
|
12372
|
+
}
|
|
12373
|
+
|
|
12374
|
+
// src/nativeViewSourceContract.ts
|
|
12375
|
+
function isNativeViewSource(value) {
|
|
12376
|
+
if (!isRecord(value)) return false;
|
|
12377
|
+
if (value.type === "placeholder")
|
|
12378
|
+
return (value.uri === void 0 || typeof value.uri === "string" && value.uri.length > 0) && (value.color === void 0 || typeof value.color === "string");
|
|
12379
|
+
if (value.type === "web") {
|
|
12380
|
+
if (typeof value.uri !== "string") return false;
|
|
12381
|
+
try {
|
|
12382
|
+
const url = new URL(value.uri);
|
|
12383
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
12384
|
+
} catch {
|
|
12385
|
+
return false;
|
|
12386
|
+
}
|
|
12387
|
+
}
|
|
12388
|
+
return value.type === "video" && typeof value.uri === "string" && value.uri.length > 0 && ["paused", "loop", "muted"].every(
|
|
12389
|
+
(key) => value[key] === void 0 || typeof value[key] === "boolean"
|
|
12390
|
+
) && (value.currentTime === void 0 || typeof value.currentTime === "number" && Number.isFinite(value.currentTime) && value.currentTime >= 0) && (value.resizeMode === void 0 || value.resizeMode === "contain" || value.resizeMode === "cover" || value.resizeMode === "stretch");
|
|
12391
|
+
}
|
|
12392
|
+
|
|
12393
|
+
// src/config.ts
|
|
12394
|
+
function readNativeRenderer2(value) {
|
|
12395
|
+
if (value === void 0) return void 0;
|
|
12396
|
+
if (value === "paper" || value === "fabric") return value;
|
|
12397
|
+
throw new Error("nativeRenderer must be paper or fabric");
|
|
12398
|
+
}
|
|
12399
|
+
function isPackageStubs(value) {
|
|
12400
|
+
if (value === "noop") return true;
|
|
12401
|
+
if (!isRecord(value)) return false;
|
|
12402
|
+
return (value.modules === void 0 || isRecord(value.modules) && Object.values(value.modules).every(
|
|
12403
|
+
(stub) => typeof stub === "string" && stub.length > 0
|
|
12404
|
+
)) && (value.views === void 0 || isRecord(value.views) && Object.values(value.views).every(
|
|
12405
|
+
(stub) => typeof stub === "string" && stub.length > 0 || isNativeViewSource(stub)
|
|
12406
|
+
));
|
|
12407
|
+
}
|
|
12408
|
+
var PEACH_CONFIG_QUERY_PARAM = "peachConfig";
|
|
12409
|
+
function isPeachConfig(value) {
|
|
12410
|
+
if (!isRecord(value)) return false;
|
|
12411
|
+
return (value.nativeRenderer === void 0 || value.nativeRenderer === "paper" || value.nativeRenderer === "fabric") && (value.mapKit === void 0 || isRecord(value.mapKit) && typeof value.mapKit.token === "string" && value.mapKit.token.length > 0 && value.mapKit.token === value.mapKit.token.trim()) && (value.runtimeVersion === void 0 || typeof value.runtimeVersion === "string" && value.runtimeVersion === value.runtimeVersion.trim() && isValidRuntimeVersion(value.runtimeVersion)) && [
|
|
12412
|
+
"modules",
|
|
12413
|
+
"packages",
|
|
12414
|
+
"turboModules",
|
|
12415
|
+
"nativeModules",
|
|
12416
|
+
"nativeViews",
|
|
12417
|
+
"env",
|
|
12418
|
+
"network",
|
|
12419
|
+
"settings",
|
|
12420
|
+
"initialProps",
|
|
12421
|
+
"initialState"
|
|
12422
|
+
].every((key) => value[key] === void 0 || isRecord(value[key])) && (value.packages === void 0 || isRecord(value.packages) && Object.values(value.packages).every(isPackageStubs)) && (value.nativeViews === void 0 || isRecord(value.nativeViews) && Object.values(value.nativeViews).every(
|
|
12423
|
+
(entry) => entry === "noop" || isNativeViewSource(entry) || isRecord(entry) && typeof entry.file === "string" && entry.file.length > 0
|
|
12424
|
+
));
|
|
12425
|
+
}
|
|
12426
|
+
function hasOwnKeys(value) {
|
|
12427
|
+
return !!value && Object.keys(value).length > 0;
|
|
12428
|
+
}
|
|
12429
|
+
function hasPeachConfig(config) {
|
|
12430
|
+
if (!config) return false;
|
|
12431
|
+
return config.nativeRenderer !== void 0 || config.mapKit !== void 0 || typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.nativeViews) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialProps) || hasOwnKeys(config.initialState);
|
|
12432
|
+
}
|
|
12433
|
+
function readPeachConfigFromSearchParams(searchParams) {
|
|
12434
|
+
const raw = searchParams.get(PEACH_CONFIG_QUERY_PARAM);
|
|
12435
|
+
if (!raw) return void 0;
|
|
12436
|
+
let parsed;
|
|
12437
|
+
try {
|
|
12438
|
+
parsed = JSON.parse(raw);
|
|
12439
|
+
} catch (error) {
|
|
12440
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12441
|
+
console.warn(`[peach] invalid ${PEACH_CONFIG_QUERY_PARAM}: ${message}`);
|
|
12442
|
+
return void 0;
|
|
12443
|
+
}
|
|
12444
|
+
if (isRecord(parsed)) readNativeRenderer2(parsed.nativeRenderer);
|
|
12445
|
+
return isPeachConfig(parsed) && hasPeachConfig(parsed) ? parsed : void 0;
|
|
12446
|
+
}
|
|
12447
|
+
|
|
12100
12448
|
// detox/navigation-lifecycle.ts
|
|
12101
12449
|
var import_attempt_events = __toESM(require_attempt_events(), 1);
|
|
12450
|
+
var developerToken = readPeachConfigFromSearchParams(
|
|
12451
|
+
new URL(process.env.PEACH_URL || "http://localhost").searchParams
|
|
12452
|
+
)?.mapKit?.token;
|
|
12453
|
+
function redactDiagnosticText(text) {
|
|
12454
|
+
const withoutConfig = text.replace(/([?&]peachConfig=)[^&\s"'<>]+/g, "$1[redacted]");
|
|
12455
|
+
return developerToken ? withoutConfig.replaceAll(developerToken, "[redacted]") : withoutConfig;
|
|
12456
|
+
}
|
|
12102
12457
|
var DIAGNOSTIC_LIMIT = 40;
|
|
12103
12458
|
var pageDiagnostics = /* @__PURE__ */ new WeakMap();
|
|
12104
12459
|
var activeNavigations = /* @__PURE__ */ new WeakMap();
|
|
@@ -12111,6 +12466,21 @@ function persistDiagnostic(diagnostic) {
|
|
|
12111
12466
|
(0, import_attempt_events.writeAttemptEvent)(diagnostic);
|
|
12112
12467
|
}
|
|
12113
12468
|
function recordPageDiagnostic(page, diagnostic, persist = false) {
|
|
12469
|
+
if ("url" in diagnostic) diagnostic.url = redactDiagnosticText(diagnostic.url);
|
|
12470
|
+
if ("navigationUrl" in diagnostic)
|
|
12471
|
+
diagnostic.navigationUrl = redactDiagnosticText(diagnostic.navigationUrl);
|
|
12472
|
+
if ("message" in diagnostic)
|
|
12473
|
+
diagnostic.message = redactDiagnosticText(diagnostic.message);
|
|
12474
|
+
if ("errorText" in diagnostic && diagnostic.errorText)
|
|
12475
|
+
diagnostic.errorText = redactDiagnosticText(diagnostic.errorText);
|
|
12476
|
+
if ("pageState" in diagnostic && diagnostic.pageState) {
|
|
12477
|
+
if ("url" in diagnostic.pageState)
|
|
12478
|
+
diagnostic.pageState.url = redactDiagnosticText(diagnostic.pageState.url);
|
|
12479
|
+
if ("evaluateError" in diagnostic.pageState)
|
|
12480
|
+
diagnostic.pageState.evaluateError = redactDiagnosticText(
|
|
12481
|
+
diagnostic.pageState.evaluateError
|
|
12482
|
+
);
|
|
12483
|
+
}
|
|
12114
12484
|
const entries = pageDiagnostics.get(page);
|
|
12115
12485
|
if (!entries) return;
|
|
12116
12486
|
entries.push(diagnostic);
|
|
@@ -12217,7 +12587,7 @@ function attachPageDiagnostics(page) {
|
|
|
12217
12587
|
}
|
|
12218
12588
|
async function readSootsimPageState(page) {
|
|
12219
12589
|
try {
|
|
12220
|
-
|
|
12590
|
+
const state = await page.evaluate(() => {
|
|
12221
12591
|
const bootMarks = Reflect.get(window, "__sootsimBootMarks");
|
|
12222
12592
|
return {
|
|
12223
12593
|
bodyText: document.body?.innerText?.slice(0, 500) ?? "",
|
|
@@ -12234,6 +12604,8 @@ async function readSootsimPageState(page) {
|
|
|
12234
12604
|
url: window.location.href
|
|
12235
12605
|
};
|
|
12236
12606
|
});
|
|
12607
|
+
state.url = redactDiagnosticText(state.url);
|
|
12608
|
+
return state;
|
|
12237
12609
|
} catch (error) {
|
|
12238
12610
|
return {
|
|
12239
12611
|
evaluateError: error instanceof Error ? error.message : String(error)
|
|
@@ -12258,14 +12630,14 @@ async function describeSootsimBridgeFailure(page, cause, summary = "timed out wa
|
|
|
12258
12630
|
`page: ${JSON.stringify(state)}`,
|
|
12259
12631
|
`recent page diagnostics:
|
|
12260
12632
|
${JSON.stringify(getSootsimNavigationDiagnostics(page))}`
|
|
12261
|
-
].join("\n")
|
|
12633
|
+
].map(redactDiagnosticText).join("\n")
|
|
12262
12634
|
);
|
|
12263
12635
|
}
|
|
12264
12636
|
async function navigateSootsimPage(page, url, identity) {
|
|
12265
12637
|
attachPageDiagnostics(page);
|
|
12266
12638
|
const navigation = {
|
|
12267
12639
|
...identity,
|
|
12268
|
-
navigationUrl: url,
|
|
12640
|
+
navigationUrl: redactDiagnosticText(url),
|
|
12269
12641
|
navigationId: ++nextNavigationIdentity
|
|
12270
12642
|
};
|
|
12271
12643
|
activeNavigations.set(page, navigation);
|
|
@@ -12318,12 +12690,13 @@ function visibleFraction(node) {
|
|
|
12318
12690
|
function isNodeVisible(node) {
|
|
12319
12691
|
return visibleFraction(node) >= DEFAULT_VISIBILITY_THRESHOLD;
|
|
12320
12692
|
}
|
|
12321
|
-
function focusIsWithin(focused,
|
|
12322
|
-
|
|
12693
|
+
function focusIsWithin(focused, node) {
|
|
12694
|
+
const nativeNodeId = node.nativeTag ?? node.nodeId;
|
|
12695
|
+
return focused.nodeId === nativeNodeId || focused.ancestorNodeIds.includes(nativeNodeId);
|
|
12323
12696
|
}
|
|
12324
12697
|
async function isTextInputNodeFocused(node, page) {
|
|
12325
12698
|
const focused = await page.evaluate(async () => window.__sootsimTest.getFocusedNode());
|
|
12326
|
-
return focused !== null && focusIsWithin(focused, node
|
|
12699
|
+
return focused !== null && focusIsWithin(focused, node);
|
|
12327
12700
|
}
|
|
12328
12701
|
async function isNodeFocused(node, page) {
|
|
12329
12702
|
if (node.isTextInput) return isTextInputNodeFocused(node, page);
|
|
@@ -12773,6 +13146,7 @@ var _browserLaunch = null;
|
|
|
12773
13146
|
var _browserLaunchAbort = null;
|
|
12774
13147
|
var _reapBrowserNow = null;
|
|
12775
13148
|
var _context = null;
|
|
13149
|
+
var _appStorageState;
|
|
12776
13150
|
var _page = null;
|
|
12777
13151
|
var _synchronizationEnabled = false;
|
|
12778
13152
|
var _proofFrameObservationActive = false;
|
|
@@ -12968,14 +13342,17 @@ async function waitForSootsimWorkletsIdle(page, timeout = 3e3) {
|
|
|
12968
13342
|
let readStartedAt = null;
|
|
12969
13343
|
let tenantAtRead = window.__sootsimRenderHost;
|
|
12970
13344
|
let shellAtRead = window.SootSim?.bridges?.shellHost;
|
|
13345
|
+
let peerProgress = null;
|
|
12971
13346
|
let deadlineTimerLateMs = null;
|
|
12972
13347
|
while (Date.now() < deadline) {
|
|
12973
13348
|
readStartedAt = Date.now();
|
|
12974
13349
|
tenantAtRead = window.__sootsimRenderHost;
|
|
12975
13350
|
shellAtRead = window.SootSim?.bridges?.shellHost;
|
|
12976
13351
|
let timer;
|
|
13352
|
+
const peerRead = getPeerStats(false);
|
|
13353
|
+
peerProgress = peerRead && "peachPeerProgress" in peerRead ? peerRead.peachPeerProgress ?? null : null;
|
|
12977
13354
|
const stats = await Promise.race([
|
|
12978
|
-
|
|
13355
|
+
peerRead,
|
|
12979
13356
|
new Promise((resolve3) => {
|
|
12980
13357
|
timer = setTimeout(
|
|
12981
13358
|
() => {
|
|
@@ -13012,6 +13389,7 @@ async function waitForSootsimWorkletsIdle(page, timeout = 3e3) {
|
|
|
13012
13389
|
outstandingRead: readStartedAt === null ? null : {
|
|
13013
13390
|
startedAtMs: readStartedAt - start,
|
|
13014
13391
|
elapsedMs: Date.now() - readStartedAt,
|
|
13392
|
+
peerProgress: peerProgress ? { ...peerProgress } : null,
|
|
13015
13393
|
testBridgeChanged: window.__sootsimTest !== testBridge,
|
|
13016
13394
|
tenant: {
|
|
13017
13395
|
presentAtRequest: !!tenantAtRead,
|
|
@@ -13092,7 +13470,8 @@ async function quiesceContextMedia(context) {
|
|
|
13092
13470
|
if (timer !== void 0) clearTimeout(timer);
|
|
13093
13471
|
}
|
|
13094
13472
|
}
|
|
13095
|
-
async function closeContext() {
|
|
13473
|
+
async function closeContext(preserveStorage) {
|
|
13474
|
+
if (!preserveStorage) _appStorageState = void 0;
|
|
13096
13475
|
if (_browserCompromised) {
|
|
13097
13476
|
throw new Error(`sootsim browser is compromised: ${_browserCompromised}`);
|
|
13098
13477
|
}
|
|
@@ -13100,6 +13479,13 @@ async function closeContext() {
|
|
|
13100
13479
|
const context = _context;
|
|
13101
13480
|
const closingContextId = contextIdentity;
|
|
13102
13481
|
try {
|
|
13482
|
+
if (preserveStorage) {
|
|
13483
|
+
_appStorageState = await withLifecycleTimeout(
|
|
13484
|
+
"context.storageState()",
|
|
13485
|
+
closingContextId,
|
|
13486
|
+
() => context.storageState({ indexedDB: true })
|
|
13487
|
+
);
|
|
13488
|
+
}
|
|
13103
13489
|
await quiesceContextMedia(context);
|
|
13104
13490
|
await withLifecycleTimeout("context.close()", closingContextId, () => context.close());
|
|
13105
13491
|
_context = null;
|
|
@@ -13113,7 +13499,8 @@ async function closeContext() {
|
|
|
13113
13499
|
throw error;
|
|
13114
13500
|
}
|
|
13115
13501
|
}
|
|
13116
|
-
async function closeBrowser() {
|
|
13502
|
+
async function closeBrowser(preserveStorage) {
|
|
13503
|
+
if (!preserveStorage) _appStorageState = void 0;
|
|
13117
13504
|
if (!_browser) return;
|
|
13118
13505
|
const browser = _browser;
|
|
13119
13506
|
const reapBrowserNow = _reapBrowserNow;
|
|
@@ -13122,7 +13509,7 @@ async function closeBrowser() {
|
|
|
13122
13509
|
browserIdentity = 0;
|
|
13123
13510
|
let closeError = null;
|
|
13124
13511
|
try {
|
|
13125
|
-
await closeContext();
|
|
13512
|
+
await closeContext(preserveStorage);
|
|
13126
13513
|
} catch (error) {
|
|
13127
13514
|
closeError = error instanceof Error ? error : new Error(String(error));
|
|
13128
13515
|
}
|
|
@@ -13358,7 +13745,7 @@ async function focusElementForTextEntry(el) {
|
|
|
13358
13745
|
await el.tap();
|
|
13359
13746
|
await pollUntil(
|
|
13360
13747
|
() => page.evaluate(async () => window.__sootsimTest.getFocusedNode()),
|
|
13361
|
-
(focused) => focused !== null && focusIsWithin(focused, node
|
|
13748
|
+
(focused) => focused !== null && focusIsWithin(focused, node),
|
|
13362
13749
|
{
|
|
13363
13750
|
timeoutMs: 5e3,
|
|
13364
13751
|
label: `SootSim text input ${node.nodeId} to focus`
|
|
@@ -13747,10 +14134,11 @@ function createSootSimElement(matcher) {
|
|
|
13747
14134
|
}
|
|
13748
14135
|
},
|
|
13749
14136
|
async swipe(direction, speed = "fast", percentage = 0.75, normalizedStartingPointX = 0.5, normalizedStartingPointY = 0.5) {
|
|
14137
|
+
const page = getPage();
|
|
14138
|
+
if (_synchronizationEnabled) await waitForSootsimIdle2(page, 3e3, false, 0);
|
|
13750
14139
|
const node = await findStableNodeByMatcher(matcher, "swipe");
|
|
13751
14140
|
if (!node)
|
|
13752
14141
|
throw new Error(`element not found for swipe: ${JSON.stringify(matcher)}`);
|
|
13753
|
-
const page = getPage();
|
|
13754
14142
|
const { absolutePosition, layout } = node;
|
|
13755
14143
|
const startSootSimX = absolutePosition.x + layout.width * normalizedStartingPointX;
|
|
13756
14144
|
const startSootSimY = absolutePosition.y + layout.height * normalizedStartingPointY;
|
|
@@ -14127,10 +14515,11 @@ var device = {
|
|
|
14127
14515
|
}
|
|
14128
14516
|
}
|
|
14129
14517
|
if (!_page || newInstance || opts?.delete || opts?.recordVideoDir) {
|
|
14130
|
-
await closeContext();
|
|
14518
|
+
await closeContext(!opts?.delete);
|
|
14131
14519
|
const contextOpts = {
|
|
14132
14520
|
hasTouch: true,
|
|
14133
|
-
viewport: { width: 500, height: 900 }
|
|
14521
|
+
viewport: { width: 500, height: 900 },
|
|
14522
|
+
storageState: _appStorageState
|
|
14134
14523
|
};
|
|
14135
14524
|
if (opts?.recordVideoDir) {
|
|
14136
14525
|
fs2.mkdirSync(opts.recordVideoDir, { recursive: true });
|
|
@@ -14235,7 +14624,7 @@ var device = {
|
|
|
14235
14624
|
await waitForSootsimWorkletsIdle(page, 3e3);
|
|
14236
14625
|
},
|
|
14237
14626
|
async terminateApp() {
|
|
14238
|
-
await closeBrowser();
|
|
14627
|
+
await closeBrowser(true);
|
|
14239
14628
|
},
|
|
14240
14629
|
async installApp() {
|
|
14241
14630
|
},
|
|
@@ -14707,7 +15096,18 @@ var device = {
|
|
|
14707
15096
|
if (input.hold && (!interact || typeof interact.touchDown !== "function")) {
|
|
14708
15097
|
throw new Error("peach interact bridge is not installed");
|
|
14709
15098
|
}
|
|
14710
|
-
const
|
|
15099
|
+
const pairedPeerStats = async (reset = false) => {
|
|
15100
|
+
const stats = await captureWindow.SootSim?.bridges?.test?.getPeerStats?.(reset);
|
|
15101
|
+
if (!stats || !Number.isSafeInteger(stats.replayedFrameCallbacks))
|
|
15102
|
+
throw new Error(
|
|
15103
|
+
"paired worklets clock needs native frame delivery diagnostics"
|
|
15104
|
+
);
|
|
15105
|
+
return stats;
|
|
15106
|
+
};
|
|
15107
|
+
if (input.workletFrameTimestampsSeconds) await pairedPeerStats(true);
|
|
15108
|
+
const controller = await lockstep.begin(60, {
|
|
15109
|
+
workletFrameTimestampsSeconds: input.workletFrameTimestampsSeconds
|
|
15110
|
+
});
|
|
14711
15111
|
const moves = input.hold?.moves ?? [];
|
|
14712
15112
|
const holdState = {
|
|
14713
15113
|
nextMove: 0,
|
|
@@ -14752,10 +15152,21 @@ var device = {
|
|
|
14752
15152
|
);
|
|
14753
15153
|
};
|
|
14754
15154
|
const keptFrames = /* @__PURE__ */ new Map();
|
|
15155
|
+
const keepFrame = (receipt, bitmap) => {
|
|
15156
|
+
keptFrames.get(receipt.frameIndex)?.bitmap.close();
|
|
15157
|
+
keptFrames.set(receipt.frameIndex, { bitmap, receipt });
|
|
15158
|
+
};
|
|
14755
15159
|
try {
|
|
15160
|
+
if (input.anchorAtTouch && !input.hold) {
|
|
15161
|
+
throw new Error("peach touch anchoring needs a hold");
|
|
15162
|
+
}
|
|
14756
15163
|
const baselineBitmap = await captureBitmap();
|
|
14757
15164
|
const baseline = regionPixels(baselineBitmap);
|
|
14758
|
-
|
|
15165
|
+
if (input.anchorAtTouch === "down")
|
|
15166
|
+
keepFrame(controller.initialFrame, baselineBitmap);
|
|
15167
|
+
else baselineBitmap.close();
|
|
15168
|
+
if (input.workletFrameTimestampsSeconds && (await pairedPeerStats()).replayedFrameCallbacks > 0)
|
|
15169
|
+
throw new Error("paired worklets callback preceded the Peach trigger");
|
|
14759
15170
|
state.ready = true;
|
|
14760
15171
|
if (input.hold && interact) {
|
|
14761
15172
|
const hit = await interact.touchDown(
|
|
@@ -14793,7 +15204,7 @@ var device = {
|
|
|
14793
15204
|
if (measurement.passedMinimum) {
|
|
14794
15205
|
visibleStart = receipt;
|
|
14795
15206
|
detectedMeasurement = measurement;
|
|
14796
|
-
|
|
15207
|
+
keepFrame(visibleStart, candidateBitmap);
|
|
14797
15208
|
} else {
|
|
14798
15209
|
candidateBitmap.close();
|
|
14799
15210
|
}
|
|
@@ -14804,8 +15215,8 @@ var device = {
|
|
|
14804
15215
|
const receipt = await controller.stepFrame();
|
|
14805
15216
|
await advanceHold(receipt);
|
|
14806
15217
|
const candidateBitmap = await captureBitmap();
|
|
14807
|
-
if (input.
|
|
14808
|
-
|
|
15218
|
+
if (input.anchorAtTouch === "down" || input.anchorAtTouch === "up" && holdState.releaseReceipt === receipt) {
|
|
15219
|
+
keepFrame(receipt, await createImageBitmap(candidateBitmap));
|
|
14809
15220
|
}
|
|
14810
15221
|
const bounds = boundsFor(candidateBitmap);
|
|
14811
15222
|
const measurement = measureChange({
|
|
@@ -14821,8 +15232,7 @@ var device = {
|
|
|
14821
15232
|
previousBitmap = null;
|
|
14822
15233
|
visibleStart = receipt;
|
|
14823
15234
|
detectedMeasurement = measurement;
|
|
14824
|
-
|
|
14825
|
-
keptFrames.set(receipt.frameIndex, candidateBitmap);
|
|
15235
|
+
keepFrame(receipt, candidateBitmap);
|
|
14826
15236
|
break;
|
|
14827
15237
|
}
|
|
14828
15238
|
previousBitmap?.close();
|
|
@@ -14836,18 +15246,14 @@ var device = {
|
|
|
14836
15246
|
}
|
|
14837
15247
|
let driveStart = visibleStart;
|
|
14838
15248
|
let currentReceipt = visibleStart;
|
|
14839
|
-
if (input.
|
|
14840
|
-
|
|
14841
|
-
throw new Error("peach release anchoring needs a hold");
|
|
14842
|
-
}
|
|
15249
|
+
if (input.anchorAtTouch === "down") driveStart = controller.initialFrame;
|
|
15250
|
+
if (input.anchorAtTouch === "up") {
|
|
14843
15251
|
while (!holdState.released) {
|
|
14844
15252
|
if (state.cancelled) throw new Error("peach motion capture was cancelled");
|
|
14845
15253
|
const receipt = await controller.stepFrame();
|
|
14846
15254
|
await advanceHold(receipt);
|
|
14847
15255
|
currentReceipt = receipt;
|
|
14848
|
-
if (holdState.released)
|
|
14849
|
-
keptFrames.set(receipt.frameIndex, await captureBitmap());
|
|
14850
|
-
}
|
|
15256
|
+
if (holdState.released) keepFrame(receipt, await captureBitmap());
|
|
14851
15257
|
}
|
|
14852
15258
|
if (!holdState.releaseReceipt) {
|
|
14853
15259
|
throw new Error("peach release anchoring found no release frame");
|
|
@@ -14926,8 +15332,7 @@ var device = {
|
|
|
14926
15332
|
`peach motion anchor ${anchor.id} found no onset past ${onsetThresholdPercent}% within ${input.detectionTimeoutMs}ms of ${anchor.notBeforeMs}ms (pan peak ${panPeakPercent.toFixed(2)}%, later peak ${latePeakPercent.toFixed(2)}%): the gate or the search start is wrong for this surface`
|
|
14927
15333
|
);
|
|
14928
15334
|
}
|
|
14929
|
-
|
|
14930
|
-
keptFrames.set(anchorReceipt.frameIndex, anchorBitmap);
|
|
15335
|
+
keepFrame(anchorReceipt, anchorBitmap);
|
|
14931
15336
|
resolvedAnchors.set(anchor.id, anchorReceipt);
|
|
14932
15337
|
anchorRecords.push({
|
|
14933
15338
|
changedPixelPercent: onsetMeasurement.changePercent,
|
|
@@ -14946,13 +15351,13 @@ var device = {
|
|
|
14946
15351
|
const kept = keptFrames.get(stageFrameIndex);
|
|
14947
15352
|
if (kept && stageFrameIndex <= currentReceipt.frameIndex) {
|
|
14948
15353
|
snapshots.push({
|
|
14949
|
-
actualMs:
|
|
15354
|
+
actualMs: kept.receipt.virtualTimestampMs - anchorReceipt.virtualTimestampMs,
|
|
14950
15355
|
anchorId,
|
|
14951
|
-
bitmap: await createImageBitmap(kept),
|
|
14952
|
-
frameIndex:
|
|
15356
|
+
bitmap: await createImageBitmap(kept.bitmap),
|
|
15357
|
+
frameIndex: kept.receipt.frameIndex,
|
|
14953
15358
|
label: stage.label,
|
|
14954
15359
|
offsetMs: stage.offsetMs,
|
|
14955
|
-
virtualTimestampMs:
|
|
15360
|
+
virtualTimestampMs: kept.receipt.virtualTimestampMs
|
|
14956
15361
|
});
|
|
14957
15362
|
continue;
|
|
14958
15363
|
}
|
|
@@ -14972,6 +15377,7 @@ var device = {
|
|
|
14972
15377
|
virtualTimestampMs: receipt.virtualTimestampMs
|
|
14973
15378
|
});
|
|
14974
15379
|
}
|
|
15380
|
+
if (input.workletFrameTimestampsSeconds) controller.endWorkletFrameReceipt();
|
|
14975
15381
|
let releasedOffsetMs = 0;
|
|
14976
15382
|
while (nextHoldEventFrameIndex() !== null) {
|
|
14977
15383
|
const receipt = await controller.stepFrame();
|
|
@@ -14993,6 +15399,17 @@ var device = {
|
|
|
14993
15399
|
await controller.stepFrame();
|
|
14994
15400
|
await new Promise((resolve3) => setTimeout(resolve3, 0));
|
|
14995
15401
|
}
|
|
15402
|
+
if (input.workletFrameTimestampsSeconds) {
|
|
15403
|
+
const stats = await pairedPeerStats();
|
|
15404
|
+
const first = stats.nativeFrameFirstTimestampMs;
|
|
15405
|
+
const firstFrameIndex = first === null ? null : Math.round(
|
|
15406
|
+
(first - controller.initialFrame.virtualTimestampMs) / (1e3 / 60)
|
|
15407
|
+
);
|
|
15408
|
+
if (firstFrameIndex !== 1)
|
|
15409
|
+
throw new Error(
|
|
15410
|
+
`paired worklets first delivery did not match the next UI frame: ${firstFrameIndex}`
|
|
15411
|
+
);
|
|
15412
|
+
}
|
|
14996
15413
|
return {
|
|
14997
15414
|
inputReceipts: controller.inputReceipts,
|
|
14998
15415
|
anchors: anchorRecords,
|
|
@@ -15013,15 +15430,16 @@ var device = {
|
|
|
15013
15430
|
}
|
|
15014
15431
|
};
|
|
15015
15432
|
} finally {
|
|
15016
|
-
for (const
|
|
15433
|
+
for (const kept of keptFrames.values()) kept.bitmap.close();
|
|
15017
15434
|
controller.end();
|
|
15018
15435
|
delete registry[input.token];
|
|
15019
15436
|
}
|
|
15020
15437
|
},
|
|
15021
15438
|
{
|
|
15439
|
+
workletFrameTimestampsSeconds: options.workletFrameTimestampsSeconds,
|
|
15022
15440
|
detectionTimeoutMs: options.detectionTimeoutMs ?? 3e3,
|
|
15023
15441
|
frame: options.frame ?? null,
|
|
15024
|
-
|
|
15442
|
+
anchorAtTouch: options.anchorAtTouch ?? null,
|
|
15025
15443
|
hold: options.hold ?? null,
|
|
15026
15444
|
motionChangeDefinition: import_motion_change.MOTION_CHANGE_DEFINITION,
|
|
15027
15445
|
platform: device.getPlatform(),
|
|
@@ -15031,14 +15449,19 @@ var device = {
|
|
|
15031
15449
|
token
|
|
15032
15450
|
}
|
|
15033
15451
|
);
|
|
15034
|
-
await
|
|
15035
|
-
(
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
|
|
15452
|
+
await Promise.race([
|
|
15453
|
+
page.waitForFunction(
|
|
15454
|
+
(captureToken) => {
|
|
15455
|
+
const registry = window.__sootsimVisibleChangeCaptures;
|
|
15456
|
+
return registry?.[captureToken]?.ready === true;
|
|
15457
|
+
},
|
|
15458
|
+
token,
|
|
15459
|
+
{ timeout: 5e3 }
|
|
15460
|
+
),
|
|
15461
|
+
capturePromise.then(() => {
|
|
15462
|
+
throw new Error("peach motion capture completed before its trigger");
|
|
15463
|
+
})
|
|
15464
|
+
]);
|
|
15042
15465
|
const triggerStartMs = Date.now();
|
|
15043
15466
|
let triggerCompletedMs = 0;
|
|
15044
15467
|
try {
|
|
@@ -15483,7 +15906,7 @@ async function cleanup() {
|
|
|
15483
15906
|
_browserLaunchAbort?.abort(new Error("Peach driver cleaned up"));
|
|
15484
15907
|
await _browserLaunch?.catch(() => {
|
|
15485
15908
|
});
|
|
15486
|
-
await closeBrowser();
|
|
15909
|
+
await closeBrowser(false);
|
|
15487
15910
|
}
|
|
15488
15911
|
// Annotate the CommonJS export names for ESM import in node:
|
|
15489
15912
|
0 && (module.exports = {
|