@goliapkg/sentori-react-native 0.9.3 → 0.9.4

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/lib/init.d.ts CHANGED
@@ -60,6 +60,15 @@ export type InitOptions = {
60
60
  hz?: number;
61
61
  mode: 'off' | 'wireframe';
62
62
  };
63
+ /** v1.1 #4 升级 — JS sample profiler. setInterval(50ms) idle-tick
64
+ * sampler aggregates frame counts → emits sentori.profile span
65
+ * every 60s with `flameData` (frame → tick count). Pairs with
66
+ * longTaskMonitor (≥200ms outliers) — sample profiler 看 idle
67
+ * 分布、long-task 看 outliers。 */
68
+ sampleProfiler?: boolean | {
69
+ flushMs?: number;
70
+ sampleMs?: number;
71
+ };
63
72
  /** v0.9.0 #3 — launch-crash loop guard. When two consecutive
64
73
  * launches don't reach `markLaunchCompleted()` (typical of an
65
74
  * OTA update with a fatal bug), invoke the host callback with
package/lib/init.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AASnF,OAAO,KAAK,EAAkB,cAAc,EAA2B,MAAM,SAAS,CAAC;AAIvF,MAAM,MAAM,WAAW,GAAG;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EACJ,OAAO,GACP;YACE;;qEAEyD;YACzD,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,CAAC;QACN;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB;;;;6CAIqC;QACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;QACrC;;;;6CAIqC;QACrC,eAAe,CAAC,EAAE,OAAO,GAAG;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrD;;;mEAG2D;QAC3D,MAAM,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG;YAAE,EAAE,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;SAAE,CAAC;QAC1E;;;sEAG8D;QAC9D,gBAAgB,CAAC,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,qBAAqB,CAAC,EAAE,CACtB,IAAI,EAAE,OAAO,sBAAsB,EAAE,eAAe,KAElD,OAAO,sBAAsB,EAAE,iBAAiB,GAChD,OAAO,CAAC,OAAO,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;YAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;IACF;;;;;gEAK4D;IAC5D,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAIF,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,KAAG,IA+J3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAUnF,OAAO,KAAK,EAAkB,cAAc,EAA2B,MAAM,SAAS,CAAC;AAIvF,MAAM,MAAM,WAAW,GAAG;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EACJ,OAAO,GACP;YACE;;qEAEyD;YACzD,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,CAAC;QACN;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB;;;;6CAIqC;QACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;QACrC;;;;6CAIqC;QACrC,eAAe,CAAC,EAAE,OAAO,GAAG;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrD;;;mEAG2D;QAC3D,MAAM,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG;YAAE,EAAE,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;SAAE,CAAC;QAC1E;;;;uCAI+B;QAC/B,cAAc,CAAC,EAAE,OAAO,GAAG;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACnE;;;sEAG8D;QAC9D,gBAAgB,CAAC,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,qBAAqB,CAAC,EAAE,CACtB,IAAI,EAAE,OAAO,sBAAsB,EAAE,eAAe,KAElD,OAAO,sBAAsB,EAAE,iBAAiB,GAChD,OAAO,CAAC,OAAO,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;YAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;IACF;;;;;gEAK4D;IAC5D,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAIF,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,KAAG,IAwK3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
package/lib/init.js CHANGED
@@ -14,6 +14,7 @@ import { startLongTaskMonitor } from './long-task-monitor';
14
14
  import { startNetworkTypeWatch } from './netinfo';
15
15
  import { startPreCrashSentinel } from './pre-crash-sentinel';
16
16
  import { startReplay } from './replay';
17
+ import { startSampleProfiler } from './sample-profiler';
17
18
  import { startSession } from './session-tracker';
18
19
  import { drainOfflineQueue, enqueue, startTransport, uploadAttachment, } from './transport';
19
20
  const DEFAULT_INGEST_URL = 'https://ingest.sentori.golia.jp';
@@ -103,6 +104,15 @@ export const init = (options) => {
103
104
  else if (rp && typeof rp === 'object' && rp.mode === 'wireframe') {
104
105
  startReplay({ hz: rp.hz, mode: 'wireframe' });
105
106
  }
107
+ // v1.1 #4 升级 — JS sample profiler. Off by default.
108
+ const sp = options.capture?.sampleProfiler;
109
+ if (sp) {
110
+ startSampleProfiler({
111
+ enabled: true,
112
+ flushMs: typeof sp === 'object' ? sp.flushMs : undefined,
113
+ sampleMs: typeof sp === 'object' ? sp.sampleMs : undefined,
114
+ });
115
+ }
106
116
  const capture = options.capture ?? {};
107
117
  if (capture.globalErrors !== false)
108
118
  installGlobalHandler();
package/lib/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type SampleProfilerOptions = {
2
+ enabled: boolean;
3
+ /** Sample interval ms. Default 50. Lower → more accurate but more
4
+ * JS-thread overhead. */
5
+ sampleMs?: number;
6
+ /** Flush window ms. Default 60 000 (one minute). */
7
+ flushMs?: number;
8
+ };
9
+ export declare function startSampleProfiler(opts: SampleProfilerOptions): void;
10
+ export declare function stopSampleProfiler(): void;
11
+ export declare function __resetSampleProfilerForTests(): void;
12
+ //# sourceMappingURL=sample-profiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-profiler.d.ts","sourceRoot":"","sources":["../src/sample-profiler.ts"],"names":[],"mappings":"AAmCA,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB;8BAC0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAUrE;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAWzC;AAyED,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
@@ -0,0 +1,129 @@
1
+ // v1.1 #4 升级 — JS sample profiler (idle-tick sampler).
2
+ //
3
+ // What it does:
4
+ // • setInterval(50ms) — captures `new Error().stack` of the tick
5
+ // callback, parses out the top frames, increments per-frame
6
+ // counts in a rolling window
7
+ // • every 60 s, emits a `sentori.profile` span with the aggregated
8
+ // flame-data (frame name → tick count) as span data
9
+ //
10
+ // What it does NOT do:
11
+ // • Sample frames during a busy JS task. JS is single-threaded;
12
+ // while the busy code is running, our setInterval can't fire,
13
+ // so the busy stack never gets sampled. Long-task monitor (#4
14
+ // v0.9.6) catches that case from a different angle (duration).
15
+ //
16
+ // Idle-tick sampling is still useful: shows which functions appear
17
+ // most often between busy moments — typically the render hot path,
18
+ // frequent timer callbacks, recurring middleware. Pairs with
19
+ // long-task-monitor (catches the 200ms+ outliers).
20
+ //
21
+ // Real Hermes off-thread sampling profiler (which would catch busy
22
+ // frames too) needs RN-internal HermesAPI access, deferred to v1.2.
23
+ import { startSpan } from '@goliapkg/sentori-core';
24
+ const SAMPLE_INTERVAL_MS = 50;
25
+ const FLUSH_INTERVAL_MS = 60_000;
26
+ const MAX_FRAMES = 200; // safety cap per profile
27
+ const MAX_FRAME_NAME_LEN = 120;
28
+ let _frameCounts = new Map();
29
+ let _windowStartedAt = 0;
30
+ let _sampleTimer = null;
31
+ let _flushTimer = null;
32
+ export function startSampleProfiler(opts) {
33
+ if (!opts.enabled || _sampleTimer !== null)
34
+ return;
35
+ const sampleMs = Math.max(20, opts.sampleMs ?? SAMPLE_INTERVAL_MS);
36
+ const flushMs = Math.max(5_000, opts.flushMs ?? FLUSH_INTERVAL_MS);
37
+ _windowStartedAt = Date.now();
38
+ _sampleTimer = setInterval(() => sampleTick(), sampleMs);
39
+ _flushTimer = setInterval(() => flushWindow(), flushMs);
40
+ _sampleTimer.unref?.();
41
+ _flushTimer.unref?.();
42
+ }
43
+ export function stopSampleProfiler() {
44
+ if (_sampleTimer !== null) {
45
+ clearInterval(_sampleTimer);
46
+ _sampleTimer = null;
47
+ }
48
+ if (_flushTimer !== null) {
49
+ clearInterval(_flushTimer);
50
+ _flushTimer = null;
51
+ }
52
+ _frameCounts.clear();
53
+ _windowStartedAt = 0;
54
+ }
55
+ function sampleTick() {
56
+ const stack = new Error().stack;
57
+ if (!stack)
58
+ return;
59
+ // Skip the first 2 frames — they're our `sampleTick` + `Error
60
+ // ctor` which would dominate every sample.
61
+ const lines = stack.split('\n').slice(2, 12);
62
+ for (const line of lines) {
63
+ const frame = parseFrameName(line);
64
+ if (frame) {
65
+ _frameCounts.set(frame, (_frameCounts.get(frame) ?? 0) + 1);
66
+ }
67
+ }
68
+ }
69
+ /** Pull a stable identifier from one stack-trace line. Handles:
70
+ *
71
+ * at FunctionName (file://path/Foo.js:123:45)
72
+ * at file://path/Foo.js:123:45 (anonymous)
73
+ * FunctionName@file://path/Foo.js:123:45 (Hermes style)
74
+ *
75
+ * Drops absolute path noise — keeps `Foo.js:Line` so re-deploys
76
+ * with stable code paths bucket together. */
77
+ function parseFrameName(line) {
78
+ const trimmed = line.trim();
79
+ if (trimmed.length === 0)
80
+ return null;
81
+ // Hermes / JSC: `FunctionName@file:line:col` or just `@file:line:col`.
82
+ // Standard: `at FunctionName (file:line:col)`.
83
+ let raw = trimmed.replace(/^at\s+/, '');
84
+ raw = raw.replace(/\s*[(\[].*$/, ''); // strip the file part after `(`
85
+ // Hermes: split on @
86
+ if (raw.includes('@')) {
87
+ raw = raw.split('@')[0] ?? raw;
88
+ }
89
+ raw = raw.trim();
90
+ if (raw.length === 0 || raw.length > MAX_FRAME_NAME_LEN)
91
+ return null;
92
+ // Ignore the obvious noise frames.
93
+ if (raw === 'Object.<anonymous>' || raw === '<anonymous>')
94
+ return null;
95
+ return raw;
96
+ }
97
+ function flushWindow() {
98
+ if (_frameCounts.size === 0)
99
+ return;
100
+ const windowEndedAt = Date.now();
101
+ const durationMs = windowEndedAt - _windowStartedAt;
102
+ // Top-N frames so attachment doesn't bloat unboundedly.
103
+ const top = Array.from(_frameCounts.entries())
104
+ .sort((a, b) => b[1] - a[1])
105
+ .slice(0, MAX_FRAMES);
106
+ const span = startSpan('sentori.profile', {
107
+ name: 'js.sample-profile',
108
+ startNowMs: _windowStartedAt,
109
+ tags: {
110
+ 'profile.kind': 'sample',
111
+ 'profile.sample_count': String(sampleCount(top)),
112
+ 'profile.duration_ms': String(durationMs),
113
+ },
114
+ });
115
+ span.setData('flameData', Object.fromEntries(top));
116
+ span.finish({ endNowMs: windowEndedAt, status: 'ok' });
117
+ _frameCounts.clear();
118
+ _windowStartedAt = windowEndedAt;
119
+ }
120
+ function sampleCount(entries) {
121
+ let total = 0;
122
+ for (const [, n] of entries)
123
+ total += n;
124
+ return total;
125
+ }
126
+ export function __resetSampleProfilerForTests() {
127
+ stopSampleProfiler();
128
+ }
129
+ //# sourceMappingURL=sample-profiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-profiler.js","sourceRoot":"","sources":["../src/sample-profiler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://sentori.golia.jp",
package/src/init.ts CHANGED
@@ -17,6 +17,7 @@ import { startLongTaskMonitor } from './long-task-monitor';
17
17
  import { startNetworkTypeWatch } from './netinfo';
18
18
  import { startPreCrashSentinel, type PreCrashChannel } from './pre-crash-sentinel';
19
19
  import { startReplay } from './replay';
20
+ import { startSampleProfiler } from './sample-profiler';
20
21
  import { startSession } from './session-tracker';
21
22
  import {
22
23
  drainOfflineQueue,
@@ -85,6 +86,12 @@ export type InitOptions = {
85
86
  * visible nodes; captureException flushes the last 60 s as a
86
87
  * `replay` attachment. Set to `'wireframe'` to enable. */
87
88
  replay?: 'off' | 'wireframe' | { hz?: number; mode: 'off' | 'wireframe' };
89
+ /** v1.1 #4 升级 — JS sample profiler. setInterval(50ms) idle-tick
90
+ * sampler aggregates frame counts → emits sentori.profile span
91
+ * every 60s with `flameData` (frame → tick count). Pairs with
92
+ * longTaskMonitor (≥200ms outliers) — sample profiler 看 idle
93
+ * 分布、long-task 看 outliers。 */
94
+ sampleProfiler?: boolean | { flushMs?: number; sampleMs?: number };
88
95
  /** v0.9.0 #3 — launch-crash loop guard. When two consecutive
89
96
  * launches don't reach `markLaunchCompleted()` (typical of an
90
97
  * OTA update with a fatal bug), invoke the host callback with
@@ -209,6 +216,15 @@ export const init = (options: InitOptions): void => {
209
216
  } else if (rp && typeof rp === 'object' && rp.mode === 'wireframe') {
210
217
  startReplay({ hz: rp.hz, mode: 'wireframe' });
211
218
  }
219
+ // v1.1 #4 升级 — JS sample profiler. Off by default.
220
+ const sp = options.capture?.sampleProfiler;
221
+ if (sp) {
222
+ startSampleProfiler({
223
+ enabled: true,
224
+ flushMs: typeof sp === 'object' ? sp.flushMs : undefined,
225
+ sampleMs: typeof sp === 'object' ? sp.sampleMs : undefined,
226
+ });
227
+ }
212
228
 
213
229
  const capture = options.capture ?? {};
214
230
  if (capture.globalErrors !== false) installGlobalHandler();
@@ -0,0 +1,143 @@
1
+ // v1.1 #4 升级 — JS sample profiler (idle-tick sampler).
2
+ //
3
+ // What it does:
4
+ // • setInterval(50ms) — captures `new Error().stack` of the tick
5
+ // callback, parses out the top frames, increments per-frame
6
+ // counts in a rolling window
7
+ // • every 60 s, emits a `sentori.profile` span with the aggregated
8
+ // flame-data (frame name → tick count) as span data
9
+ //
10
+ // What it does NOT do:
11
+ // • Sample frames during a busy JS task. JS is single-threaded;
12
+ // while the busy code is running, our setInterval can't fire,
13
+ // so the busy stack never gets sampled. Long-task monitor (#4
14
+ // v0.9.6) catches that case from a different angle (duration).
15
+ //
16
+ // Idle-tick sampling is still useful: shows which functions appear
17
+ // most often between busy moments — typically the render hot path,
18
+ // frequent timer callbacks, recurring middleware. Pairs with
19
+ // long-task-monitor (catches the 200ms+ outliers).
20
+ //
21
+ // Real Hermes off-thread sampling profiler (which would catch busy
22
+ // frames too) needs RN-internal HermesAPI access, deferred to v1.2.
23
+
24
+ import { startSpan } from '@goliapkg/sentori-core';
25
+
26
+ const SAMPLE_INTERVAL_MS = 50;
27
+ const FLUSH_INTERVAL_MS = 60_000;
28
+ const MAX_FRAMES = 200; // safety cap per profile
29
+ const MAX_FRAME_NAME_LEN = 120;
30
+
31
+ let _frameCounts = new Map<string, number>();
32
+ let _windowStartedAt = 0;
33
+ let _sampleTimer: ReturnType<typeof setInterval> | null = null;
34
+ let _flushTimer: ReturnType<typeof setInterval> | null = null;
35
+
36
+ export type SampleProfilerOptions = {
37
+ enabled: boolean;
38
+ /** Sample interval ms. Default 50. Lower → more accurate but more
39
+ * JS-thread overhead. */
40
+ sampleMs?: number;
41
+ /** Flush window ms. Default 60 000 (one minute). */
42
+ flushMs?: number;
43
+ };
44
+
45
+ export function startSampleProfiler(opts: SampleProfilerOptions): void {
46
+ if (!opts.enabled || _sampleTimer !== null) return;
47
+ const sampleMs = Math.max(20, opts.sampleMs ?? SAMPLE_INTERVAL_MS);
48
+ const flushMs = Math.max(5_000, opts.flushMs ?? FLUSH_INTERVAL_MS);
49
+
50
+ _windowStartedAt = Date.now();
51
+ _sampleTimer = setInterval(() => sampleTick(), sampleMs);
52
+ _flushTimer = setInterval(() => flushWindow(), flushMs);
53
+ (_sampleTimer as unknown as { unref?: () => void }).unref?.();
54
+ (_flushTimer as unknown as { unref?: () => void }).unref?.();
55
+ }
56
+
57
+ export function stopSampleProfiler(): void {
58
+ if (_sampleTimer !== null) {
59
+ clearInterval(_sampleTimer);
60
+ _sampleTimer = null;
61
+ }
62
+ if (_flushTimer !== null) {
63
+ clearInterval(_flushTimer);
64
+ _flushTimer = null;
65
+ }
66
+ _frameCounts.clear();
67
+ _windowStartedAt = 0;
68
+ }
69
+
70
+ function sampleTick(): void {
71
+ const stack = new Error().stack;
72
+ if (!stack) return;
73
+ // Skip the first 2 frames — they're our `sampleTick` + `Error
74
+ // ctor` which would dominate every sample.
75
+ const lines = stack.split('\n').slice(2, 12);
76
+ for (const line of lines) {
77
+ const frame = parseFrameName(line);
78
+ if (frame) {
79
+ _frameCounts.set(frame, (_frameCounts.get(frame) ?? 0) + 1);
80
+ }
81
+ }
82
+ }
83
+
84
+ /** Pull a stable identifier from one stack-trace line. Handles:
85
+ *
86
+ * at FunctionName (file://path/Foo.js:123:45)
87
+ * at file://path/Foo.js:123:45 (anonymous)
88
+ * FunctionName@file://path/Foo.js:123:45 (Hermes style)
89
+ *
90
+ * Drops absolute path noise — keeps `Foo.js:Line` so re-deploys
91
+ * with stable code paths bucket together. */
92
+ function parseFrameName(line: string): null | string {
93
+ const trimmed = line.trim();
94
+ if (trimmed.length === 0) return null;
95
+ // Hermes / JSC: `FunctionName@file:line:col` or just `@file:line:col`.
96
+ // Standard: `at FunctionName (file:line:col)`.
97
+ let raw = trimmed.replace(/^at\s+/, '');
98
+ raw = raw.replace(/\s*[(\[].*$/, ''); // strip the file part after `(`
99
+ // Hermes: split on @
100
+ if (raw.includes('@')) {
101
+ raw = raw.split('@')[0] ?? raw;
102
+ }
103
+ raw = raw.trim();
104
+ if (raw.length === 0 || raw.length > MAX_FRAME_NAME_LEN) return null;
105
+ // Ignore the obvious noise frames.
106
+ if (raw === 'Object.<anonymous>' || raw === '<anonymous>') return null;
107
+ return raw;
108
+ }
109
+
110
+ function flushWindow(): void {
111
+ if (_frameCounts.size === 0) return;
112
+ const windowEndedAt = Date.now();
113
+ const durationMs = windowEndedAt - _windowStartedAt;
114
+ // Top-N frames so attachment doesn't bloat unboundedly.
115
+ const top = Array.from(_frameCounts.entries())
116
+ .sort((a, b) => b[1] - a[1])
117
+ .slice(0, MAX_FRAMES);
118
+
119
+ const span = startSpan('sentori.profile', {
120
+ name: 'js.sample-profile',
121
+ startNowMs: _windowStartedAt,
122
+ tags: {
123
+ 'profile.kind': 'sample',
124
+ 'profile.sample_count': String(sampleCount(top)),
125
+ 'profile.duration_ms': String(durationMs),
126
+ },
127
+ });
128
+ span.setData('flameData', Object.fromEntries(top));
129
+ span.finish({ endNowMs: windowEndedAt, status: 'ok' });
130
+
131
+ _frameCounts.clear();
132
+ _windowStartedAt = windowEndedAt;
133
+ }
134
+
135
+ function sampleCount(entries: [string, number][]): number {
136
+ let total = 0;
137
+ for (const [, n] of entries) total += n;
138
+ return total;
139
+ }
140
+
141
+ export function __resetSampleProfilerForTests(): void {
142
+ stopSampleProfiler();
143
+ }