@farmslot/adapter-rn 0.15.0 → 0.16.0

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 (53) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +15 -10
  3. package/bridge-runtime/console-forwarder.cjs +485 -0
  4. package/bridge-runtime/lib/bridge-errors.cjs +108 -0
  5. package/bridge-runtime/lib/cdp-eval.cjs +118 -0
  6. package/bridge-runtime/lib/config.cjs +68 -0
  7. package/bridge-runtime/lib/console-format.cjs +54 -0
  8. package/bridge-runtime/lib/devtools-proxy.cjs +169 -0
  9. package/bridge-runtime/lib/issue-capture.cjs +86 -0
  10. package/bridge-runtime/lib/match-bridge-target.cjs +89 -0
  11. package/bridge-runtime/lib/target-discovery.cjs +436 -0
  12. package/bridge-runtime/lib/ws-client.cjs +119 -0
  13. package/dist/cli.js +1 -1
  14. package/dist/cli.js.map +1 -1
  15. package/dist/devices.d.ts +16 -0
  16. package/dist/devices.d.ts.map +1 -0
  17. package/dist/devices.js +131 -0
  18. package/dist/devices.js.map +1 -0
  19. package/dist/doctor.js +1 -1
  20. package/dist/doctor.js.map +1 -1
  21. package/dist/fingerprint-baseline.d.ts +8 -0
  22. package/dist/fingerprint-baseline.d.ts.map +1 -0
  23. package/dist/fingerprint-baseline.js +68 -0
  24. package/dist/fingerprint-baseline.js.map +1 -0
  25. package/dist/frame-metrics.d.ts +26 -0
  26. package/dist/frame-metrics.d.ts.map +1 -0
  27. package/dist/frame-metrics.js +134 -0
  28. package/dist/frame-metrics.js.map +1 -0
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +6 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/metro-env.d.ts +11 -0
  34. package/dist/metro-env.d.ts.map +1 -0
  35. package/dist/metro-env.js +29 -0
  36. package/dist/metro-env.js.map +1 -0
  37. package/dist/source-freshness.d.ts +11 -0
  38. package/dist/source-freshness.d.ts.map +1 -0
  39. package/dist/source-freshness.js +98 -0
  40. package/dist/source-freshness.js.map +1 -0
  41. package/dist/tool-paths.d.ts +13 -0
  42. package/dist/tool-paths.d.ts.map +1 -0
  43. package/dist/tool-paths.js +125 -0
  44. package/dist/tool-paths.js.map +1 -0
  45. package/dist/video-recorder.d.ts +7 -0
  46. package/dist/video-recorder.d.ts.map +1 -0
  47. package/dist/video-recorder.js +250 -0
  48. package/dist/video-recorder.js.map +1 -0
  49. package/metro/coalesce-metro-log.cjs +28 -0
  50. package/metro/launch-metro.cjs +84 -0
  51. package/metro/metro-config.cjs +92 -0
  52. package/metro/metro-log-generation.cjs +116 -0
  53. package/package.json +26 -7
