@farmslot/adapter-rn 0.17.1 → 0.19.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ All notable changes to `@farmslot/adapter-rn` (published as `@farmslot/expo-reci
6
6
 
7
7
  - Active-development baseline; add user-facing changes here before release or package publication.
8
8
 
9
+ ## 0.19.0 - 2026-10-08
10
+
11
+ - Add `metroBundleProgress(line)`: the percent and module counts of a Metro or Expo bundle progress line, ready for a stage's `progress`.
12
+ - Publish with protocol 0.34.0 and recipe-runner 0.26.0.
13
+
14
+ ## 0.18.0 - 2026-10-06
15
+
16
+ - **Breaking:** `summarizeFrames`, `FrameSample` and `FrameMetricSummary` are no longer exported from the index. They moved to `@farmslot/recipe-runner/runtime/cdp-trace`, unchanged; import them from there.
17
+ - Publish with protocol 0.34.0 and recipe-runner 0.26.0.
18
+
9
19
  ## 0.17.1 - 2026-10-06
10
20
 
11
21
  - Publish with protocol 0.34.0 and recipe-runner 0.25.0 so consumers share one recipe-runner copy.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Public docs: <https://farmslot.io/docs/guides/adapter-rn>
19
19
  | `bridge-runtime/bridge-core.cjs` | Generic bridge CLI (`runBridgeCli`); a host preset adds its commands, routes and recovery hints. |
20
20
  | `metro/` | Metro config wrapper, detached launcher and log generation/coalescing helpers. |
21
21
  | `src/tool-paths.ts`, `src/devices.ts` | adb/idb discovery (`RECIPE_RN_ADB_PATH`/`RECIPE_RN_IDB_PATH`) and connected-device listing. |
22
- | `src/video-recorder.ts`, `src/frame-metrics.ts` | Device video recorders and frame-timing summaries. |
22
+ | `src/video-recorder.ts` | Device video recorders. |
23
23
  | `src/metro-env.ts`, `src/source-freshness.ts`, `src/fingerprint-baseline.ts` | Bundle-input fingerprints with recorded baselines; the project supplies the inputs. |
24
24
 
25
25
  ## Relationship to the harness
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ export { BRIDGE_HUD_PATH, BRIDGE_INDEX_PATH, BRIDGE_PROVIDER_PATH, DEFAULT_EXPO_
4
4
  export { type ConnectedDevice, type DeviceDiscoveryError, type DevicePlatform, findAvailableIosSimulatorById, listConnectedDevices, } from './devices.js';
5
5
  export { runExpoRecipeDoctor } from './doctor.js';
6
6
  export { type FingerprintCheck, type FingerprintStatus } from './fingerprint-baseline.js';
7
- export { type FrameMetricSummary, type FrameSample, summarizeFrames } from './frame-metrics.js';
8
7
  export { metroEnvCheck, metroEnvFingerprint, type MetroEnvInputs, recordMetroEnvBaseline, } from './metro-env.js';
8
+ export { type MetroBundleProgress, metroBundleProgress } from './metro-progress.js';
9
9
  export { createRedactingCoreAdapters } from './redaction.js';
10
10
  export { resolveExpoRecordingTarget, runExpoRecipeDocument, validateExpoRecipeDocument, } from './runner.js';
11
11
  export { installExpoRecipeScaffold, packageScripts } from './scaffold.js';
@@ -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,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"}
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,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,cAAc,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACpF,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
@@ -3,8 +3,8 @@ 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
4
  export { findAvailableIosSimulatorById, listConnectedDevices, } from './devices.js';
5
5
  export { runExpoRecipeDoctor } from './doctor.js';
6
- export { summarizeFrames } from './frame-metrics.js';
7
6
  export { metroEnvCheck, metroEnvFingerprint, recordMetroEnvBaseline, } from './metro-env.js';
7
+ export { metroBundleProgress } from './metro-progress.js';
8
8
  export { createRedactingCoreAdapters } from './redaction.js';
9
9
  export { resolveExpoRecordingTarget, runExpoRecipeDocument, validateExpoRecipeDocument, } from './runner.js';
10
10
  export { installExpoRecipeScaffold, packageScripts } from './scaffold.js';
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,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"}
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,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAA4B,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACpF,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,10 @@
1
+ export interface MetroBundleProgress {
2
+ message: 'bundling';
3
+ percent: number;
4
+ current?: number;
5
+ total?: number;
6
+ unit?: 'modules';
7
+ }
8
+ /** The progress a Metro bundle line shows, or null for any other line. */
9
+ export declare function metroBundleProgress(line: string): MetroBundleProgress | null;
10
+ //# sourceMappingURL=metro-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-progress.d.ts","sourceRoot":"","sources":["../src/metro-progress.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAY5E"}
@@ -0,0 +1,22 @@
1
+ // Metro's bundle progress as a setup stage reports it. Metro and the Expo CLI
2
+ // print `iOS ./index.js ▓▓▓▓░░ 61.3% (4210/6900)` while bundling, and
3
+ // coalesce-metro-log keeps those lines in the Metro log; a caller tailing that
4
+ // log passes each line here and hands the result to its stage handle.
5
+ const BUNDLE_PROGRESS = /^\s*(?:iOS|Android)\b.*?(\d{1,3}(?:\.\d+)?)%(?:\s*\(\s*(\d+)\s*\/\s*(\d+)\s*\))?/u;
6
+ /** The progress a Metro bundle line shows, or null for any other line. */
7
+ export function metroBundleProgress(line) {
8
+ const match = BUNDLE_PROGRESS.exec(line);
9
+ if (!match)
10
+ return null;
11
+ const percent = Number(match[1]);
12
+ if (match[2] === undefined || match[3] === undefined)
13
+ return { message: 'bundling', percent };
14
+ return {
15
+ message: 'bundling',
16
+ percent,
17
+ current: Number(match[2]),
18
+ total: Number(match[3]),
19
+ unit: 'modules',
20
+ };
21
+ }
22
+ //# sourceMappingURL=metro-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-progress.js","sourceRoot":"","sources":["../src/metro-progress.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sEAAsE;AACtE,+EAA+E;AAC/E,sEAAsE;AAEtE,MAAM,eAAe,GACnB,mFAAmF,CAAC;AAUtF,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAC9F,OAAO;QACL,OAAO,EAAE,UAAU;QACnB,OAAO;QACP,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,EAAE,SAAS;KAChB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/adapter-rn",
3
- "version": "0.17.1",
3
+ "version": "0.19.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@farmslot/protocol": "0.34.0",
46
- "@farmslot/recipe-runner": "0.25.0",
46
+ "@farmslot/recipe-runner": "0.26.0",
47
47
  "pngjs": "^7.0.0",
48
48
  "ws": "^8.18.0"
49
49
  },
@@ -1,26 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,134 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"frame-metrics.js","sourceRoot":"","sources":["../src/frame-metrics.ts"],"names":[],"mappings":"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"}