@buoy-gg/js-top 7.0.3
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/LICENSE +58 -0
- package/README.md +56 -0
- package/lib/commonjs/index.js +97 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/js-top/components/BusySparkline.js +56 -0
- package/lib/commonjs/js-top/components/BusySparkline.js.map +1 -0
- package/lib/commonjs/js-top/components/JsTopHudOverlay.js +79 -0
- package/lib/commonjs/js-top/components/JsTopHudOverlay.js.map +1 -0
- package/lib/commonjs/js-top/components/JsTopModal.js +347 -0
- package/lib/commonjs/js-top/components/JsTopModal.js.map +1 -0
- package/lib/commonjs/js-top/components/TaskDetailView.js +329 -0
- package/lib/commonjs/js-top/components/TaskDetailView.js.map +1 -0
- package/lib/commonjs/js-top/components/TaskTable.js +360 -0
- package/lib/commonjs/js-top/components/TaskTable.js.map +1 -0
- package/lib/commonjs/js-top/engine/JsTopController.js +350 -0
- package/lib/commonjs/js-top/engine/JsTopController.js.map +1 -0
- package/lib/commonjs/js-top/engine/aggregator.js +148 -0
- package/lib/commonjs/js-top/engine/aggregator.js.map +1 -0
- package/lib/commonjs/js-top/engine/busyProbe.js +101 -0
- package/lib/commonjs/js-top/engine/busyProbe.js.map +1 -0
- package/lib/commonjs/js-top/engine/frameStack.js +133 -0
- package/lib/commonjs/js-top/engine/frameStack.js.map +1 -0
- package/lib/commonjs/js-top/engine/longtasks.js +141 -0
- package/lib/commonjs/js-top/engine/longtasks.js.map +1 -0
- package/lib/commonjs/js-top/engine/now.js +38 -0
- package/lib/commonjs/js-top/engine/now.js.map +1 -0
- package/lib/commonjs/js-top/engine/originRegistry.js +402 -0
- package/lib/commonjs/js-top/engine/originRegistry.js.map +1 -0
- package/lib/commonjs/js-top/engine/patches/bridge.js +60 -0
- package/lib/commonjs/js-top/engine/patches/bridge.js.map +1 -0
- package/lib/commonjs/js-top/engine/patches/microtasks.js +27 -0
- package/lib/commonjs/js-top/engine/patches/microtasks.js.map +1 -0
- package/lib/commonjs/js-top/engine/patches/promises.js +65 -0
- package/lib/commonjs/js-top/engine/patches/promises.js.map +1 -0
- package/lib/commonjs/js-top/engine/patches/timers.js +66 -0
- package/lib/commonjs/js-top/engine/patches/timers.js.map +1 -0
- package/lib/commonjs/js-top/engine/state.js +63 -0
- package/lib/commonjs/js-top/engine/state.js.map +1 -0
- package/lib/commonjs/js-top/engine/symbolicate.js +95 -0
- package/lib/commonjs/js-top/engine/symbolicate.js.map +1 -0
- package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js +74 -0
- package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js.map +1 -0
- package/lib/commonjs/js-top/types/index.js +46 -0
- package/lib/commonjs/js-top/types/index.js.map +1 -0
- package/lib/commonjs/js-top/utils/preferences.js +39 -0
- package/lib/commonjs/js-top/utils/preferences.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +75 -0
- package/lib/commonjs/preset.js.map +1 -0
- package/lib/module/index.js +47 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/js-top/components/BusySparkline.js +52 -0
- package/lib/module/js-top/components/BusySparkline.js.map +1 -0
- package/lib/module/js-top/components/JsTopHudOverlay.js +75 -0
- package/lib/module/js-top/components/JsTopHudOverlay.js.map +1 -0
- package/lib/module/js-top/components/JsTopModal.js +343 -0
- package/lib/module/js-top/components/JsTopModal.js.map +1 -0
- package/lib/module/js-top/components/TaskDetailView.js +325 -0
- package/lib/module/js-top/components/TaskDetailView.js.map +1 -0
- package/lib/module/js-top/components/TaskTable.js +353 -0
- package/lib/module/js-top/components/TaskTable.js.map +1 -0
- package/lib/module/js-top/engine/JsTopController.js +347 -0
- package/lib/module/js-top/engine/JsTopController.js.map +1 -0
- package/lib/module/js-top/engine/aggregator.js +136 -0
- package/lib/module/js-top/engine/aggregator.js.map +1 -0
- package/lib/module/js-top/engine/busyProbe.js +94 -0
- package/lib/module/js-top/engine/busyProbe.js.map +1 -0
- package/lib/module/js-top/engine/frameStack.js +126 -0
- package/lib/module/js-top/engine/frameStack.js.map +1 -0
- package/lib/module/js-top/engine/longtasks.js +133 -0
- package/lib/module/js-top/engine/longtasks.js.map +1 -0
- package/lib/module/js-top/engine/now.js +33 -0
- package/lib/module/js-top/engine/now.js.map +1 -0
- package/lib/module/js-top/engine/originRegistry.js +388 -0
- package/lib/module/js-top/engine/originRegistry.js.map +1 -0
- package/lib/module/js-top/engine/patches/bridge.js +56 -0
- package/lib/module/js-top/engine/patches/bridge.js.map +1 -0
- package/lib/module/js-top/engine/patches/microtasks.js +23 -0
- package/lib/module/js-top/engine/patches/microtasks.js.map +1 -0
- package/lib/module/js-top/engine/patches/promises.js +62 -0
- package/lib/module/js-top/engine/patches/promises.js.map +1 -0
- package/lib/module/js-top/engine/patches/timers.js +62 -0
- package/lib/module/js-top/engine/patches/timers.js.map +1 -0
- package/lib/module/js-top/engine/state.js +54 -0
- package/lib/module/js-top/engine/state.js.map +1 -0
- package/lib/module/js-top/engine/symbolicate.js +91 -0
- package/lib/module/js-top/engine/symbolicate.js.map +1 -0
- package/lib/module/js-top/sync/jsTopSyncAdapter.js +70 -0
- package/lib/module/js-top/sync/jsTopSyncAdapter.js.map +1 -0
- package/lib/module/js-top/types/index.js +42 -0
- package/lib/module/js-top/types/index.js.map +1 -0
- package/lib/module/js-top/utils/preferences.js +34 -0
- package/lib/module/js-top/utils/preferences.js.map +1 -0
- package/lib/module/preset.js +71 -0
- package/lib/module/preset.js.map +1 -0
- package/lib/typescript/index.d.ts +21 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/js-top/components/BusySparkline.d.ts +8 -0
- package/lib/typescript/js-top/components/BusySparkline.d.ts.map +1 -0
- package/lib/typescript/js-top/components/JsTopHudOverlay.d.ts +8 -0
- package/lib/typescript/js-top/components/JsTopHudOverlay.d.ts.map +1 -0
- package/lib/typescript/js-top/components/JsTopModal.d.ts +39 -0
- package/lib/typescript/js-top/components/JsTopModal.d.ts.map +1 -0
- package/lib/typescript/js-top/components/TaskDetailView.d.ts +15 -0
- package/lib/typescript/js-top/components/TaskDetailView.d.ts.map +1 -0
- package/lib/typescript/js-top/components/TaskTable.d.ts +38 -0
- package/lib/typescript/js-top/components/TaskTable.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/JsTopController.d.ts +78 -0
- package/lib/typescript/js-top/engine/JsTopController.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/__tests__/engine.test.d.ts +9 -0
- package/lib/typescript/js-top/engine/__tests__/engine.test.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/aggregator.d.ts +33 -0
- package/lib/typescript/js-top/engine/aggregator.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/busyProbe.d.ts +25 -0
- package/lib/typescript/js-top/engine/busyProbe.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/frameStack.d.ts +44 -0
- package/lib/typescript/js-top/engine/frameStack.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/longtasks.d.ts +37 -0
- package/lib/typescript/js-top/engine/longtasks.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/now.d.ts +9 -0
- package/lib/typescript/js-top/engine/now.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/originRegistry.d.ts +82 -0
- package/lib/typescript/js-top/engine/originRegistry.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/patches/bridge.d.ts +17 -0
- package/lib/typescript/js-top/engine/patches/bridge.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/patches/microtasks.d.ts +6 -0
- package/lib/typescript/js-top/engine/patches/microtasks.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/patches/promises.d.ts +18 -0
- package/lib/typescript/js-top/engine/patches/promises.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/patches/timers.d.ts +11 -0
- package/lib/typescript/js-top/engine/patches/timers.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/state.d.ts +35 -0
- package/lib/typescript/js-top/engine/state.d.ts.map +1 -0
- package/lib/typescript/js-top/engine/symbolicate.d.ts +16 -0
- package/lib/typescript/js-top/engine/symbolicate.d.ts.map +1 -0
- package/lib/typescript/js-top/sync/jsTopSyncAdapter.d.ts +43 -0
- package/lib/typescript/js-top/sync/jsTopSyncAdapter.d.ts.map +1 -0
- package/lib/typescript/js-top/types/index.d.ts +130 -0
- package/lib/typescript/js-top/types/index.d.ts.map +1 -0
- package/lib/typescript/js-top/utils/preferences.d.ts +13 -0
- package/lib/typescript/js-top/utils/preferences.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +49 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/index.tsx +69 -0
- package/src/js-top/components/BusySparkline.tsx +59 -0
- package/src/js-top/components/JsTopHudOverlay.tsx +78 -0
- package/src/js-top/components/JsTopModal.tsx +421 -0
- package/src/js-top/components/TaskDetailView.tsx +349 -0
- package/src/js-top/components/TaskTable.tsx +365 -0
- package/src/js-top/engine/JsTopController.ts +401 -0
- package/src/js-top/engine/__tests__/engine.test.ts +337 -0
- package/src/js-top/engine/aggregator.ts +148 -0
- package/src/js-top/engine/busyProbe.ts +100 -0
- package/src/js-top/engine/frameStack.ts +142 -0
- package/src/js-top/engine/longtasks.ts +137 -0
- package/src/js-top/engine/now.ts +33 -0
- package/src/js-top/engine/originRegistry.ts +495 -0
- package/src/js-top/engine/patches/bridge.ts +69 -0
- package/src/js-top/engine/patches/microtasks.ts +25 -0
- package/src/js-top/engine/patches/promises.ts +57 -0
- package/src/js-top/engine/patches/timers.ts +80 -0
- package/src/js-top/engine/state.ts +66 -0
- package/src/js-top/engine/symbolicate.ts +109 -0
- package/src/js-top/sync/jsTopSyncAdapter.ts +72 -0
- package/src/js-top/types/index.ts +144 -0
- package/src/js-top/utils/preferences.ts +35 -0
- package/src/preset.tsx +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsTopController.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/JsTopController.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,UAAU,CAAC;AAyBlB,KAAK,kBAAkB,GAAG,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;AAC5D,KAAK,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AACpD,KAAK,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D,CAAC;AAEF,cAAM,mBAAmB;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,KAAK,CAKX;IACF,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,kBAAkB,CAAgC;IAC1D;mEAC+D;IAC/D,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,OAAO,CAAC,mBAAmB,CAA8B;IACzD,OAAO,CAAC,UAAU,CAAyB;;IAW3C,SAAS,CAAC,EAAE,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAU7C,gBAAgB,CAAC,EAAE,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAQnD;6EACyE;IACzE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAiB7B,SAAS,IAAI,OAAO;IAIpB;qEACiE;IACjE,iBAAiB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAMpC,gBAAgB,IAAI,OAAO;IAI3B,SAAS,IAAI,WAAW;IAOxB,KAAK,IAAI,IAAI;IAQb,MAAM,IAAI,IAAI;IAUd,KAAK,IAAI,IAAI;IAab,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvC,WAAW,IAAI,aAAa;IAI5B;;;;OAIG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAuCtD,4DAA4D;IAC5D,qBAAqB,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI;IAO/D,wBAAwB,CAAC,EAAE,EAAE,MAAM,aAAa,CAAC,WAAW,CAAC,GAAG,IAAI;IAIpE,2BAA2B,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI;IAMpD,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,WAAW;IA+BnB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,aAAa;IA6DrB,OAAO,CAAC,YAAY;IAcpB,kDAAkD;IAClD,cAAc,IAAI,OAAO;CAG1B;AAED,eAAO,MAAM,eAAe,qBAA4B,CAAC;AACzD,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the js-top engine's pure accounting core.
|
|
3
|
+
*
|
|
4
|
+
* Same self-contained harness pattern as perf-monitor's __tests__: the repo
|
|
5
|
+
* has no Jest, so run with `npx tsx <path>`; `__tests__` is excluded from
|
|
6
|
+
* the publish build.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=engine.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.test.d.ts","sourceRoot":"","sources":["../../../../../src/js-top/engine/__tests__/engine.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global per-bucket accounting: the engine's clock is divided into 250ms
|
|
3
|
+
* buckets (epochs). Each bucket tracks measured busy ms (from the probe) and
|
|
4
|
+
* attributed ms (from wrapped tasks); `unattributed = busy − attributed` per
|
|
5
|
+
* bucket is what keeps the table honest when work enters the thread through
|
|
6
|
+
* a path we can't wrap (bridgeless events, React commits, async/await).
|
|
7
|
+
*
|
|
8
|
+
* Rings are epoch-stamped parallel arrays: a slot is only valid when its
|
|
9
|
+
* stamp matches the epoch being read, so stale slots cost nothing to skip
|
|
10
|
+
* and nothing to zero eagerly.
|
|
11
|
+
*/
|
|
12
|
+
export declare function epochOf(t: number): number;
|
|
13
|
+
/** Book probe-measured busy time over [start, end], capped per bucket. */
|
|
14
|
+
export declare function bookBusyRange(start: number, end: number): void;
|
|
15
|
+
/**
|
|
16
|
+
* Book a task's exclusive ms, spread proportionally over its wall span.
|
|
17
|
+
* (Exclusive time isn't contiguous when children interleave; proportional
|
|
18
|
+
* spread is exact at 250ms-bucket granularity for all practical tasks.)
|
|
19
|
+
*/
|
|
20
|
+
export declare function bookAttributedRange(start: number, end: number, exclusiveMs: number): void;
|
|
21
|
+
/** Book a reported longtask span (for history display only). */
|
|
22
|
+
export declare function bookLongtaskRange(start: number, end: number): void;
|
|
23
|
+
export declare function windowBusyMs(nowT: number): number;
|
|
24
|
+
export declare function windowAttributedMs(nowT: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Per-bucket UNATTRIBUTED ms (busy − attributed), oldest→newest over the
|
|
27
|
+
* rolling window — the "system" row's activity trend for the detail view.
|
|
28
|
+
*/
|
|
29
|
+
export declare function windowResidualBuckets(nowT: number): number[];
|
|
30
|
+
/** Per-bucket busy%, oldest→newest, over the full 30s history ring. */
|
|
31
|
+
export declare function busyHistory(nowT: number): number[];
|
|
32
|
+
export declare function resetAggregator(): void;
|
|
33
|
+
//# sourceMappingURL=aggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAsCD,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GAClB,IAAI,CAON;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAIlE;AAYD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAY5D;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAelD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Busy probe — measures true JS-thread occupancy from timer-gap inflation.
|
|
3
|
+
*
|
|
4
|
+
* A 16ms heartbeat (created with the PRE-PATCH setInterval so the probe never
|
|
5
|
+
* appears in its own table) can only fire when the thread yields; any gap
|
|
6
|
+
* beyond the calibrated idle baseline is time the thread was busy. This is
|
|
7
|
+
* the same physical signal as perf-monitor's stall-aware sampler, at higher
|
|
8
|
+
* frequency: multi-second stalls simply arrive as one huge gap and are booked
|
|
9
|
+
* as fully-busy buckets by bookBusyRange (the backfill falls out of the
|
|
10
|
+
* range-distribution math; no separate synthetic-sample pass needed).
|
|
11
|
+
*
|
|
12
|
+
* Calibration: the nominal 16ms is never what a real device delivers at
|
|
13
|
+
* idle. We track a rolling min gap (3 one-second slots) and subtract THAT,
|
|
14
|
+
* otherwise idle devices read 10–20% phantom busy.
|
|
15
|
+
*
|
|
16
|
+
* AppState transitions also pause JS timers, so the controller flags them
|
|
17
|
+
* via suppressNextGap() — same trick as PerfMonitorController; AppState
|
|
18
|
+
* events arrive on the JS thread, so a genuine stall can never set the flag.
|
|
19
|
+
*/
|
|
20
|
+
export declare function startBusyProbe(): void;
|
|
21
|
+
export declare function stopBusyProbe(): void;
|
|
22
|
+
export declare function suppressNextGap(): void;
|
|
23
|
+
/** Test-only. */
|
|
24
|
+
export declare function debugBaseline(): number;
|
|
25
|
+
//# sourceMappingURL=busyProbe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"busyProbe.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/busyProbe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAsDH,wBAAgB,cAAc,IAAI,IAAI,CAUrC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,iBAAiB;AACjB,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wrapTask — the single wrapper every patched entry point uses, plus the
|
|
3
|
+
* frame stack that makes nested wrapped calls book EXCLUSIVE time.
|
|
4
|
+
*
|
|
5
|
+
* The no-double-count rule: every wrapper at any depth books
|
|
6
|
+
* `(end − start) − childrenMs` to its own origin and adds its TOTAL to its
|
|
7
|
+
* parent frame's childrenMs. Thread occupancy is then the sum of exclusive
|
|
8
|
+
* time at all depths, which equals the union of wrapped wall intervals —
|
|
9
|
+
* nesting (e.g. rAF callbacks fired inside a wrapped bridge call-in) can
|
|
10
|
+
* never inflate totals.
|
|
11
|
+
*
|
|
12
|
+
* Naming: exported/inner functions carry a `buoyJsTop` prefix on purpose —
|
|
13
|
+
* Hermes dev stacks only show function names + bundle offsets, and the
|
|
14
|
+
* registry's stack parser filters engine frames by that prefix.
|
|
15
|
+
*/
|
|
16
|
+
import type { TaskApi } from "../types";
|
|
17
|
+
export interface CompletedInterval {
|
|
18
|
+
originKey: string;
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
}
|
|
22
|
+
/** Recent depth-0 wrapped intervals, unordered — consumers scan all slots. */
|
|
23
|
+
export declare function recentIntervals(): (CompletedInterval | null)[];
|
|
24
|
+
type AnyFn = (...args: any[]) => any;
|
|
25
|
+
/**
|
|
26
|
+
* Wrap a callback at schedule time. ALWAYS wraps once patches are installed
|
|
27
|
+
* (installation itself only happens on first engine start): a long-lived
|
|
28
|
+
* callback — the classic forgotten setInterval — must stay attributable
|
|
29
|
+
* even when it was scheduled while the engine was off, or after clear()
|
|
30
|
+
* deleted its origin record. Identity is therefore resolved eagerly at
|
|
31
|
+
* schedule time when possible (best stack context) and re-resolved lazily
|
|
32
|
+
* at fire time otherwise. Inactive-engine cost per fire: one boolean.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buoyJsTopWrapTask<T extends AnyFn>(fn: T, api: TaskApi): T;
|
|
35
|
+
/**
|
|
36
|
+
* Run a thunk as a named task frame — for entry points that aren't
|
|
37
|
+
* schedule-a-callback shaped (e.g. bridge call-ins, where the "origin" is
|
|
38
|
+
* the module.method being invoked right now).
|
|
39
|
+
*/
|
|
40
|
+
export declare function buoyJsTopRunAs<T>(api: TaskApi, name: string, thunk: () => T): T;
|
|
41
|
+
/** Test-only: current nesting depth. */
|
|
42
|
+
export declare function debugDepth(): number;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=frameStack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameStack.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/frameStack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAqBxC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAOD,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,EAAE,CAE9D;AAGD,KAAK,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAmCrC;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,CAqBzE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,GACb,CAAC,CAIH;AAED,wCAAwC;AACxC,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Freeze tracking. RN ships a real `PerformanceObserver('longtask')` (C++
|
|
3
|
+
* TurboModule, present in Expo Go and release): entries fire for any task
|
|
4
|
+
* that blocks the JS event loop ≥ 50ms — what a user feels as a dropped tap
|
|
5
|
+
* or stuttered animation — but carry NO attribution. We supply it: each
|
|
6
|
+
* entry is overlap-matched against the ring of recent depth-0 wrapped
|
|
7
|
+
* intervals; the biggest overlap names the offender.
|
|
8
|
+
*
|
|
9
|
+
* Freeze data doesn't get its own UI section — it decorates the places you
|
|
10
|
+
* already look: per-row ⚠ badges in the task table and a summary chip in
|
|
11
|
+
* the header, both fed by getFreezeStats() (trailing 60s window). The raw
|
|
12
|
+
* entry list is still exported for the desktop panel and MCP payloads.
|
|
13
|
+
*
|
|
14
|
+
* The observer installs once and stays connected (uninstalling/reinstalling
|
|
15
|
+
* observers has its own churn); its handler early-outs when the engine is
|
|
16
|
+
* inactive — longtasks only fire on 50ms+ blocks, so the idle cost is nil.
|
|
17
|
+
*/
|
|
18
|
+
import type { JsTopLongtask, JsTopTiers } from "../types";
|
|
19
|
+
/** Per-origin key for freezes we couldn't attribute to a wrapped callback. */
|
|
20
|
+
export declare const SYSTEM_FREEZE_KEY = "unattributed";
|
|
21
|
+
export interface FreezeStats {
|
|
22
|
+
/** Freezes in the trailing window. */
|
|
23
|
+
count: number;
|
|
24
|
+
worstMs: number;
|
|
25
|
+
/** Keyed by origin key (SYSTEM_FREEZE_KEY for unattributed). */
|
|
26
|
+
byOrigin: Record<string, {
|
|
27
|
+
count: number;
|
|
28
|
+
maxMs: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export declare function installLongtaskObserver(): Partial<JsTopTiers>;
|
|
32
|
+
/** Raw recent entries (desktop panel + MCP payload shape). */
|
|
33
|
+
export declare function getLongtasks(): JsTopLongtask[];
|
|
34
|
+
/** Windowed per-origin freeze aggregation for badges + header summary. */
|
|
35
|
+
export declare function getFreezeStats(now: number): FreezeStats;
|
|
36
|
+
export declare function clearLongtasks(): void;
|
|
37
|
+
//# sourceMappingURL=longtasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"longtasks.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/longtasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM1D,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAShD,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAsBD,wBAAgB,uBAAuB,IAAI,OAAO,CAAC,UAAU,CAAC,CAmC7D;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAO9C;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAkBvD;AAED,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-res monotonic clock for the engine's hot path. Resolved once at module
|
|
3
|
+
* load: `nativePerformanceNow` (JSI global, cheapest) → `performance.now` →
|
|
4
|
+
* `Date.now`. All engine timestamps share this single time base.
|
|
5
|
+
*/
|
|
6
|
+
export declare function now(): number;
|
|
7
|
+
/** Test-only: swap the engine clock for a controllable one. */
|
|
8
|
+
export declare function setNowForTests(fn: (() => number) | null): void;
|
|
9
|
+
//# sourceMappingURL=now.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"now.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/now.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,EAAE,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAE9D"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin registry — the "process table". An origin is the identity of a task
|
|
3
|
+
* scheduling site.
|
|
4
|
+
*
|
|
5
|
+
* Two-stage identity keeps the hot path free of stack captures:
|
|
6
|
+
* - Cheap key `${api}|${fnName}` — computed on every schedule, just string
|
|
7
|
+
* concat + Map lookup.
|
|
8
|
+
* - Once an origin gets hot (PROMOTE_MIN_CALLS schedules or
|
|
9
|
+
* PROMOTE_MIN_TOTAL_MS booked), the next schedule captures ONE
|
|
10
|
+
* `Error().stack` (throttled per-key and globally) and refines the key
|
|
11
|
+
* with the scheduling site's caller frame. Hermes dev stacks reference
|
|
12
|
+
* bundle offsets, not source files — the CALLER FUNCTION NAME is the
|
|
13
|
+
* readable part, so labels read `setInterval ← startPolling`; raw frames
|
|
14
|
+
* are kept on the origin for future desktop symbolication.
|
|
15
|
+
*/
|
|
16
|
+
import { type JsTopRow, type JsTopOriginDetail, type OriginStackFrame, type TaskApi } from "../types";
|
|
17
|
+
export interface Origin {
|
|
18
|
+
key: string;
|
|
19
|
+
api: TaskApi;
|
|
20
|
+
label: string;
|
|
21
|
+
/** Caller function name from the scheduling stack, once refined. */
|
|
22
|
+
caller?: string;
|
|
23
|
+
file?: string;
|
|
24
|
+
line?: number;
|
|
25
|
+
frames?: OriginStackFrame[];
|
|
26
|
+
calls: number;
|
|
27
|
+
totalMs: number;
|
|
28
|
+
maxMs: number;
|
|
29
|
+
scheduleCount: number;
|
|
30
|
+
lastSeenAt: number;
|
|
31
|
+
promoted: boolean;
|
|
32
|
+
/** On cheap origins: the refined key new work currently attributes to. */
|
|
33
|
+
activeRefinedKey?: string;
|
|
34
|
+
lastCaptureAt: number;
|
|
35
|
+
/** Dev-only Metro symbolication attempted (one shot per origin). */
|
|
36
|
+
symbolicated?: boolean;
|
|
37
|
+
ring: Float64Array;
|
|
38
|
+
ringStamps: Float64Array;
|
|
39
|
+
}
|
|
40
|
+
/** Pinned bucket that absorbs evicted cold origins. */
|
|
41
|
+
export declare const OTHER_KEY = "other";
|
|
42
|
+
/**
|
|
43
|
+
* Parse a Hermes stack into frames, skipping engine/wrapper frames. Engine
|
|
44
|
+
* functions are deliberately named with a `buoyJsTop` prefix so they are
|
|
45
|
+
* identifiable here even in bundle-offset stacks.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseStack(stack: string): {
|
|
48
|
+
caller?: string;
|
|
49
|
+
frames: OriginStackFrame[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the origin key for a schedule. Called from patched globals at
|
|
53
|
+
* schedule time — this is the hot path; the common case is one Map get and
|
|
54
|
+
* two counter bumps.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buoyJsTopOriginExists(key: string): boolean;
|
|
57
|
+
export declare function buoyJsTopScheduleOrigin(api: TaskApi, fn: {
|
|
58
|
+
name?: string;
|
|
59
|
+
displayName?: string;
|
|
60
|
+
} | ((...args: never[]) => unknown), nowT: number,
|
|
61
|
+
/**
|
|
62
|
+
* False when identity is resolved at FIRE time (callback scheduled while
|
|
63
|
+
* the engine was off, or stats cleared since): a runtime stack is not a
|
|
64
|
+
* scheduling site, so stack capture is skipped on that path.
|
|
65
|
+
*/
|
|
66
|
+
allowStackCapture?: boolean): string;
|
|
67
|
+
/** Book a completed call's exclusive time onto its origin + global buckets. */
|
|
68
|
+
export declare function buoyJsTopBookExclusive(originKey: string, exclusiveMs: number, start: number, end: number): void;
|
|
69
|
+
export declare function labelForOrigin(key: string): string | null;
|
|
70
|
+
/** Build the ranked table rows (excludes the pinned unattributed row — the
|
|
71
|
+
* controller assembles that from aggregator residuals). */
|
|
72
|
+
export declare function buildRows(nowT: number, windowBusy: number, topN: number): JsTopRow[];
|
|
73
|
+
/**
|
|
74
|
+
* Full origin detail minus freeze stats (the controller merges those). The
|
|
75
|
+
* bucket array is the origin's 5s activity trend, oldest→newest.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getOriginDetailBase(key: string, nowT: number, windowBusy: number): Omit<JsTopOriginDetail, "freezes" | "worstFreezeMs"> | null;
|
|
78
|
+
export declare function resetOrigins(): void;
|
|
79
|
+
/** Test-only introspection. */
|
|
80
|
+
export declare function debugGetOrigin(key: string): Origin | undefined;
|
|
81
|
+
export declare function originCount(): number;
|
|
82
|
+
//# sourceMappingURL=originRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"originRegistry.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/originRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAOL,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,OAAO,EACb,MAAM,UAAU,CAAC;AAOlB,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAID,uDAAuD;AACvD,eAAO,MAAM,SAAS,UAAU,CAAC;AA8DjC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B,CAuCA;AA2BD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC,EAC7E,IAAI,EAAE,MAAM;AACZ;;;;GAIG;AACH,iBAAiB,UAAO,GACvB,MAAM,CAmFR;AAuBD,+EAA+E;AAC/E,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,IAAI,CAoCN;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEzD;AAED;2DAC2D;AAC3D,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,QAAQ,EAAE,CA4DZ;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,eAAe,CAAC,GAAG,IAAI,CAmC7D;AAED,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAED,+BAA+B;AAC/B,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE9D;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 2 patch: legacy-bridge call-ins. On Paper/legacy-bridge runtimes,
|
|
3
|
+
* every native→JS call (touch events via RCTEventEmitter, timer flushes via
|
|
4
|
+
* JSTimers.callTimers, module callbacks) enters through
|
|
5
|
+
* `__fbBatchedBridge.callFunctionReturnFlushedQueue` /
|
|
6
|
+
* `invokeCallbackAndReturnFlushedQueue`. Wrapping them attributes event and
|
|
7
|
+
* native-callback cost by module.method.
|
|
8
|
+
*
|
|
9
|
+
* On New Architecture (bridgeless) these globals don't exist — install
|
|
10
|
+
* reports `bridge: false` and the UI banners the coverage gap. Nested
|
|
11
|
+
* wrapped work (e.g. our wrapped rAF callbacks running inside a
|
|
12
|
+
* callTimers call-in) books exclusively via the frame stack, so this tier
|
|
13
|
+
* only ever adds its own un-nested remainder.
|
|
14
|
+
*/
|
|
15
|
+
import type { JsTopTiers } from "../../types";
|
|
16
|
+
export declare function installBridgePatch(): Partial<JsTopTiers>;
|
|
17
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../../../../src/js-top/engine/patches/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,CAiDxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microtasks.d.ts","sourceRoot":"","sources":["../../../../../src/js-top/engine/patches/microtasks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,wBAAgB,uBAAuB,IAAI,IAAI,CAgB9C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 1.5 patch: Promise reactions via Promise.prototype.then/catch/finally.
|
|
3
|
+
*
|
|
4
|
+
* All three are patched: in Hermes, catch/finally delegate to then, and the
|
|
5
|
+
* WRAPPED_TAG check in wrapTask makes the delegation harmless (a reaction
|
|
6
|
+
* wrapped by our catch patch passes through our then patch untouched).
|
|
7
|
+
*
|
|
8
|
+
* Known, documented gap: native async/await resumption never goes through
|
|
9
|
+
* `.then` — async-function bodies land in the "unattributed" row, not here.
|
|
10
|
+
*
|
|
11
|
+
* The wrapper is passthrough-first: non-function reactions
|
|
12
|
+
* (`.then(undefined, fn)`), `this` binding, and return values are preserved
|
|
13
|
+
* exactly; when the engine is inactive the original is called with the raw
|
|
14
|
+
* arguments.
|
|
15
|
+
*/
|
|
16
|
+
import type { JsTopTiers } from "../../types";
|
|
17
|
+
export declare function installPromisePatches(): Partial<JsTopTiers>;
|
|
18
|
+
//# sourceMappingURL=promises.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promises.d.ts","sourceRoot":"","sources":["../../../../../src/js-top/engine/patches/promises.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA+B9C,wBAAgB,qBAAqB,IAAI,OAAO,CAAC,UAAU,CAAC,CAO3D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 1 patches: setTimeout / setInterval / setImmediate /
|
|
3
|
+
* requestAnimationFrame. Public globals only — RN internals (JSTimers) are
|
|
4
|
+
* private API and churn across versions.
|
|
5
|
+
*
|
|
6
|
+
* Install-once, never unpatch (see state.ts). Handles are returned from the
|
|
7
|
+
* originals unchanged, so clearTimeout/clearInterval/cancelAnimationFrame
|
|
8
|
+
* need no patching. Extra setTimeout args pass through.
|
|
9
|
+
*/
|
|
10
|
+
export declare function installTimerPatches(): void;
|
|
11
|
+
//# sourceMappingURL=timers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../../../../src/js-top/engine/patches/timers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,wBAAgB,mBAAmB,IAAI,IAAI,CAkE1C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared engine state + pre-patch originals.
|
|
3
|
+
*
|
|
4
|
+
* `active` is the single gate every patched global checks at schedule time:
|
|
5
|
+
* patches install once and are NEVER removed (restoring originals would
|
|
6
|
+
* clobber any wrapper another library — Sentry, Reanimated — layered on top
|
|
7
|
+
* of ours after install; same reasoning as highlight-updates' CommitProfiler
|
|
8
|
+
* hook). When inactive, a patched global forwards the raw callback to the
|
|
9
|
+
* original at the cost of one boolean check.
|
|
10
|
+
*
|
|
11
|
+
* `originals` are captured BEFORE patching so the engine's own probe and
|
|
12
|
+
* notify timers never flow through the wrappers — JS TOP must not list
|
|
13
|
+
* itself as a task.
|
|
14
|
+
*/
|
|
15
|
+
export declare const g: any;
|
|
16
|
+
export declare function isActive(): boolean;
|
|
17
|
+
export declare function setActive(on: boolean): void;
|
|
18
|
+
interface Originals {
|
|
19
|
+
setTimeout: typeof setTimeout;
|
|
20
|
+
setInterval: typeof setInterval;
|
|
21
|
+
clearInterval: typeof clearInterval;
|
|
22
|
+
clearTimeout: typeof clearTimeout;
|
|
23
|
+
setImmediate: typeof setImmediate | undefined;
|
|
24
|
+
requestAnimationFrame: typeof requestAnimationFrame | undefined;
|
|
25
|
+
queueMicrotask: typeof queueMicrotask | undefined;
|
|
26
|
+
}
|
|
27
|
+
/** Capture pre-patch globals. Idempotent; first call wins. */
|
|
28
|
+
export declare function captureOriginals(): Originals;
|
|
29
|
+
export declare function getOriginals(): Originals;
|
|
30
|
+
/** Tag interned on patched globals so duplicate module instances skip re-patching. */
|
|
31
|
+
export declare const PATCHED_TAG: unique symbol;
|
|
32
|
+
/** Marker set on wrapper functions so a wrapped fn is never wrapped twice. */
|
|
33
|
+
export declare const WRAPPED_TAG: unique symbol;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,eAAO,MAAM,CAAC,EAAE,GAEqC,CAAC;AAItD,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE3C;AAED,UAAU,SAAS;IACjB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,WAAW,EAAE,OAAO,WAAW,CAAC;IAChC,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,YAAY,EAAE,OAAO,YAAY,GAAG,SAAS,CAAC;IAC9C,qBAAqB,EAAE,OAAO,qBAAqB,GAAG,SAAS,CAAC;IAChE,cAAc,EAAE,OAAO,cAAc,GAAG,SAAS,CAAC;CACnD;AAID,8DAA8D;AAC9D,wBAAgB,gBAAgB,IAAI,SAAS,CAa5C;AAED,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAED,sFAAsF;AACtF,eAAO,MAAM,WAAW,eAAmC,CAAC;AAC5D,8EAA8E;AAC9E,eAAO,MAAM,WAAW,eAAmC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-only origin symbolication via Metro's /symbolicate endpoint (the same
|
|
3
|
+
* one LogBox uses). Hermes stacks give function names + bundle offsets; for
|
|
4
|
+
* anonymous scheduling sites (the typical `useEffect(() => setInterval(…))`)
|
|
5
|
+
* that leaves an unreadable label. Metro maps the offset back to the real
|
|
6
|
+
* source file — so a row can say `setInterval ← ChatScreen.tsx:42`, which is
|
|
7
|
+
* component-level attribution in practice.
|
|
8
|
+
*
|
|
9
|
+
* Fire-and-forget with hard caps: one attempt per origin, few in flight,
|
|
10
|
+
* silent on any failure (release builds, tunnels, Metro gone). The origin's
|
|
11
|
+
* label/file/line are upgraded in place when the answer lands — the table
|
|
12
|
+
* re-renders every tick and picks it up.
|
|
13
|
+
*/
|
|
14
|
+
import type { Origin } from "./originRegistry";
|
|
15
|
+
export declare function buoyJsTopSymbolicateOrigin(o: Origin, apiLabelText: string): void;
|
|
16
|
+
//# sourceMappingURL=symbolicate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbolicate.d.ts","sourceRoot":"","sources":["../../../../src/js-top/engine/symbolicate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAuB/C,wBAAgB,0BAA0B,CACxC,CAAC,EAAE,MAAM,EACT,YAAY,EAAE,MAAM,GACnB,IAAI,CAoEN"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync adapter for the JS TOP tool, consumed by @buoy-gg/external-sync's
|
|
3
|
+
* `useExternalSync` (structurally matches its ToolSyncAdapter interface so
|
|
4
|
+
* this package doesn't need a dependency on it — same pattern as
|
|
5
|
+
* perf-monitor's adapter).
|
|
6
|
+
*
|
|
7
|
+
* `subscribe` is only called while a dashboard is watching, and subscribing
|
|
8
|
+
* to JsTopController is exactly what starts the engine — so a desktop
|
|
9
|
+
* watcher auto-starts sampling and closing the desktop tool stops it. The
|
|
10
|
+
* snapshot IS the live channel; there is no heavy persisted state.
|
|
11
|
+
*/
|
|
12
|
+
import type { JsTopSnapshot } from "../types";
|
|
13
|
+
export declare const jsTopSyncAdapter: {
|
|
14
|
+
version: number;
|
|
15
|
+
getSnapshot: () => {
|
|
16
|
+
live: JsTopSnapshot;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
};
|
|
19
|
+
subscribe: (onChange: () => void) => () => void;
|
|
20
|
+
actions: {
|
|
21
|
+
/**
|
|
22
|
+
* Silent sampling for a desktop viewer: streams snapshots without
|
|
23
|
+
* showing the device's own HUD. (Subscribing via `subscribe` already
|
|
24
|
+
* runs the engine while watched; this exists so MCP / scripted callers
|
|
25
|
+
* can force sampling on without a watch.)
|
|
26
|
+
*/
|
|
27
|
+
setEnabled: (params: unknown) => void;
|
|
28
|
+
pause: () => void;
|
|
29
|
+
resume: () => void;
|
|
30
|
+
clear: () => void;
|
|
31
|
+
/** Full detail for one origin (desktop tap-through parity). */
|
|
32
|
+
getOriginDetail: (params: unknown) => import("../types").JsTopOriginDetail | null;
|
|
33
|
+
/**
|
|
34
|
+
* One-shot sample for MCP/automation: ensure the engine is running,
|
|
35
|
+
* observe for `durationMs` (default 3s, capped 30s), return the
|
|
36
|
+
* resulting snapshot. `clearFirst` resets all stats before sampling so
|
|
37
|
+
* the result attributes exactly one interaction/window. Leaves sampling
|
|
38
|
+
* in its prior state.
|
|
39
|
+
*/
|
|
40
|
+
sample: (params: unknown) => Promise<JsTopSnapshot>;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=jsTopSyncAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsTopSyncAdapter.d.ts","sourceRoot":"","sources":["../../../../src/js-top/sync/jsTopSyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,eAAO,MAAM,gBAAgB;;uBAEV;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;0BAOpC,MAAM,IAAI;;QAS9B;;;;;WAKG;6BACkB,OAAO;;;;QAO5B,+DAA+D;kCACrC,OAAO;QAEjC;;;;;;WAMG;yBACoB,OAAO;;CAejC,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JS TOP — live Task Manager for the React Native JS thread.
|
|
3
|
+
*
|
|
4
|
+
* Attribution model: the engine wraps every JS-thread entry point it can
|
|
5
|
+
* reach (timers, rAF, microtasks, Promise reactions, legacy-bridge call-ins)
|
|
6
|
+
* and books EXCLUSIVE time per "origin" (the place a callback was scheduled
|
|
7
|
+
* from). A high-frequency probe measures true thread occupancy; the gap
|
|
8
|
+
* between measured busy time and attributed time is surfaced honestly as an
|
|
9
|
+
* "unattributed" row rather than hidden.
|
|
10
|
+
*/
|
|
11
|
+
/** Which entry-point API a task came through. */
|
|
12
|
+
export type TaskApi = "timeout" | "interval" | "immediate" | "raf" | "microtask" | "then" | "bridge" | "other" | "unattributed";
|
|
13
|
+
/** One captured stack frame from an origin's scheduling site (dev-readable). */
|
|
14
|
+
export interface OriginStackFrame {
|
|
15
|
+
file: string;
|
|
16
|
+
line: number;
|
|
17
|
+
col: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Which coverage tiers are live on this device. UIs gray out / banner what a
|
|
21
|
+
* runtime can't see (e.g. bridge call-ins don't exist on bridgeless).
|
|
22
|
+
*/
|
|
23
|
+
export interface JsTopTiers {
|
|
24
|
+
/** Tier 1: timers/rAF/queueMicrotask — always true once the engine runs. */
|
|
25
|
+
timers: boolean;
|
|
26
|
+
/** Tier 1.5: Promise.prototype reactions (async/await bodies excluded). */
|
|
27
|
+
promises: boolean;
|
|
28
|
+
/** Tier 2: legacy-bridge call-ins (absent on New Architecture). */
|
|
29
|
+
bridge: boolean;
|
|
30
|
+
/** PerformanceObserver('longtask') available on this runtime. */
|
|
31
|
+
longtask: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** One row of the live table — a task origin ("process" in Task Manager terms). */
|
|
34
|
+
export interface JsTopRow {
|
|
35
|
+
/** Stable identity (cheap or refined origin key). */
|
|
36
|
+
key: string;
|
|
37
|
+
/** Human label, e.g. `setInterval pollFeed` or `Promise.then @ api.ts:88`. */
|
|
38
|
+
label: string;
|
|
39
|
+
api: TaskApi;
|
|
40
|
+
/** Present once the origin was promoted and a scheduling site resolved. */
|
|
41
|
+
file?: string;
|
|
42
|
+
line?: number;
|
|
43
|
+
/** Exclusive ms booked in the rolling window (the default sort column). */
|
|
44
|
+
windowMs: number;
|
|
45
|
+
/** windowMs as a share of measured busy time in the same window, 0–100. */
|
|
46
|
+
pctOfBusy: number;
|
|
47
|
+
/** Exclusive ms since engine start / last clear. */
|
|
48
|
+
totalMs: number;
|
|
49
|
+
calls: number;
|
|
50
|
+
avgMs: number;
|
|
51
|
+
maxMs: number;
|
|
52
|
+
lastSeenAgoMs: number;
|
|
53
|
+
/** 50ms+ freezes attributed to this origin in the last 60s. */
|
|
54
|
+
freezes: number;
|
|
55
|
+
/** Worst attributed freeze duration in that window (0 when none). */
|
|
56
|
+
worstFreezeMs: number;
|
|
57
|
+
}
|
|
58
|
+
/** A 50ms+ blocking task reported by the runtime, with our best attribution. */
|
|
59
|
+
export interface JsTopLongtask {
|
|
60
|
+
/** performance.now()-based start of the block. */
|
|
61
|
+
start: number;
|
|
62
|
+
duration: number;
|
|
63
|
+
/** Wall-clock time (Date.now()) the block was reported — for "Ns ago" UI. */
|
|
64
|
+
at: number;
|
|
65
|
+
/** Label of the wrapped origin that overlapped the block most, if any. */
|
|
66
|
+
originLabel: string | null;
|
|
67
|
+
}
|
|
68
|
+
/** The JSON-serializable live snapshot (device UI + external-sync payload). */
|
|
69
|
+
export interface JsTopSnapshot {
|
|
70
|
+
ts: number;
|
|
71
|
+
paused: boolean;
|
|
72
|
+
/** Thread busy% over the rolling window, 0–100. */
|
|
73
|
+
busyPct: number;
|
|
74
|
+
/** Per-bucket busy% history, oldest→newest, ≤120 points (30s @ 250ms). */
|
|
75
|
+
busyHistory: number[];
|
|
76
|
+
tiers: JsTopTiers;
|
|
77
|
+
/** Top origins by windowMs, plus pinned "unattributed"/"other" rows. */
|
|
78
|
+
rows: JsTopRow[];
|
|
79
|
+
totals: {
|
|
80
|
+
attributedWindowMs: number;
|
|
81
|
+
unattributedWindowMs: number;
|
|
82
|
+
/** Wall span of the rolling window actually covered, in ms. */
|
|
83
|
+
windowMs: number;
|
|
84
|
+
};
|
|
85
|
+
/** Freezes (50ms+ blocks) over the trailing 60s — header summary chip. */
|
|
86
|
+
freezeSummary: {
|
|
87
|
+
count: number;
|
|
88
|
+
worstMs: number;
|
|
89
|
+
};
|
|
90
|
+
longtasks: JsTopLongtask[];
|
|
91
|
+
}
|
|
92
|
+
export type JsTopStatus = "disabled" | "running" | "paused";
|
|
93
|
+
/** Everything the engine knows about one origin — the tap-through detail. */
|
|
94
|
+
export interface JsTopOriginDetail {
|
|
95
|
+
key: string;
|
|
96
|
+
label: string;
|
|
97
|
+
api: TaskApi;
|
|
98
|
+
/** Scheduling site (present once the origin was promoted + captured). */
|
|
99
|
+
caller?: string;
|
|
100
|
+
file?: string;
|
|
101
|
+
line?: number;
|
|
102
|
+
frames?: OriginStackFrame[];
|
|
103
|
+
promoted: boolean;
|
|
104
|
+
/** Times a callback was scheduled from this site. */
|
|
105
|
+
scheduleCount: number;
|
|
106
|
+
/** Times a callback actually ran. */
|
|
107
|
+
calls: number;
|
|
108
|
+
totalMs: number;
|
|
109
|
+
avgMs: number;
|
|
110
|
+
maxMs: number;
|
|
111
|
+
windowMs: number;
|
|
112
|
+
pctOfBusy: number;
|
|
113
|
+
lastSeenAgoMs: number;
|
|
114
|
+
/** Exclusive ms per 250ms bucket, oldest→newest (the 5s trend). */
|
|
115
|
+
buckets: number[];
|
|
116
|
+
freezes: number;
|
|
117
|
+
worstFreezeMs: number;
|
|
118
|
+
}
|
|
119
|
+
/** Engine tuning constants — exported for tests. */
|
|
120
|
+
export declare const BUCKET_MS = 250;
|
|
121
|
+
/** Rolling "recent" window: 20 buckets = 5s. */
|
|
122
|
+
export declare const WINDOW_BUCKETS = 20;
|
|
123
|
+
/** Global busy history ring: 120 buckets = 30s. */
|
|
124
|
+
export declare const HISTORY_BUCKETS = 120;
|
|
125
|
+
export declare const MAX_ORIGINS = 500;
|
|
126
|
+
/** Promotion thresholds: capture a scheduling stack once an origin is hot. */
|
|
127
|
+
export declare const PROMOTE_MIN_CALLS = 25;
|
|
128
|
+
export declare const PROMOTE_MIN_TOTAL_MS = 50;
|
|
129
|
+
export declare const SNAPSHOT_ROWS = 30;
|
|
130
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/js-top/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted JS TOP preferences. Same load-then-save contract as
|
|
3
|
+
* perf-monitor's hudPreferences: rehydrate async, and only persist
|
|
4
|
+
* user-driven changes after the load resolves so defaults never clobber
|
|
5
|
+
* last session's state.
|
|
6
|
+
*/
|
|
7
|
+
interface JsTopPrefs {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadJsTopPrefs(): Promise<JsTopPrefs>;
|
|
11
|
+
export declare function saveJsTopPrefs(prefs: JsTopPrefs): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../../../src/js-top/utils/preferences.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAS1D;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE"}
|