@@ -0,0 +1,131 @@
1
+ // Shared connected-device enumeration for first-class `--device` targeting and the
2
+ // `status` devices section. Every probe shells the platform tool via execFile with
3
+ // an argv array (NEVER a string-interpolated shell) so a device id can never inject.
4
+ import { execFileSync } from 'node:child_process';
5
+ import { resolveMobileToolPath } from './tool-paths.js';
6
+ const IOS_DEVICE_DISCOVERY_TIMEOUT_MS = 30_000;
7
+ function reportProbeFailure(errors, platform, error) {
8
+ const code = error?.code;
9
+ if (code === 'ENOENT')
10
+ return;
11
+ const timeoutSeconds = platform === 'ios' ? IOS_DEVICE_DISCOVERY_TIMEOUT_MS / 1000 : 5;
12
+ const reason = code === 'ETIMEDOUT' ? `timed out after ${timeoutSeconds} seconds` : 'failed';
13
+ const probeCode = code ?? error?.status;
14
+ errors.push({
15
+ platform,
16
+ message: `${platform} device discovery ${reason}; device availability is unknown.`,
17
+ userAction: platform === 'ios' ? 'xcrun simctl list devices booted -j' : 'adb devices -l',
18
+ ...(probeCode !== undefined ? { probeCode } : {}),
19
+ });
20
+ }
21
+ // Enumerate the connected devices for one platform (or both when unspecified).
22
+ // Advisory by contract: a missing tool (no `adb`, non-macOS with no `xcrun`) yields
23
+ // [] for that platform rather than throwing — see listAndroidDevices/listIosSimulators.
24
+ export function listConnectedDevices(platform, errors = []) {
25
+ const devices = [];
26
+ if (!platform || platform === 'android')
27
+ devices.push(...listAndroidDevices(errors));
28
+ if (!platform || platform === 'ios')
29
+ devices.push(...listIosSimulators('booted', errors));
30
+ return devices;
31
+ }
32
+ // Launch may need to resolve a simulator before it is booted. Keep the normal
33
+ // connected-device inventory booted-only, but expose the same parsed identity
34
+ // shape for the launch target resolver.
35
+ export function findAvailableIosSimulatorById(id, errors = []) {
36
+ for (const simulator of listIosSimulators('available', errors)) {
37
+ if (simulator.id === id)
38
+ return simulator;
39
+ }
40
+ return undefined;
41
+ }
42
+ function listAndroidDevices(errors) {
43
+ const adbPath = resolveMobileToolPath('adb');
44
+ if (!adbPath)
45
+ return [];
46
+ let output;
47
+ try {
48
+ output = execFileSync(adbPath, ['devices', '-l'], {
49
+ encoding: 'utf8',
50
+ timeout: 5000,
51
+ stdio: ['ignore', 'pipe', 'ignore'],
52
+ });
53
+ }
54
+ catch (error) {
55
+ reportProbeFailure(errors, 'android', error);
56
+ return [];
57
+ }
58
+ if (!output.trimStart().startsWith('List of devices attached')) {
59
+ errors.push({
60
+ platform: 'android',
61
+ message: 'Android device discovery returned an invalid response; device availability is unknown.',
62
+ userAction: 'adb devices -l',
63
+ });
64
+ return [];
65
+ }
66
+ const devices = [];
67
+ // First line is the "List of devices attached" header; each remaining non-empty
68
+ // line is "<serial> <state> [key:value ...]" (e.g. model:Pixel_7).
69
+ for (const line of output.split('\n').slice(1)) {
70
+ const trimmed = line.trim();
71
+ if (!trimmed)
72
+ continue;
73
+ const fields = trimmed.split(/\s+/u);
74
+ const id = fields[0];
75
+ const state = fields[1] ?? 'unknown';
76
+ if (!id)
77
+ continue;
78
+ const modelField = fields.find((f) => f.startsWith('model:'));
79
+ const name = modelField ? modelField.slice('model:'.length) : undefined;
80
+ devices.push({ platform: 'android', id, state, ...(name ? { name } : {}) });
81
+ }
82
+ return devices;
83
+ }
84
+ function listIosSimulators(scope, errors) {
85
+ let output;
86
+ try {
87
+ output = execFileSync('xcrun', ['simctl', 'list', 'devices', scope, '-j'], {
88
+ encoding: 'utf8',
89
+ timeout: IOS_DEVICE_DISCOVERY_TIMEOUT_MS,
90
+ stdio: ['ignore', 'pipe', 'ignore'],
91
+ });
92
+ }
93
+ catch (error) {
94
+ reportProbeFailure(errors, 'ios', error);
95
+ return [];
96
+ }
97
+ let parsed;
98
+ try {
99
+ parsed = JSON.parse(output);
100
+ if (!parsed?.devices ||
101
+ typeof parsed.devices !== 'object' ||
102
+ Array.isArray(parsed.devices) ||
103
+ Object.values(parsed.devices).some((devices) => !Array.isArray(devices) ||
104
+ devices.some((device) => !device || typeof device.udid !== 'string'))) {
105
+ throw new Error('Invalid simctl device inventory');
106
+ }
107
+ }
108
+ catch {
109
+ errors.push({
110
+ platform: 'ios',
111
+ message: 'iOS device discovery returned an invalid response; device availability is unknown.',
112
+ userAction: `xcrun simctl list devices ${scope} -j`,
113
+ });
114
+ return [];
115
+ }
116
+ const devices = [];
117
+ for (const runtimeDevices of Object.values(parsed.devices ?? {})) {
118
+ for (const device of runtimeDevices) {
119
+ if (!device.udid)
120
+ continue;
121
+ devices.push({
122
+ platform: 'ios',
123
+ id: device.udid,
124
+ state: device.state ?? 'unknown',
125
+ ...(device.name ? { name: device.name } : {}),
126
+ });
127
+ }
128
+ }
129
+ return devices;
130
+ }
131
+ //# sourceMappingURL=devices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices.js","sourceRoot":"","sources":["../src/devices.ts"],"names":[],"mappings":"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"}
package/dist/doctor.js CHANGED
@@ -39,7 +39,7 @@ export async function runExpoRecipeDoctor(options = {}) {
39
39
  return { status, projectRoot, recipePath, manifestPath, findings };
40
40
  }
