@goliapkg/sentori-react-native 4.0.0 → 5.1.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/MIGRATION.md +131 -0
- package/README.md +40 -30
- package/android/build.gradle +21 -0
- package/android/src/main/java/com/sentori/SentoriCrashHandler.kt +29 -0
- package/android/src/main/java/com/sentori/SentoriModule.kt +8 -0
- package/android/src/main/java/com/sentori/SentoriScreenshotCapture.kt +36 -4
- package/android/src/test/java/com/sentori/SentoriCrashHandlerTest.kt +7 -2
- package/android/src/test/resources/robolectric.properties +10 -0
- package/ios/SentoriCrashHandler.swift +48 -4
- package/ios/SentoriModule.swift +12 -0
- package/ios/SentoriScreenshotCapture.swift +34 -3
- package/lib/config.d.ts +17 -47
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +3 -0
- package/lib/config.js.map +1 -1
- package/lib/device.d.ts +5 -0
- package/lib/device.d.ts.map +1 -0
- package/lib/device.js +29 -0
- package/lib/device.js.map +1 -0
- package/lib/emit-hooks.d.ts +7 -0
- package/lib/emit-hooks.d.ts.map +1 -0
- package/lib/emit-hooks.js +24 -0
- package/lib/emit-hooks.js.map +1 -0
- package/lib/error-boundary.d.ts.map +1 -1
- package/lib/error-boundary.js +1 -1
- package/lib/error-boundary.js.map +1 -1
- package/lib/feature-flags.d.ts.map +1 -1
- package/lib/handlers/dev-symbolicate.d.ts +1 -1
- package/lib/handlers/dev-symbolicate.d.ts.map +1 -1
- package/lib/handlers/dev-symbolicate.js +2 -0
- package/lib/handlers/dev-symbolicate.js.map +1 -1
- package/lib/handlers/global.js +1 -1
- package/lib/handlers/global.js.map +1 -1
- package/lib/handlers/lifecycle.js +3 -3
- package/lib/handlers/lifecycle.js.map +1 -1
- package/lib/handlers/network.d.ts +2 -2
- package/lib/handlers/network.d.ts.map +1 -1
- package/lib/handlers/network.js +69 -187
- package/lib/handlers/network.js.map +1 -1
- package/lib/handlers/promise.js +1 -1
- package/lib/handlers/promise.js.map +1 -1
- package/lib/handlers/screenshot.d.ts.map +1 -1
- package/lib/handlers/screenshot.js +3 -12
- package/lib/handlers/screenshot.js.map +1 -1
- package/lib/index.d.ts +32 -109
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +54 -103
- package/lib/index.js.map +1 -1
- package/lib/init.d.ts +3 -150
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js +100 -261
- package/lib/init.js.map +1 -1
- package/lib/long-task-monitor.d.ts +1 -7
- package/lib/long-task-monitor.d.ts.map +1 -1
- package/lib/long-task-monitor.js +37 -58
- package/lib/long-task-monitor.js.map +1 -1
- package/lib/mask.d.ts +5 -13
- package/lib/mask.d.ts.map +1 -1
- package/lib/mask.js +29 -30
- package/lib/mask.js.map +1 -1
- package/lib/mobile-vitals.d.ts +3 -31
- package/lib/mobile-vitals.d.ts.map +1 -1
- package/lib/mobile-vitals.js +22 -61
- package/lib/mobile-vitals.js.map +1 -1
- package/lib/native-pending.d.ts +3 -0
- package/lib/native-pending.d.ts.map +1 -0
- package/lib/native-pending.js +64 -0
- package/lib/native-pending.js.map +1 -0
- package/lib/native.d.ts +4 -11
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +23 -0
- package/lib/native.js.map +1 -1
- package/lib/navigation.d.ts +3 -17
- package/lib/navigation.d.ts.map +1 -1
- package/lib/navigation.js +32 -133
- package/lib/navigation.js.map +1 -1
- package/lib/netinfo.d.ts +1 -1
- package/lib/netinfo.d.ts.map +1 -1
- package/lib/netinfo.js +2 -2
- package/lib/netinfo.js.map +1 -1
- package/lib/push.d.ts.map +1 -1
- package/lib/push.js +2 -4
- package/lib/push.js.map +1 -1
- package/lib/rage-tap.d.ts.map +1 -1
- package/lib/rage-tap.js +56 -23
- package/lib/rage-tap.js.map +1 -1
- package/lib/replay-screens.d.ts +15 -0
- package/lib/replay-screens.d.ts.map +1 -0
- package/lib/replay-screens.js +87 -0
- package/lib/replay-screens.js.map +1 -0
- package/lib/replay.d.ts.map +1 -1
- package/lib/replay.js +3 -24
- package/lib/replay.js.map +1 -1
- package/lib/responsiveness-detector.d.ts +18 -0
- package/lib/responsiveness-detector.d.ts.map +1 -0
- package/lib/responsiveness-detector.js +55 -0
- package/lib/responsiveness-detector.js.map +1 -0
- package/lib/scope.d.ts +7 -0
- package/lib/scope.d.ts.map +1 -0
- package/lib/scope.js +41 -0
- package/lib/scope.js.map +1 -0
- package/lib/transport.d.ts +19 -92
- package/lib/transport.d.ts.map +1 -1
- package/lib/transport.js +75 -288
- package/lib/transport.js.map +1 -1
- package/lib/verbs.d.ts +16 -0
- package/lib/verbs.d.ts.map +1 -0
- package/lib/verbs.js +153 -0
- package/lib/verbs.js.map +1 -0
- package/package.json +4 -3
- package/src/__tests__/iron-rule.test.ts +128 -0
- package/src/__tests__/replay-screens.test.ts +63 -0
- package/src/__tests__/responsiveness-detector.test.ts +74 -0
- package/src/__tests__/screenshot.test.ts +0 -2
- package/src/__tests__/transport.test.ts +66 -213
- package/src/__tests__/verbs.test.ts +91 -0
- package/src/config.ts +20 -47
- package/src/device.ts +36 -0
- package/src/emit-hooks.ts +30 -0
- package/src/error-boundary.tsx +1 -1
- package/src/handlers/dev-symbolicate.ts +2 -1
- package/src/handlers/global.ts +1 -1
- package/src/handlers/lifecycle.ts +3 -3
- package/src/handlers/network.ts +95 -211
- package/src/handlers/promise.ts +1 -1
- package/src/handlers/screenshot.ts +3 -11
- package/src/index.ts +84 -215
- package/src/init.ts +115 -449
- package/src/long-task-monitor.ts +42 -64
- package/src/mask.ts +29 -31
- package/src/mobile-vitals.ts +22 -82
- package/src/native-pending.ts +92 -0
- package/src/native.ts +33 -0
- package/src/navigation.ts +34 -142
- package/src/netinfo.ts +3 -3
- package/src/push.ts +2 -5
- package/src/rage-tap.tsx +72 -25
- package/src/replay-screens.ts +95 -0
- package/src/replay.ts +3 -20
- package/src/responsiveness-detector.ts +66 -0
- package/src/scope.ts +50 -0
- package/src/transport.ts +84 -371
- package/src/verbs.ts +198 -0
- package/lib/breadcrumbs.d.ts +0 -18
- package/lib/breadcrumbs.d.ts.map +0 -1
- package/lib/breadcrumbs.js +0 -42
- package/lib/breadcrumbs.js.map +0 -1
- package/lib/bundle-info.d.ts +0 -12
- package/lib/bundle-info.d.ts.map +0 -1
- package/lib/bundle-info.js +0 -73
- package/lib/bundle-info.js.map +0 -1
- package/lib/capture.d.ts +0 -140
- package/lib/capture.d.ts.map +0 -1
- package/lib/capture.js +0 -511
- package/lib/capture.js.map +0 -1
- package/lib/compat/sentry.d.ts +0 -126
- package/lib/compat/sentry.d.ts.map +0 -1
- package/lib/compat/sentry.js +0 -332
- package/lib/compat/sentry.js.map +0 -1
- package/lib/control-channel.d.ts +0 -6
- package/lib/control-channel.d.ts.map +0 -1
- package/lib/control-channel.js +0 -96
- package/lib/control-channel.js.map +0 -1
- package/lib/expo-compat.d.ts +0 -270
- package/lib/expo-compat.d.ts.map +0 -1
- package/lib/expo-compat.js +0 -500
- package/lib/expo-compat.js.map +0 -1
- package/lib/feedback-widget.d.ts +0 -35
- package/lib/feedback-widget.d.ts.map +0 -1
- package/lib/feedback-widget.js +0 -193
- package/lib/feedback-widget.js.map +0 -1
- package/lib/feedback.d.ts +0 -2
- package/lib/feedback.d.ts.map +0 -1
- package/lib/feedback.js +0 -17
- package/lib/feedback.js.map +0 -1
- package/lib/heartbeat.d.ts +0 -9
- package/lib/heartbeat.d.ts.map +0 -1
- package/lib/heartbeat.js +0 -138
- package/lib/heartbeat.js.map +0 -1
- package/lib/index.js.bak +0 -64
- package/lib/install-id.d.ts +0 -17
- package/lib/install-id.d.ts.map +0 -1
- package/lib/install-id.js +0 -125
- package/lib/install-id.js.map +0 -1
- package/lib/lifecycle.d.ts +0 -28
- package/lib/lifecycle.d.ts.map +0 -1
- package/lib/lifecycle.js +0 -73
- package/lib/lifecycle.js.map +0 -1
- package/lib/measure.d.ts +0 -4
- package/lib/measure.d.ts.map +0 -1
- package/lib/measure.js +0 -25
- package/lib/measure.js.map +0 -1
- package/lib/metrics.d.ts +0 -24
- package/lib/metrics.d.ts.map +0 -1
- package/lib/metrics.js +0 -81
- package/lib/metrics.js.map +0 -1
- package/lib/pre-crash-sentinel.d.ts +0 -12
- package/lib/pre-crash-sentinel.d.ts.map +0 -1
- package/lib/pre-crash-sentinel.js +0 -116
- package/lib/pre-crash-sentinel.js.map +0 -1
- package/lib/report-security.d.ts +0 -40
- package/lib/report-security.d.ts.map +0 -1
- package/lib/report-security.js +0 -159
- package/lib/report-security.js.map +0 -1
- package/lib/runtime-metrics-fps.d.ts +0 -19
- package/lib/runtime-metrics-fps.d.ts.map +0 -1
- package/lib/runtime-metrics-fps.js +0 -128
- package/lib/runtime-metrics-fps.js.map +0 -1
- package/lib/runtime-metrics-heap.d.ts +0 -13
- package/lib/runtime-metrics-heap.d.ts.map +0 -1
- package/lib/runtime-metrics-heap.js +0 -67
- package/lib/runtime-metrics-heap.js.map +0 -1
- package/lib/runtime-metrics-network.d.ts +0 -23
- package/lib/runtime-metrics-network.d.ts.map +0 -1
- package/lib/runtime-metrics-network.js +0 -99
- package/lib/runtime-metrics-network.js.map +0 -1
- package/lib/runtime-metrics.d.ts +0 -43
- package/lib/runtime-metrics.d.ts.map +0 -1
- package/lib/runtime-metrics.js +0 -115
- package/lib/runtime-metrics.js.map +0 -1
- package/lib/sample-profiler.d.ts +0 -21
- package/lib/sample-profiler.d.ts.map +0 -1
- package/lib/sample-profiler.js +0 -152
- package/lib/sample-profiler.js.map +0 -1
- package/lib/sentinel-context.d.ts +0 -4
- package/lib/sentinel-context.d.ts.map +0 -1
- package/lib/sentinel-context.js +0 -52
- package/lib/sentinel-context.js.map +0 -1
- package/lib/session-tracker.d.ts +0 -6
- package/lib/session-tracker.d.ts.map +0 -1
- package/lib/session-tracker.js +0 -50
- package/lib/session-tracker.js.map +0 -1
- package/lib/stack.d.ts +0 -3
- package/lib/stack.d.ts.map +0 -1
- package/lib/stack.js +0 -7
- package/lib/stack.js.map +0 -1
- package/lib/state-snapshots.d.ts +0 -33
- package/lib/state-snapshots.d.ts.map +0 -1
- package/lib/state-snapshots.js +0 -109
- package/lib/state-snapshots.js.map +0 -1
- package/lib/track.d.ts +0 -34
- package/lib/track.d.ts.map +0 -1
- package/lib/track.js +0 -107
- package/lib/track.js.map +0 -1
- package/lib/trail.d.ts +0 -12
- package/lib/trail.d.ts.map +0 -1
- package/lib/trail.js +0 -28
- package/lib/trail.js.map +0 -1
- package/lib/trust-score.d.ts +0 -20
- package/lib/trust-score.d.ts.map +0 -1
- package/lib/trust-score.js +0 -151
- package/lib/trust-score.js.map +0 -1
- package/lib/types.d.ts +0 -2
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -4
- package/lib/types.js.map +0 -1
- package/lib/uuid.d.ts +0 -2
- package/lib/uuid.d.ts.map +0 -1
- package/lib/uuid.js +0 -3
- package/lib/uuid.js.map +0 -1
- package/src/__tests__/before-send.test.ts +0 -72
- package/src/__tests__/breadcrumbs.test.ts +0 -44
- package/src/__tests__/capture-replay.test.ts +0 -150
- package/src/__tests__/compat-sentry.test.ts +0 -121
- package/src/__tests__/control-channel.test.ts +0 -111
- package/src/__tests__/install-id.test.ts +0 -60
- package/src/__tests__/long-task-monitor.test.ts +0 -59
- package/src/__tests__/measure.test.ts +0 -45
- package/src/__tests__/navigation.test.ts +0 -175
- package/src/__tests__/push.test.ts +0 -238
- package/src/__tests__/report-security.test.ts +0 -106
- package/src/__tests__/runtime-metrics-instruments.test.ts +0 -109
- package/src/__tests__/runtime-metrics-network.test.ts +0 -78
- package/src/__tests__/sample-profiler.test.ts +0 -59
- package/src/__tests__/stack.test.ts +0 -45
- package/src/__tests__/state-snapshots.test.ts +0 -119
- package/src/__tests__/tracing.test.ts +0 -201
- package/src/__tests__/track.test.ts +0 -91
- package/src/__tests__/uuid.test.ts +0 -41
- package/src/breadcrumbs.ts +0 -57
- package/src/bundle-info.ts +0 -95
- package/src/capture.ts +0 -660
- package/src/compat/sentry.ts +0 -490
- package/src/control-channel.ts +0 -98
- package/src/expo-compat.ts +0 -698
- package/src/feedback-widget.tsx +0 -316
- package/src/feedback.ts +0 -21
- package/src/heartbeat.ts +0 -157
- package/src/install-id.ts +0 -146
- package/src/lifecycle.ts +0 -76
- package/src/measure.ts +0 -28
- package/src/metrics.ts +0 -94
- package/src/pre-crash-sentinel.ts +0 -140
- package/src/report-security.ts +0 -165
- package/src/runtime-metrics-fps.ts +0 -137
- package/src/runtime-metrics-heap.ts +0 -78
- package/src/runtime-metrics-network.ts +0 -103
- package/src/runtime-metrics.ts +0 -122
- package/src/sample-profiler.ts +0 -169
- package/src/sentinel-context.ts +0 -60
- package/src/session-tracker.ts +0 -53
- package/src/stack.ts +0 -10
- package/src/state-snapshots.ts +0 -133
- package/src/track.ts +0 -123
- package/src/trail.ts +0 -32
- package/src/trust-score.ts +0 -176
- package/src/types.ts +0 -21
- package/src/uuid.ts +0 -2
package/lib/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,eAAO,MAAM,IAAI,0CAgGf,CAAC;AAeH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
|
package/lib/init.js
CHANGED
|
@@ -1,279 +1,118 @@
|
|
|
1
|
-
|
|
1
|
+
// sentori.init(config) — the single configuration entry point
|
|
2
|
+
// (design.md §4). Synchronous, never throws; a bad config degrades
|
|
3
|
+
// every verb to a no-op with one console.warn, never a crash
|
|
4
|
+
// (failure-isolation iron rule).
|
|
5
|
+
import { safeFn, setLogLevel } from '@goliapkg/sentori-core';
|
|
2
6
|
import { setConfig } from './config';
|
|
7
|
+
import { registerEmitHook } from './emit-hooks';
|
|
3
8
|
import { installGlobalHandler } from './handlers/global';
|
|
4
9
|
import { installLifecycleHandler } from './handlers/lifecycle';
|
|
5
|
-
import { installPromiseHandler } from './handlers/promise';
|
|
6
10
|
import { installNetworkHandler } from './handlers/network';
|
|
7
|
-
import {
|
|
8
|
-
import { markLaunchCompleted, runLaunchCrashGuard, } from './launch-crash-guard';
|
|
9
|
-
import { getInstallId } from './install-id';
|
|
10
|
-
import { startMetricsTimer } from './metrics';
|
|
11
|
-
import { emitColdStart, markColdStartT0, startRuntimeMetricsTimer, } from './runtime-metrics';
|
|
12
|
-
import { startFpsInstrument } from './runtime-metrics-fps';
|
|
13
|
-
import { startHeapInstrument } from './runtime-metrics-heap';
|
|
14
|
-
import { startNetworkBytesInstrument } from './runtime-metrics-network';
|
|
15
|
-
import { startTrackTimer } from './track';
|
|
16
|
-
import { drainNativePending, markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
17
|
-
import { getColdStartMs } from './mobile-vitals';
|
|
18
|
-
import { startHeartbeat } from './heartbeat';
|
|
19
|
-
import { startSpan } from '@goliapkg/sentori-core';
|
|
20
|
-
import { startControlChannel } from './control-channel';
|
|
11
|
+
import { installPromiseHandler } from './handlers/promise';
|
|
21
12
|
import { startLongTaskMonitor } from './long-task-monitor';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { drainOfflineQueue,
|
|
28
|
-
|
|
29
|
-
export const init = (
|
|
30
|
-
if (
|
|
31
|
-
|
|
13
|
+
import { checkColdStart } from './mobile-vitals';
|
|
14
|
+
import { markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
15
|
+
import { shipNativePending } from './native-pending';
|
|
16
|
+
import { drainReplay, startReplay } from './replay';
|
|
17
|
+
import { drainScreenReplay, startScreenReplay } from './replay-screens';
|
|
18
|
+
import { drainOfflineQueue, startTransport, uploadAttachment } from './transport';
|
|
19
|
+
let _initialized = false;
|
|
20
|
+
export const init = safeFn('init', (config) => {
|
|
21
|
+
if (_initialized)
|
|
22
|
+
return;
|
|
23
|
+
if (!config || typeof config.token !== 'string' || config.token.length === 0) {
|
|
24
|
+
// eslint-disable-next-line no-console
|
|
25
|
+
console.warn('[sentori] init skipped: token missing — SDK is a no-op');
|
|
26
|
+
return;
|
|
32
27
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// are gated correctly. Default 'warn' from logger.ts; an explicit
|
|
38
|
-
// host setting overrides.
|
|
39
|
-
setLogLevel(options.logLevel);
|
|
40
|
-
const env = options.environment ??
|
|
41
|
-
(typeof __DEV__ !== 'undefined' && __DEV__ ? 'dev' : 'prod');
|
|
42
|
-
// v0.9.0 #3 — launch-crash guard. Fires *before* any other setup so
|
|
43
|
-
// a known-bad bundle can roll back instead of running JS that's
|
|
44
|
-
// about to die again. AsyncStorage-backed; if the host doesn't have
|
|
45
|
-
// it the guard is a no-op.
|
|
46
|
-
const lcg = options.capture?.launchCrashGuard;
|
|
47
|
-
if (lcg?.enabled) {
|
|
48
|
-
void runLaunchCrashGuard(lcg, options.release, getBundleInfo()?.id ?? null);
|
|
28
|
+
if (typeof config.ingestUrl !== 'string' || config.ingestUrl.length === 0) {
|
|
29
|
+
// eslint-disable-next-line no-console
|
|
30
|
+
console.warn('[sentori] init skipped: ingestUrl missing — SDK is a no-op');
|
|
31
|
+
return;
|
|
49
32
|
}
|
|
33
|
+
_initialized = true;
|
|
50
34
|
setConfig({
|
|
51
|
-
token:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
35
|
+
token: config.token,
|
|
36
|
+
ingestUrl: config.ingestUrl.replace(/\/+$/, ''),
|
|
37
|
+
release: config.release ?? '',
|
|
38
|
+
environment: config.environment ?? 'production',
|
|
55
39
|
enabled: true,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// carries the customer journey. Defaults false to preserve v1
|
|
66
|
-
// breadcrumb shape on upgrade.
|
|
67
|
-
trackAutoBreadcrumb: options.capture?.trackAutoBreadcrumb === true,
|
|
68
|
-
// v2.3 — host-side beforeSend hook (sync). Stored on Config so
|
|
69
|
-
// capture.ts can pull it without re-resolving the InitOptions.
|
|
70
|
-
beforeSend: options.beforeSend,
|
|
71
|
-
});
|
|
72
|
-
// Tell the native crash handler about the config so the JSON it writes
|
|
73
|
-
// on the next NSException / Java uncaught carries release + env.
|
|
74
|
-
setNativeConfig({
|
|
75
|
-
token: options.token,
|
|
76
|
-
release: options.release,
|
|
77
|
-
environment: env,
|
|
40
|
+
detect: {
|
|
41
|
+
rageTap: config.detect?.rageTap ?? true,
|
|
42
|
+
longFreeze: config.detect?.longFreeze ?? true,
|
|
43
|
+
slowColdStart: config.detect?.slowColdStart ?? true,
|
|
44
|
+
slowApi: config.detect?.slowApi ?? false,
|
|
45
|
+
},
|
|
46
|
+
replaySeconds: config.replaySeconds ?? 30,
|
|
47
|
+
replayScreens: config.replayScreens ?? false,
|
|
48
|
+
beforeSend: config.beforeSend,
|
|
78
49
|
});
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
tags: { 'vital.kind': 'cold_start' },
|
|
94
|
-
});
|
|
95
|
-
span.finish({ status: 'ok' });
|
|
96
|
-
}
|
|
97
|
-
startTransport();
|
|
98
|
-
// v1.1 +S7 升级 — control channel poll for live-debug flag.
|
|
99
|
-
startControlChannel();
|
|
100
|
-
// v0.8.0-c — start watching network class. No-op if NetInfo isn't
|
|
101
|
-
// installed; events just won't carry `device.networkType` in that
|
|
102
|
-
// case.
|
|
103
|
-
startNetworkTypeWatch();
|
|
104
|
-
// v0.8.3 — drain custom-metric ring every 30 s.
|
|
105
|
-
startMetricsTimer();
|
|
106
|
-
// v1.1 chunk B — drain `sentori.track()` ring every 30 s.
|
|
107
|
-
startTrackTimer();
|
|
108
|
-
// v2.1 W2 — runtime metrics auto-instrument. Defaults on; host
|
|
109
|
-
// can opt out with `capture: { runtimeMetrics: false }`. The
|
|
110
|
-
// ring + emit live in `@goliapkg/sentori-core`; we own the
|
|
111
|
-
// 30 s flusher + the cold-start one-shot here. FPS / heap /
|
|
112
|
-
// route-nav / network instruments ship in W2 part 3 (each
|
|
113
|
-
// gated on its own per-tick perf budget CI test).
|
|
114
|
-
if (options.capture?.runtimeMetrics !== false) {
|
|
115
|
-
markColdStartT0();
|
|
116
|
-
startRuntimeMetricsTimer();
|
|
117
|
-
// Defer the emit one tick so React's first paint settles
|
|
118
|
-
// before we stamp "cold-start ended". 0-delay setTimeout puts
|
|
119
|
-
// the call after the current microtask queue drains.
|
|
120
|
-
setTimeout(emitColdStart, 0);
|
|
121
|
-
// FPS via rAF (per-tick budget < 0.5 ms — see
|
|
122
|
-
// runtime-metrics-fps.ts header). Heap is a 30 s polling
|
|
123
|
-
// tick; no-op when performance.memory isn't exposed (most
|
|
124
|
-
// RN engines today; we ship the wiring anyway so the same
|
|
125
|
-
// SDK works on web targets via @goliapkg/sentori-javascript).
|
|
126
|
-
startFpsInstrument();
|
|
127
|
-
startHeapInstrument();
|
|
128
|
-
// Network bytes counters drain every 30 s. The counters
|
|
129
|
-
// themselves are incremented inline by handlers/network.ts
|
|
130
|
-
// on every fetch round-trip — see the recordNetworkBytes
|
|
131
|
-
// call site there. No-op when `capture.network: false` is
|
|
132
|
-
// set (no fetch patch → no counter increments).
|
|
133
|
-
startNetworkBytesInstrument();
|
|
134
|
-
// Route-nav dwell timing emits inline from `navigation.ts`'s
|
|
135
|
-
// useTraceNavigation state listener — no extra start call
|
|
136
|
-
// needed; the host already mounts that hook for tracing.
|
|
137
|
-
}
|
|
138
|
-
// v1.1 chunk S1 — warm the install-id cache. Fire-and-forget;
|
|
139
|
-
// any event captured before the first resolve simply omits
|
|
140
|
-
// `device.installId`. Subsequent captures pick it up via the
|
|
141
|
-
// sync `peekInstallId()` read in collectDevice().
|
|
142
|
-
void getInstallId();
|
|
143
|
-
// v0.9.1 +S4 — pre-crash sentinel. Off by default; opt-in via
|
|
144
|
-
// `capture.preCrashSentinel: true`.
|
|
145
|
-
if (options.capture?.preCrashSentinel === true) {
|
|
146
|
-
startPreCrashSentinel({
|
|
147
|
-
enabled: true,
|
|
148
|
-
channels: options.capture.sentinelChannels,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
// v0.9.6 #4 — long-task monitor. Off by default.
|
|
152
|
-
const lt = options.capture?.longTaskMonitor;
|
|
153
|
-
if (lt) {
|
|
154
|
-
startLongTaskMonitor({
|
|
155
|
-
enabled: true,
|
|
156
|
-
thresholdMs: typeof lt === 'object' ? lt.thresholdMs : undefined,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
// v0.9.6 #2 — wireframe replay. Off by default.
|
|
160
|
-
const rp = options.capture?.replay;
|
|
161
|
-
if (rp === 'wireframe') {
|
|
50
|
+
setLogLevel(config.logLevel ?? 'warn');
|
|
51
|
+
// JS-side error capture + the signal-ring feeders.
|
|
52
|
+
installGlobalHandler();
|
|
53
|
+
installPromiseHandler();
|
|
54
|
+
installNetworkHandler();
|
|
55
|
+
installLifecycleHandler();
|
|
56
|
+
// Warn-scenario detectors (design.md §3 minimum set). rage_tap
|
|
57
|
+
// rides the RageTapCapture component; the rest start here.
|
|
58
|
+
if (config.detect?.longFreeze !== false)
|
|
59
|
+
startLongTaskMonitor();
|
|
60
|
+
// B-type replay: a rolling in-memory wireframe ring; an error/warn
|
|
61
|
+
// going out drains it into a replay attachment on that event.
|
|
62
|
+
const replaySeconds = config.replaySeconds ?? 30;
|
|
63
|
+
if (replaySeconds > 0) {
|
|
162
64
|
startReplay({ mode: 'wireframe' });
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const capture = options.capture ?? {};
|
|
177
|
-
if (capture.globalErrors !== false)
|
|
178
|
-
installGlobalHandler();
|
|
179
|
-
if (capture.promiseRejections !== false)
|
|
180
|
-
installPromiseHandler();
|
|
181
|
-
if (capture.network !== false) {
|
|
182
|
-
const netOpts = typeof capture.network === 'object' ? capture.network : undefined;
|
|
183
|
-
installNetworkHandler({ graphql: netOpts?.graphql });
|
|
184
|
-
}
|
|
185
|
-
if (capture.sessions !== false) {
|
|
186
|
-
// Open the cold-start session now (RN doesn't fire an AppState
|
|
187
|
-
// `change` for the initial `active` state), then bind AppState so
|
|
188
|
-
// background ends it and the next foreground opens a fresh one.
|
|
189
|
-
startSession();
|
|
190
|
-
installLifecycleHandler();
|
|
191
|
-
}
|
|
192
|
-
// Analytics v1 — live-presence heartbeat. Foreground 1/min by
|
|
193
|
-
// default; pass `capture.heartbeat = false` to opt out, or
|
|
194
|
-
// `{ intervalMs: 30_000 }` to override. The default budget is well
|
|
195
|
-
// under the "几乎不能造成性能抖动" rule (CLAUDE.md).
|
|
196
|
-
const heartbeatOpt = capture.heartbeat;
|
|
197
|
-
if (heartbeatOpt !== false) {
|
|
198
|
-
startHeartbeat(typeof heartbeatOpt === 'object' ? heartbeatOpt : {});
|
|
199
|
-
}
|
|
200
|
-
// Drain events persisted from previous session (best-effort):
|
|
201
|
-
// - native crashes from <Documents>/sentori/pending/*.json
|
|
202
|
-
// - JS transport offline queue from AsyncStorage
|
|
203
|
-
drainNativePending()
|
|
204
|
-
.then(async (items) => {
|
|
205
|
-
for (const json of items) {
|
|
206
|
-
try {
|
|
207
|
-
const event = JSON.parse(json);
|
|
208
|
-
// Phase 42 sub-E.05 / F.09: the native crash handler couldn't
|
|
209
|
-
// upload attachments at crash time (the app was dying); it
|
|
210
|
-
// base64-encoded them into `_pendingAttachments` instead.
|
|
211
|
-
// On next launch we upload each before enqueueing the event,
|
|
212
|
-
// so the dashboard sees the refs in `event.attachments[]`.
|
|
213
|
-
if (event._pendingAttachments && event._pendingAttachments.length > 0) {
|
|
214
|
-
for (const p of event._pendingAttachments) {
|
|
215
|
-
const meta = await uploadAttachment(event.id, p.kind, { base64: p.base64, mediaType: p.mediaType }, { source: p.source });
|
|
216
|
-
if (meta) {
|
|
217
|
-
if (!event.attachments)
|
|
218
|
-
event.attachments = [];
|
|
219
|
-
event.attachments.push(meta);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
delete event._pendingAttachments;
|
|
65
|
+
// Visual ring is opt-in: screenshots can carry user content.
|
|
66
|
+
if (config.replayScreens === true)
|
|
67
|
+
startScreenReplay(replaySeconds);
|
|
68
|
+
registerEmitHook((event) => {
|
|
69
|
+
if (event.kind !== 'error' && event.kind !== 'warn')
|
|
70
|
+
return;
|
|
71
|
+
if (!event.id)
|
|
72
|
+
return;
|
|
73
|
+
const lines = drainReplay();
|
|
74
|
+
if (lines) {
|
|
75
|
+
const base64 = base64Encode(lines);
|
|
76
|
+
if (base64) {
|
|
77
|
+
void uploadAttachment(event.id, 'replay', { base64, mediaType: 'application/x-sentori-replay' }, { source: 'js' });
|
|
223
78
|
}
|
|
224
|
-
enqueue(event);
|
|
225
79
|
}
|
|
226
|
-
|
|
227
|
-
|
|
80
|
+
const frames = drainScreenReplay();
|
|
81
|
+
if (frames) {
|
|
82
|
+
const base64 = base64Encode(frames);
|
|
83
|
+
if (base64) {
|
|
84
|
+
void uploadAttachment(event.id, 'screens', { base64, mediaType: 'application/x-sentori-screens' }, { source: 'js' });
|
|
85
|
+
}
|
|
228
86
|
}
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
.catch(() => { });
|
|
232
|
-
drainOfflineQueue().catch(() => { });
|
|
233
|
-
// v0.9.0 #3 — init reached the end without throwing. Schedule the
|
|
234
|
-
// "launch completed" marker after one tick so any synchronous user
|
|
235
|
-
// code right after `init()` gets to run first; we want the marker to
|
|
236
|
-
// confirm the JS bridge stayed alive, not just that `init()` returned.
|
|
237
|
-
if (lcg?.enabled) {
|
|
238
|
-
setTimeout(() => {
|
|
239
|
-
void markLaunchCompleted(getBundleInfo()?.id ?? null);
|
|
240
|
-
}, 2_000);
|
|
87
|
+
});
|
|
241
88
|
}
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
try {
|
|
269
|
-
options.onReady(info);
|
|
270
|
-
}
|
|
271
|
-
catch {
|
|
272
|
-
// Host's onReady threw. NEVER rule — swallow.
|
|
273
|
-
}
|
|
89
|
+
// Native side: hand over release/environment for the crash-file
|
|
90
|
+
// writer, mark the bridge live, then drain crashes from previous
|
|
91
|
+
// launches. All fire-and-forget — init stays synchronous and fast
|
|
92
|
+
// (< 50 ms budget; the work below happens off the critical path).
|
|
93
|
+
setNativeConfig({
|
|
94
|
+
environment: config.environment ?? 'production',
|
|
95
|
+
release: config.release ?? '',
|
|
96
|
+
token: config.token,
|
|
97
|
+
});
|
|
98
|
+
markNativeJsBridgeReady();
|
|
99
|
+
startTransport();
|
|
100
|
+
checkColdStart(config.detect?.slowColdStart !== false);
|
|
101
|
+
void shipNativePending().catch(() => undefined);
|
|
102
|
+
void drainOfflineQueue();
|
|
103
|
+
});
|
|
104
|
+
/** RN's Hermes has no btoa in older releases; go through base64.ts. */
|
|
105
|
+
const base64Encode = (text) => {
|
|
106
|
+
try {
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
108
|
+
const { encodeBase64 } = require('./base64');
|
|
109
|
+
return encodeBase64(text);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
274
113
|
}
|
|
275
114
|
};
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
115
|
+
export const __resetForTests = () => {
|
|
116
|
+
_initialized = false;
|
|
117
|
+
};
|
|
279
118
|
//# sourceMappingURL=init.js.map
|
package/lib/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
enabled: boolean;
|
|
3
|
-
/** Threshold ms above which a tick lag becomes a longtask span.
|
|
4
|
-
* Default 200ms. Lower → noisier. */
|
|
5
|
-
thresholdMs?: number;
|
|
6
|
-
};
|
|
7
|
-
export declare function startLongTaskMonitor(opts: LongTaskMonitorOptions): void;
|
|
1
|
+
export declare function startLongTaskMonitor(): void;
|
|
8
2
|
export declare function stopLongTaskMonitor(): void;
|
|
9
3
|
/** Test-only. */
|
|
10
4
|
export declare function __resetLongTaskMonitorForTests(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"long-task-monitor.d.ts","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"long-task-monitor.d.ts","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"AA8BA,wBAAgB,oBAAoB,IAAI,IAAI,CAO3C;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AA0BD,iBAAiB;AACjB,wBAAgB,8BAA8B,IAAI,IAAI,CAKrD"}
|
package/lib/long-task-monitor.js
CHANGED
|
@@ -1,48 +1,35 @@
|
|
|
1
|
-
//
|
|
1
|
+
// long_freeze — detected warn scenario (design.md §3, category B:
|
|
2
|
+
// 「app 卡住了 / 死了几秒」), JS-thread side.
|
|
2
3
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// Mini-spec: a setInterval(50 ms) tick measures wall-clock drift.
|
|
5
|
+
// Drift ≤ 2 s ⇒ a `freeze` signal in the ring (context only —
|
|
6
|
+
// brief jank is not worth an event). Drift > 2 s ⇒ one `warn`
|
|
7
|
+
// event, scenario `long_freeze`, surface = current screen, with the
|
|
8
|
+
// blocked duration. Rate-limited to 6 events/minute so a freeze
|
|
9
|
+
// storm cannot flood ingest.
|
|
9
10
|
//
|
|
10
|
-
// What it
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// that vary per RN minor. We could swizzle / vendor headers but
|
|
18
|
-
// that's an Insight-build-config burden. The long-task monitor
|
|
19
|
-
// gets ~80% of the practical value (find slow renders, expensive
|
|
20
|
-
// reducers, accidental sync work in render path) with zero native
|
|
21
|
-
// code + zero RN-version sensitivity.
|
|
22
|
-
//
|
|
23
|
-
// Pairs naturally with +S4 (pre-crash sentinel, RAF frame budget,
|
|
24
|
-
// fires at the slow-frame threshold) — long-task monitor fires
|
|
25
|
-
// further down the slowness scale.
|
|
26
|
-
import { startSpan } from '@goliapkg/sentori-core';
|
|
11
|
+
// What it cannot do: capture the stack DURING the block — JS is
|
|
12
|
+
// single-threaded; by the time our tick runs the busy code is gone.
|
|
13
|
+
// The native watchdogs (HangWatchdog / AnrWatchdog) cover the
|
|
14
|
+
// UI-thread side of the same scenario.
|
|
15
|
+
import { pushSignal } from '@goliapkg/sentori-core';
|
|
16
|
+
import { currentScreen } from './navigation';
|
|
17
|
+
import { warnDetected } from './verbs';
|
|
27
18
|
const TICK_INTERVAL_MS = 50;
|
|
28
|
-
const
|
|
29
|
-
const
|
|
19
|
+
const SIGNAL_THRESHOLD_MS = 200; // ring entry: noticeable jank
|
|
20
|
+
const WARN_THRESHOLD_MS = 2_000; // warn event: a real freeze
|
|
21
|
+
const MAX_WARNS_PER_MIN = 6;
|
|
30
22
|
let _timer = null;
|
|
31
23
|
let _lastTick = 0;
|
|
32
|
-
let
|
|
33
|
-
let
|
|
34
|
-
export function startLongTaskMonitor(
|
|
24
|
+
let _warnWindowStart = 0;
|
|
25
|
+
let _warnsThisWindow = 0;
|
|
26
|
+
export function startLongTaskMonitor() {
|
|
35
27
|
if (_timer !== null)
|
|
36
28
|
return;
|
|
37
|
-
if (!opts.enabled)
|
|
38
|
-
return;
|
|
39
|
-
const threshold = opts.thresholdMs ?? LONGTASK_THRESHOLD_MS;
|
|
40
29
|
_lastTick = Date.now();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
_timer = setInterval(
|
|
44
|
-
tick(threshold);
|
|
45
|
-
}, TICK_INTERVAL_MS);
|
|
30
|
+
_warnWindowStart = _lastTick;
|
|
31
|
+
_warnsThisWindow = 0;
|
|
32
|
+
_timer = setInterval(tick, TICK_INTERVAL_MS);
|
|
46
33
|
_timer.unref?.();
|
|
47
34
|
}
|
|
48
35
|
export function stopLongTaskMonitor() {
|
|
@@ -51,38 +38,30 @@ export function stopLongTaskMonitor() {
|
|
|
51
38
|
_timer = null;
|
|
52
39
|
}
|
|
53
40
|
}
|
|
54
|
-
function tick(
|
|
41
|
+
function tick() {
|
|
55
42
|
const now = Date.now();
|
|
56
43
|
const elapsed = now - _lastTick;
|
|
57
44
|
_lastTick = now;
|
|
58
45
|
const lag = elapsed - TICK_INTERVAL_MS;
|
|
59
|
-
if (lag <=
|
|
46
|
+
if (lag <= SIGNAL_THRESHOLD_MS)
|
|
47
|
+
return;
|
|
48
|
+
pushSignal('freeze', { blockedMs: Math.round(lag) });
|
|
49
|
+
if (lag <= WARN_THRESHOLD_MS)
|
|
60
50
|
return;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
_emitWindowStart = now;
|
|
65
|
-
_emitsThisWindow = 0;
|
|
51
|
+
if (now - _warnWindowStart >= 60_000) {
|
|
52
|
+
_warnWindowStart = now;
|
|
53
|
+
_warnsThisWindow = 0;
|
|
66
54
|
}
|
|
67
|
-
if (
|
|
55
|
+
if (_warnsThisWindow >= MAX_WARNS_PER_MIN)
|
|
68
56
|
return;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
name: 'js.longtask',
|
|
72
|
-
startNowMs: now - lag,
|
|
73
|
-
tags: {
|
|
74
|
-
'profile.kind': 'longtask',
|
|
75
|
-
'profile.duration_ms': String(Math.round(lag)),
|
|
76
|
-
'profile.tick_interval_ms': String(TICK_INTERVAL_MS),
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
span.finish({ endNowMs: now, status: 'ok' });
|
|
57
|
+
_warnsThisWindow += 1;
|
|
58
|
+
warnDetected('long_freeze', { screen: currentScreen() }, { blockedMs: Math.round(lag), thread: 'js' });
|
|
80
59
|
}
|
|
81
60
|
/** Test-only. */
|
|
82
61
|
export function __resetLongTaskMonitorForTests() {
|
|
83
62
|
stopLongTaskMonitor();
|
|
84
63
|
_lastTick = 0;
|
|
85
|
-
|
|
86
|
-
|
|
64
|
+
_warnWindowStart = 0;
|
|
65
|
+
_warnsThisWindow = 0;
|
|
87
66
|
}
|
|
88
67
|
//# sourceMappingURL=long-task-monitor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"long-task-monitor.js","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"long-task-monitor.js","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,qCAAqC;AACrC,EAAE;AACF,kEAAkE;AAClE,8DAA8D;AAC9D,8DAA8D;AAC9D,oEAAoE;AACpE,gEAAgE;AAChE,6BAA6B;AAC7B,EAAE;AACF,gEAAgE;AAChE,oEAAoE;AACpE,8DAA8D;AAC9D,uCAAuC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAC,8BAA8B;AAC/D,MAAM,iBAAiB,GAAG,KAAK,CAAC,CAAC,4BAA4B;AAC7D,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,IAAI,MAAM,GAA0C,IAAI,CAAC;AACzD,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,IAAI,gBAAgB,GAAG,CAAC,CAAC;AACzB,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB,MAAM,UAAU,oBAAoB;IAClC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO;IAC5B,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,gBAAgB,GAAG,SAAS,CAAC;IAC7B,gBAAgB,GAAG,CAAC,CAAC;IACrB,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC5C,MAA4C,CAAC,KAAK,EAAE,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,aAAa,CAAC,MAAM,CAAC,CAAC;QACtB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,IAAI;IACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC;IAChC,SAAS,GAAG,GAAG,CAAC;IAChB,MAAM,GAAG,GAAG,OAAO,GAAG,gBAAgB,CAAC;IACvC,IAAI,GAAG,IAAI,mBAAmB;QAAE,OAAO;IAEvC,UAAU,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrD,IAAI,GAAG,IAAI,iBAAiB;QAAE,OAAO;IAErC,IAAI,GAAG,GAAG,gBAAgB,IAAI,MAAM,EAAE,CAAC;QACrC,gBAAgB,GAAG,GAAG,CAAC;QACvB,gBAAgB,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,gBAAgB,IAAI,iBAAiB;QAAE,OAAO;IAClD,gBAAgB,IAAI,CAAC,CAAC;IAEtB,YAAY,CACV,aAAa,EACb,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,EAC3B,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAC7C,CAAC;AACJ,CAAC;AAED,iBAAiB;AACjB,MAAM,UAAU,8BAA8B;IAC5C,mBAAmB,EAAE,CAAC;IACtB,SAAS,GAAG,CAAC,CAAC;IACd,gBAAgB,GAAG,CAAC,CAAC;IACrB,gBAAgB,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
package/lib/mask.d.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
type MaskQuery = () => string[];
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Idempotent: a second call replaces the first. Pass `null` (or
|
|
8
|
-
* call `clearMaskQuery`) to detach.
|
|
9
|
-
*/
|
|
10
|
-
export declare function registerMaskQuery(query: MaskQuery): void;
|
|
11
|
-
/** Unregister. Mostly for tests / teardown. */
|
|
12
|
-
export declare function clearMaskQuery(): void;
|
|
13
|
-
/** Internal — read by `handlers/screenshot.ts` at capture time. */
|
|
14
|
-
export declare function getRegisteredMaskQuery(): MaskQuery | null;
|
|
2
|
+
/** Register (or with `null`, clear) the mask query. */
|
|
3
|
+
export declare const registerMaskQuery: (query: MaskQuery | null) => void;
|
|
4
|
+
/** The current mask list; empty when unregistered or throwing. */
|
|
5
|
+
export declare const maskedNativeIds: () => string[];
|
|
6
|
+
export declare const __resetForTests: () => void;
|
|
15
7
|
export {};
|
|
16
8
|
//# sourceMappingURL=mask.d.ts.map
|