41
41
  export function printDoctorResult(result) {
42
- console.log(`Farmslot Expo Recipe doctor: ${result.status}`);
42
+ console.log(`Farmslot React Native adapter doctor: ${result.status}`);
43
43
  console.log(`Recipe: ${result.recipePath}`);
44
44
  console.log(`Manifest: ${result.manifestPath}`);
45
45
  if (result.findings.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type FingerprintStatus = 'current' | 'missing' | 'changed';
2
+ export interface FingerprintCheck {
3
+ fingerprint: string;
4
+ status: FingerprintStatus;
5
+ }
6
+ export declare function checkFingerprintBaseline(markerPath: string, fingerprint: string): FingerprintCheck;
7
+ export declare function recordFingerprintBaseline(markerPath: string, expectedFingerprint: string, fingerprint: () => string): boolean;
8
+ //# sourceMappingURL=fingerprint-baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint-baseline.d.ts","sourceRoot":"","sources":["../src/fingerprint-baseline.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAQD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAOlB;AAID,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,mBAAmB,EAAE,MAAM,EAC3B,WAAW,EAAE,MAAM,MAAM,GACxB,OAAO,CAuBT"}
@@ -0,0 +1,68 @@
1
+ // A recorded fingerprint ("baseline") next to the runtime state, written
2
+ // atomically and only while the inputs still produce the expected fingerprint.
3
+ // Metro env freshness and source freshness both use it.
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ export function checkFingerprintBaseline(markerPath, fingerprint) {
7
+ const baseline = readFingerprintBaseline(markerPath);
8
+ return {
9
+ fingerprint,
10
+ status: baseline === null ? 'missing' : baseline.fingerprint === fingerprint ? 'current' : 'changed',
11
+ };
12
+ }
13
+ // Records `expectedFingerprint` unless `fingerprint()` drifts before, during or
14
+ // right after the write; a drift leaves no baseline for that value behind.
15
+ export function recordFingerprintBaseline(markerPath, expectedFingerprint, fingerprint) {
16
+ if (fingerprint() !== expectedFingerprint)
17
+ return false;
18
+ const temporary = `${markerPath}.${process.pid}.${Date.now()}.tmp`;
19
+ const baseline = {
20
+ schemaVersion: 1,
21
+ fingerprint: expectedFingerprint,
22
+ recordedAt: new Date().toISOString(),
23
+ };
24
+ fs.mkdirSync(path.dirname(markerPath), { recursive: true });
25
+ try {
26
+ fs.writeFileSync(temporary, `${JSON.stringify(baseline, null, 2)}\n`, { mode: 0o600 });
27
+ if (fingerprint() !== expectedFingerprint)
28
+ return false;
29
+ fs.renameSync(temporary, markerPath);
30
+ if (fingerprint() !== expectedFingerprint) {
31
+ if (readFingerprintBaseline(markerPath)?.fingerprint === expectedFingerprint) {
32
+ fs.rmSync(markerPath, { force: true });
33
+ }
34
+ return false;
35
+ }
36
+ }
37
+ finally {
38
+ fs.rmSync(temporary, { force: true });
39
+ }
40
+ return true;
41
+ }
42
+ function readFingerprintBaseline(markerPath) {
43
+ let raw;
44
+ try {
45
+ raw = fs.readFileSync(markerPath, 'utf8');
46
+ }
47
+ catch (error) {
48
+ // No baseline recorded yet.
49
+ if (error.code === 'ENOENT')
50
+ return null;
51
+ throw error;
52
+ }
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(raw);
56
+ }
57
+ catch (error) {
58
+ // A torn or hand-edited baseline proves nothing; treat it as missing so the
59
+ // next launch records a fresh one.
60
+ if (error instanceof SyntaxError)
61
+ return null;
62
+ throw error;
63
+ }
64
+ return parsed.schemaVersion === 1 && typeof parsed.fingerprint === 'string'
65
+ ? parsed
66
+ : null;
67
+ }
68
+ //# sourceMappingURL=fingerprint-baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint-baseline.js","sourceRoot":"","sources":["../src/fingerprint-baseline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface FrameSample {
2
+ cadenceInterval?: boolean;
3
+ completedAtEpochMs: number;
4
+ durationMs: number;
5
+ frameBudgetMs?: number;
6
+ overBudget?: boolean;
7
+ startedAtEpochMs?: number;
8
+ }
9
+ export interface FrameMetricSummary {
10
+ activeFps?: number;
11
+ cadenceGapCount?: number;
12
+ fpsIntervalCount?: number;
13
+ fpsUnavailableReason?: 'insufficient_active_frames' | 'refresh_rate_unavailable' | 'unclassified_cadence_gap';
14
+ frameBudgetMs?: number;
15
+ frameCount: number;
16
+ longestCadenceGapMs?: number;
17
+ longestFrameMs?: number;
18
+ overBudgetFrameCount?: number;
19
+ overBudgetFramePercent?: number;
20
+ p50FrameMs?: number;
21
+ p95FrameMs?: number;
22
+ p99FrameMs?: number;
23
+ refreshRateHz?: number;
24
+ }
25
+ export declare function summarizeFrames(samples: readonly FrameSample[]): FrameMetricSummary;
26
+ //# sourceMappingURL=frame-metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-metrics.d.ts","sourceRoot":"","sources":["../src/frame-metrics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EACjB,4BAA4B,GAC5B,0BAA0B,GAC1B,0BAA0B,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,kBAAkB,CAgGnF"}
@@ -0,0 +1,134 @@
1
+ const MIN_ACTIVE_INTERVALS = 5;
2
+ export function summarizeFrames(samples) {
3
+ const allValidSamples = samples.filter((sample) => Number.isFinite(sample.durationMs) && sample.durationMs > 0);
4
+ const frameBudgetMs = commonFrameBudget(allValidSamples);
5
+ const cadenceSamples = allValidSamples.length > 0 &&
6
+ allValidSamples.every((sample) => sample.cadenceInterval === true);
7
+ const cadenceGaps = cadenceSamples && frameBudgetMs
8
+ ? allValidSamples.filter((sample) => sample.durationMs > frameBudgetMs * 3.01)
9
+ : [];
10
+ const validSamples = cadenceGaps.length > 0
11
+ ? allValidSamples.filter((sample) => sample.durationMs <= (frameBudgetMs ?? 0) * 3.01)
12
+ : allValidSamples;
13
+ const durations = validSamples
14
+ .map((sample) => sample.durationMs)
15
+ .sort((first, second) => first - second);
16
+ if (durations.length === 0) {
17
+ return {
18
+ fpsUnavailableReason: frameBudgetMs
19
+ ? 'insufficient_active_frames'
20
+ : 'refresh_rate_unavailable',
21
+ ...(cadenceGaps.length > 0
22
+ ? {
23
+ cadenceGapCount: cadenceGaps.length,
24
+ longestCadenceGapMs: round(Math.max(...cadenceGaps.map((sample) => sample.durationMs))),
25
+ }
26
+ : {}),
27
+ ...(frameBudgetMs
28
+ ? {
29
+ frameBudgetMs: round(frameBudgetMs),
30
+ refreshRateHz: round(1000 / frameBudgetMs),
31
+ }
32
+ : {}),
33
+ frameCount: 0,
34
+ };
35
+ }
36
+ const frameBudgetOutcomes = validSamples
37
+ .map((sample) => sample.overBudget)
38
+ .filter((value) => value !== undefined);
39
+ const missedFrameBudgetCount = frameBudgetOutcomes.filter(Boolean).length;
40
+ const activeIntervals = frameBudgetMs
41
+ ? activeRenderingIntervals(validSamples, frameBudgetMs)
42
+ : [];
43
+ const activeElapsedMs = activeIntervals.reduce((total, interval) => total + interval, 0);
44
+ const hasActiveFps = cadenceGaps.length === 0 &&
45
+ activeIntervals.length >= MIN_ACTIVE_INTERVALS &&
46
+ activeElapsedMs > 0;
47
+ const refreshRateHz = frameBudgetMs ? 1000 / frameBudgetMs : undefined;
48
+ return {
49
+ ...(hasActiveFps
50
+ ? {
51
+ activeFps: round(Math.min(refreshRateHz ?? Number.POSITIVE_INFINITY, (activeIntervals.length * 1000) / activeElapsedMs)),
52
+ fpsIntervalCount: activeIntervals.length,
53
+ }
54
+ : {
55
+ fpsUnavailableReason: frameBudgetMs
56
+ ? cadenceGaps.length > 0
57
+ ? 'unclassified_cadence_gap'
58
+ : 'insufficient_active_frames'
59
+ : 'refresh_rate_unavailable',
60
+ }),
61
+ ...(cadenceGaps.length > 0
62
+ ? {
63
+ cadenceGapCount: cadenceGaps.length,
64
+ longestCadenceGapMs: round(Math.max(...cadenceGaps.map((sample) => sample.durationMs))),
65
+ }
66
+ : {}),
67
+ ...(frameBudgetMs
68
+ ? {
69
+ frameBudgetMs: round(frameBudgetMs),
70
+ refreshRateHz: round(1000 / frameBudgetMs),
71
+ }
72
+ : {}),
73
+ frameCount: durations.length,
74
+ ...(frameBudgetOutcomes.length === validSamples.length
75
+ ? {
76
+ overBudgetFrameCount: missedFrameBudgetCount,
77
+ overBudgetFramePercent: round((missedFrameBudgetCount / validSamples.length) * 100),
78
+ }
79
+ : {}),
80
+ longestFrameMs: round(durations.at(-1) ?? 0),
81
+ p50FrameMs: round(percentile(durations, 0.5)),
82
+ p95FrameMs: round(percentile(durations, 0.95)),
83
+ p99FrameMs: round(percentile(durations, 0.99)),
84
+ };
85
+ }
86
+ function commonFrameBudget(samples) {
87
+ const budgets = samples
88
+ .map((sample) => sample.frameBudgetMs)
89
+ .filter((value) => value !== undefined && Number.isFinite(value) && value > 0)
90
+ .sort((first, second) => first - second);
91
+ return budgets.length > 0 ? percentile(budgets, 0.5) : undefined;
92
+ }
93
+ function activeRenderingIntervals(samples, frameBudgetMs) {
94
+ if (samples.every((sample) => sample.cadenceInterval === true)) {
95
+ return samples
96
+ .map((sample) => sample.durationMs)
97
+ .filter((durationMs) => Number.isFinite(durationMs) && durationMs > 0 && durationMs <= frameBudgetMs * 3.01);
98
+ }
99
+ const ordered = [...samples]
100
+ .map((sample) => ({
101
+ ...sample,
102
+ startedAtEpochMs: sample.startedAtEpochMs ?? sample.completedAtEpochMs - sample.durationMs,
103
+ }))
104
+ .sort((first, second) => first.startedAtEpochMs - second.startedAtEpochMs);
105
+ const intervals = [];
106
+ for (let index = 1; index < ordered.length; index += 1) {
107
+ const previous = ordered[index - 1];
108
+ const current = ordered[index];
109
+ if (!previous || !current)
110
+ continue;
111
+ const interval = current.startedAtEpochMs - previous.startedAtEpochMs;
112
+ if (!Number.isFinite(interval) || interval <= 0)
113
+ continue;
114
+ const continuous = interval <= frameBudgetMs * 3.01;
115
+ const explainedBySlowFrame = Math.max(previous.durationMs, current.durationMs) >= interval - frameBudgetMs * 1.01;
116
+ if (continuous || explainedBySlowFrame)
117
+ intervals.push(interval);
118
+ }
119
+ return intervals;
120
+ }
121
+ function percentile(sorted, quantile) {
122
+ if (sorted.length === 1)
123
+ return sorted[0] ?? 0;
124
+ const position = (sorted.length - 1) * quantile;
125
+ const lower = Math.floor(position);
126
+ const upper = Math.ceil(position);
127
+ const lowerValue = sorted[lower] ?? 0;
128
+ const upperValue = sorted[upper] ?? lowerValue;
129
+ return lowerValue + (upperValue - lowerValue) * (position - lower);
130
+ }
131
+ function round(value) {
132
+ return Math.round(value * 1000) / 1000;
133
+ }
134
+ //# sourceMappingURL=frame-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-metrics.js","sourceRoot":"","sources":["../src/frame-metrics.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  export { createAgentDeviceUiTransport, NATIVE_UI_ACTIONS } from './agent-device-ui-transport.js';
2
2
  export { runAdapterRnCli } from './cli.js';
3
3
  export { BRIDGE_HUD_PATH, BRIDGE_INDEX_PATH, BRIDGE_PROVIDER_PATH, DEFAULT_EXPO_RECIPE_MANIFEST_PATH, DEFAULT_EXPO_RECIPE_PATH, } from './constants.js';
4
+ export { type ConnectedDevice, type DeviceDiscoveryError, type DevicePlatform, findAvailableIosSimulatorById, listConnectedDevices, } from './devices.js';
4
5
  export { runExpoRecipeDoctor } from './doctor.js';
6
+ export { type FingerprintCheck, type FingerprintStatus } from './fingerprint-baseline.js';
7
+ export { type FrameMetricSummary, type FrameSample, summarizeFrames } from './frame-metrics.js';
8
+ export { metroEnvCheck, metroEnvFingerprint, type MetroEnvInputs, recordMetroEnvBaseline, } from './metro-env.js';
5
9
  export { createRedactingCoreAdapters } from './redaction.js';
6
10
  export { resolveExpoRecordingTarget, runExpoRecipeDocument, validateExpoRecipeDocument, } from './runner.js';
7
11
  export { installExpoRecipeScaffold, packageScripts } from './scaffold.js';
12
+ export { recordSourceBaseline, sourceCheck, sourceFingerprint, type SourceInputs, } from './source-freshness.js';
13
+ export { clearMobileToolPathCache, type MobileTool, mobileToolEnvName, type MobileToolPaths, mobileToolRecovery, resolveAndExportMobileToolPaths, resolveMobileToolPath, } from './tool-paths.js';
14
+ export { ANDROID_RECORDING_TARGET_PREFIX, androidScreenrecordArgs, createAndroidVideoRecorder, createIosSimulatorVideoRecorder, IOS_SIMULATOR_RECORDING_TARGET_PREFIX, } from './video-recorder.js';
8
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,cAAc,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,wBAAwB,EACxB,KAAK,UAAU,EACf,iBAAiB,EACjB,KAAK,eAAe,EACpB,kBAAkB,EAClB,+BAA+B,EAC/B,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,qCAAqC,GACtC,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,14 @@
1
1
  export { createAgentDeviceUiTransport, NATIVE_UI_ACTIONS } from './agent-device-ui-transport.js';
2
2
  export { runAdapterRnCli } from './cli.js';
3
3
  export { BRIDGE_HUD_PATH, BRIDGE_INDEX_PATH, BRIDGE_PROVIDER_PATH, DEFAULT_EXPO_RECIPE_MANIFEST_PATH, DEFAULT_EXPO_RECIPE_PATH, } from './constants.js';
4
+ export { findAvailableIosSimulatorById, listConnectedDevices, } from './devices.js';
4
5
  export { runExpoRecipeDoctor } from './doctor.js';
6
+ export { summarizeFrames } from './frame-metrics.js';
7
+ export { metroEnvCheck, metroEnvFingerprint, recordMetroEnvBaseline, } from './metro-env.js';
5
8
  export { createRedactingCoreAdapters } from './redaction.js';
6
9
  export { resolveExpoRecordingTarget, runExpoRecipeDocument, validateExpoRecipeDocument, } from './runner.js';
7
10
  export { installExpoRecipeScaffold, packageScripts } from './scaffold.js';
11
+ export { recordSourceBaseline, sourceCheck, sourceFingerprint, } from './source-freshness.js';
12
+ export { clearMobileToolPathCache, mobileToolEnvName, mobileToolRecovery, resolveAndExportMobileToolPaths, resolveMobileToolPath, } from './tool-paths.js';
13
+ export { ANDROID_RECORDING_TARGET_PREFIX, androidScreenrecordArgs, createAndroidVideoRecorder, createIosSimulatorVideoRecorder, IOS_SIMULATOR_RECORDING_TARGET_PREFIX, } from './video-recorder.js';
8
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAIL,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAA6C,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,wBAAwB,EAExB,iBAAiB,EAEjB,kBAAkB,EAClB,+BAA+B,EAC/B,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,qCAAqC,GACtC,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type FingerprintCheck } from './fingerprint-baseline.js';
2
+ export interface MetroEnvInputs {
3
+ /** Env files relative to the project root, hashed in order (absent files hash as absent). */
4
+ files: readonly string[];
5
+ /** Process env names, hashed in order. */
6
+ env: readonly string[];
7
+ }
8
+ export declare function metroEnvFingerprint(projectRoot: string, inputs: MetroEnvInputs): string;
9
+ export declare function metroEnvCheck(projectRoot: string, inputs: MetroEnvInputs, markerPath: string): FingerprintCheck;
10
+ export declare function recordMetroEnvBaseline(projectRoot: string, inputs: MetroEnvInputs, markerPath: string, expectedFingerprint: string): boolean;
11
+ //# sourceMappingURL=metro-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-env.d.ts","sourceRoot":"","sources":["../src/metro-env.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,cAAc;IAC7B,6FAA6F;IAC7F,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,0CAA0C;IAC1C,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAavF;AAED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,MAAM,GACjB,gBAAgB,CAElB;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,MAAM,EAClB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAIT"}
@@ -0,0 +1,29 @@
1
+ // Fingerprint of the environment a Metro bundle was built with: env files in
2
+ // the project plus selected process env values. The project supplies both lists.
3
+ import { createHash } from 'node:crypto';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { checkFingerprintBaseline, recordFingerprintBaseline, } from './fingerprint-baseline.js';
7
+ export function metroEnvFingerprint(projectRoot, inputs) {
8
+ const hash = createHash('sha256');
9
+ for (const relative of inputs.files) {
10
+ const absolute = path.join(projectRoot, relative);
11
+ hash.update(`${relative}\0`);
12
+ if (fs.existsSync(absolute))
13
+ hash.update(fs.readFileSync(absolute));
14
+ else
15
+ hash.update('<absent>');
16
+ hash.update('\0');
17
+ }
18
+ for (const name of inputs.env) {
19
+ hash.update(`${name}\0${process.env[name] ?? '<absent>'}\0`);
20
+ }
21
+ return hash.digest('hex');
22
+ }
23
+ export function metroEnvCheck(projectRoot, inputs, markerPath) {
24
+ return checkFingerprintBaseline(markerPath, metroEnvFingerprint(projectRoot, inputs));
25
+ }
26
+ export function recordMetroEnvBaseline(projectRoot, inputs, markerPath, expectedFingerprint) {
27
+ return recordFingerprintBaseline(markerPath, expectedFingerprint, () => metroEnvFingerprint(projectRoot, inputs));
28
+ }
29
+ //# sourceMappingURL=metro-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-env.js","sourceRoot":"","sources":["../src/metro-env.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iFAAiF;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,wBAAwB,EAExB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AASnC,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,MAAsB;IAC7E,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;;YAC/D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,KAAK,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,WAAmB,EACnB,MAAsB,EACtB,UAAkB;IAElB,OAAO,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,WAAmB,EACnB,MAAsB,EACtB,UAAkB,EAClB,mBAA2B;IAE3B,OAAO,yBAAyB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,EAAE,CACrE,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,CACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type FingerprintCheck } from './fingerprint-baseline.js';
2
+ export interface SourceInputs {
3
+ /** Source files and directories relative to the project root. */
4
+ paths: readonly string[];
5
+ /** Env files relative to the project root (absent files hash as absent). */
6
+ envFiles: readonly string[];
7
+ }
8
+ export declare function sourceFingerprint(projectRoot: string, inputs: SourceInputs): string;
9
+ export declare function sourceCheck(projectRoot: string, inputs: SourceInputs, markerPath: string): FingerprintCheck;
10
+ export declare function recordSourceBaseline(projectRoot: string, inputs: SourceInputs, markerPath: string, expectedFingerprint: string): boolean;
11
+ //# sourceMappingURL=source-freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-freshness.d.ts","sourceRoot":"","sources":["../src/source-freshness.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAwCnF;AAED,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,GACjB,gBAAgB,CAElB;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAIT"}