@goliapkg/sentori-react-native 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/lib/bundle-info.d.ts +12 -0
  2. package/lib/bundle-info.d.ts.map +1 -0
  3. package/lib/bundle-info.js +73 -0
  4. package/lib/bundle-info.js.map +1 -0
  5. package/lib/capture.d.ts.map +1 -1
  6. package/lib/capture.js +6 -0
  7. package/lib/capture.js.map +1 -1
  8. package/lib/feature-flags.d.ts +9 -0
  9. package/lib/feature-flags.d.ts.map +1 -0
  10. package/lib/feature-flags.js +44 -0
  11. package/lib/feature-flags.js.map +1 -0
  12. package/lib/handlers/network.d.ts +9 -1
  13. package/lib/handlers/network.d.ts.map +1 -1
  14. package/lib/handlers/network.js +189 -18
  15. package/lib/handlers/network.js.map +1 -1
  16. package/lib/index.d.ts +18 -0
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +19 -0
  19. package/lib/index.js.map +1 -1
  20. package/lib/init.d.ts +16 -1
  21. package/lib/init.d.ts.map +1 -1
  22. package/lib/init.js +26 -2
  23. package/lib/init.js.map +1 -1
  24. package/lib/launch-crash-guard.d.ts +37 -0
  25. package/lib/launch-crash-guard.d.ts.map +1 -0
  26. package/lib/launch-crash-guard.js +163 -0
  27. package/lib/launch-crash-guard.js.map +1 -0
  28. package/lib/measure.d.ts +4 -0
  29. package/lib/measure.d.ts.map +1 -0
  30. package/lib/measure.js +25 -0
  31. package/lib/measure.js.map +1 -0
  32. package/lib/metrics.d.ts +9 -0
  33. package/lib/metrics.d.ts.map +1 -0
  34. package/lib/metrics.js +64 -0
  35. package/lib/metrics.js.map +1 -0
  36. package/lib/rage-tap-detector.d.ts +8 -0
  37. package/lib/rage-tap-detector.d.ts.map +1 -0
  38. package/lib/rage-tap-detector.js +21 -0
  39. package/lib/rage-tap-detector.js.map +1 -0
  40. package/lib/rage-tap.d.ts +6 -0
  41. package/lib/rage-tap.d.ts.map +1 -0
  42. package/lib/rage-tap.js +35 -0
  43. package/lib/rage-tap.js.map +1 -0
  44. package/lib/transport.d.ts +12 -0
  45. package/lib/transport.d.ts.map +1 -1
  46. package/lib/transport.js +24 -0
  47. package/lib/transport.js.map +1 -1
  48. package/package.json +11 -3
  49. package/src/__tests__/feature-flags.test.ts +55 -0
  50. package/src/__tests__/measure.test.ts +45 -0
  51. package/src/__tests__/network-graphql.test.ts +75 -0
  52. package/src/__tests__/rage-tap.test.ts +38 -0
  53. package/src/bundle-info.ts +95 -0
  54. package/src/capture.ts +6 -0
  55. package/src/feature-flags.ts +47 -0
  56. package/src/handlers/network.ts +198 -18
  57. package/src/index.ts +29 -0
  58. package/src/init.ts +57 -2
  59. package/src/launch-crash-guard.ts +221 -0
  60. package/src/measure.ts +28 -0
  61. package/src/metrics.ts +74 -0
  62. package/src/rage-tap-detector.ts +26 -0
  63. package/src/rage-tap.tsx +48 -0
  64. package/src/transport.ts +32 -0
package/lib/index.js CHANGED
@@ -2,7 +2,12 @@ import { init } from './init';
2
2
  import { addBreadcrumb } from './breadcrumbs';
3
3
  import { captureError, captureException, captureStep, getUser, sendUserFeedback, setUser, } from './capture';
4
4
  import { ErrorBoundary } from './error-boundary';
5
+ import { clearAllFeatureFlags, clearFeatureFlag, getFeatureFlags, setFeatureFlag, } from './feature-flags';
5
6
  import { clearMaskQuery, registerMaskQuery } from './mask';
7
+ import { measureFn } from './measure';
8
+ import { startMoment } from '@goliapkg/sentori-core';
9
+ import { flushMetrics, recordMetric } from './metrics';
10
+ import { RageTapCapture } from './rage-tap';
6
11
  import { endSession, markSessionCrashed, startSession, } from './session-tracker';
7
12
  export const sentori = {
8
13
  init,
@@ -13,7 +18,16 @@ export const sentori = {
13
18
  captureException,
14
19
  captureStep,
15
20
  sendUserFeedback,
21
+ recordMetric,
22
+ flushMetrics,
23
+ measureFn,
24
+ startMoment,
25
+ setFeatureFlag,
26
+ clearFeatureFlag,
27
+ clearAllFeatureFlags,
28
+ getFeatureFlags,
16
29
  ErrorBoundary,
30
+ RageTapCapture,
17
31
  registerMaskQuery,
18
32
  clearMaskQuery,
19
33
  startSession,
@@ -25,7 +39,12 @@ export { init, init as initSentori } from './init';
25
39
  export { addBreadcrumb } from './breadcrumbs';
26
40
  export { captureError, captureException, captureStep, getUser, sendUserFeedback, setUser, } from './capture';
27
41
  export { ErrorBoundary } from './error-boundary';
42
+ export { clearAllFeatureFlags, clearFeatureFlag, getFeatureFlags, setFeatureFlag, } from './feature-flags';
28
43
  export { clearMaskQuery, registerMaskQuery } from './mask';
44
+ export { flushMetrics, recordMetric } from './metrics';
45
+ export { measureFn } from './measure';
46
+ export { MomentHandle, startMoment } from '@goliapkg/sentori-core';
47
+ export { RageTapCapture } from './rage-tap';
29
48
  export { startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
30
49
  export { endSession, markSessionCrashed, startSession, } from './session-tracker';
31
50
  export { useTraceNavigation } from './navigation';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI;IACJ,aAAa;IACb,OAAO;IACP,OAAO;IACP,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,gBAAgB;IAChB,aAAa;IACb,iBAAiB;IACjB,cAAc;IACd,YAAY;IACZ,UAAU;IACV,kBAAkB;CACnB,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI;IACJ,aAAa;IACb,OAAO;IACP,OAAO;IACP,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,gBAAgB;IAChB,YAAY;IACZ,YAAY;IACZ,SAAS;IACT,WAAW;IACX,cAAc;IACd,gBAAgB;IAChB,oBAAoB;IACpB,eAAe;IACf,aAAa;IACb,cAAc;IACd,iBAAiB;IACjB,cAAc;IACd,YAAY;IACZ,UAAU;IACV,kBAAkB;CACnB,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,YAAY,EAAyB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
package/lib/init.d.ts CHANGED
@@ -12,7 +12,12 @@ export type InitOptions = {
12
12
  capture?: {
13
13
  globalErrors?: boolean;
14
14
  promiseRejections?: boolean;
15
- network?: boolean;
15
+ network?: boolean | {
16
+ /** v0.9.0 #11 — auto-extract GraphQL `operationName` from
17
+ * POST request bodies and use it as the breadcrumb / span
18
+ * name (instead of `POST /graphql`). Default `true`. */
19
+ graphql?: boolean;
20
+ };
16
21
  /** Session tracking: opens a session on init and on each
17
22
  * foreground (`AppState` → `active`), ends it on background.
18
23
  * Drives crash-free rate. Set `false` to opt out. */
@@ -31,6 +36,16 @@ export type InitOptions = {
31
36
  * the buffer is sealed and uploaded as a `sessionTrail`
32
37
  * attachment. Defaults to false. */
33
38
  sessionTrail?: boolean;
39
+ /** v0.9.0 #3 — launch-crash loop guard. When two consecutive
40
+ * launches don't reach `markLaunchCompleted()` (typical of an
41
+ * OTA update with a fatal bug), invoke the host callback with
42
+ * a 200 ms timeout to decide rollback / reset / continue. */
43
+ launchCrashGuard?: {
44
+ enabled: boolean;
45
+ onLaunchCrashDetected?: (info: import('./launch-crash-guard').LaunchCrashInfo) => import('./launch-crash-guard').LaunchCrashAction | Promise<import('./launch-crash-guard').LaunchCrashAction>;
46
+ threshold?: number;
47
+ timeoutMs?: number;
48
+ };
34
49
  };
35
50
  /** Phase 44 sub-B: client-side sampling. Each rate is `[0, 1]`;
36
51
  * absent / null keeps everything. Defaults to 1.0 for both
package/lib/init.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAcA,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,EAAE,OAAO,CAAC;QAClB;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,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,IAwF3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAoBA,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;;;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,IAoH3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
package/lib/init.js CHANGED
@@ -3,6 +3,9 @@ import { installGlobalHandler } from './handlers/global';
3
3
  import { installLifecycleHandler } from './handlers/lifecycle';
4
4
  import { installPromiseHandler } from './handlers/promise';
5
5
  import { installNetworkHandler } from './handlers/network';
6
+ import { getBundleInfo } from './bundle-info';
7
+ import { markLaunchCompleted, runLaunchCrashGuard, } from './launch-crash-guard';
8
+ import { startMetricsTimer } from './metrics';
6
9
  import { drainNativePending, setNativeConfig } from './native';
7
10
  import { startNetworkTypeWatch } from './netinfo';
8
11
  import { startSession } from './session-tracker';
@@ -17,6 +20,14 @@ export const init = (options) => {
17
20
  }
18
21
  const env = options.environment ??
19
22
  (typeof __DEV__ !== 'undefined' && __DEV__ ? 'dev' : 'prod');
23
+ // v0.9.0 #3 — launch-crash guard. Fires *before* any other setup so
24
+ // a known-bad bundle can roll back instead of running JS that's
25
+ // about to die again. AsyncStorage-backed; if the host doesn't have
26
+ // it the guard is a no-op.
27
+ const lcg = options.capture?.launchCrashGuard;
28
+ if (lcg?.enabled) {
29
+ void runLaunchCrashGuard(lcg, options.release, getBundleInfo()?.id ?? null);
30
+ }
20
31
  setConfig({
21
32
  token: options.token,
22
33
  release: options.release,
@@ -40,13 +51,17 @@ export const init = (options) => {
40
51
  // installed; events just won't carry `device.networkType` in that
41
52
  // case.
42
53
  startNetworkTypeWatch();
54
+ // v0.8.3 — drain custom-metric ring every 30 s.
55
+ startMetricsTimer();
43
56
  const capture = options.capture ?? {};
44
57
  if (capture.globalErrors !== false)
45
58
  installGlobalHandler();
46
59
  if (capture.promiseRejections !== false)
47
60
  installPromiseHandler();
48
- if (capture.network !== false)
49
- installNetworkHandler();
61
+ if (capture.network !== false) {
62
+ const netOpts = typeof capture.network === 'object' ? capture.network : undefined;
63
+ installNetworkHandler({ graphql: netOpts?.graphql });
64
+ }
50
65
  if (capture.sessions !== false) {
51
66
  // Open the cold-start session now (RN doesn't fire an AppState
52
67
  // `change` for the initial `active` state), then bind AppState so
@@ -87,5 +102,14 @@ export const init = (options) => {
87
102
  })
88
103
  .catch(() => { });
89
104
  drainOfflineQueue().catch(() => { });
105
+ // v0.9.0 #3 — init reached the end without throwing. Schedule the
106
+ // "launch completed" marker after one tick so any synchronous user
107
+ // code right after `init()` gets to run first; we want the marker to
108
+ // confirm the JS bridge stayed alive, not just that `init()` returned.
109
+ if (lcg?.enabled) {
110
+ setTimeout(() => {
111
+ void markLaunchCompleted(getBundleInfo()?.id ?? null);
112
+ }, 2_000);
113
+ }
90
114
  };
91
115
  //# 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,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAkDrB,MAAM,kBAAkB,GAAG,iCAAiC,CAAC;AAE7D,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAoB,EAAQ,EAAE;IACjD,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,GAAG,GACP,OAAO,CAAC,WAAW;QACnB,CAAC,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAE/D,SAAS,CAAC;QACR,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,kBAAkB;QAClD,OAAO,EAAE,IAAI;QACb,kBAAkB,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI;QACxD,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;QACjD,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;QACjD,mBAAmB,EAAE,OAAO,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI;KAC5D,CAAC,CAAC;IAEH,uEAAuE;IACvE,iEAAiE;IACjE,eAAe,CAAC;QACd,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,cAAc,EAAE,CAAC;IACjB,kEAAkE;IAClE,kEAAkE;IAClE,QAAQ;IACR,qBAAqB,EAAE,CAAC;IAExB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK;QAAE,oBAAoB,EAAE,CAAC;IAC3D,IAAI,OAAO,CAAC,iBAAiB,KAAK,KAAK;QAAE,qBAAqB,EAAE,CAAC;IACjE,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK;QAAE,qBAAqB,EAAE,CAAC;IACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC/B,+DAA+D;QAC/D,kEAAkE;QAClE,gEAAgE;QAChE,YAAY,EAAE,CAAC;QACf,uBAAuB,EAAE,CAAC;IAC5B,CAAC;IAED,8DAA8D;IAC9D,2DAA2D;IAC3D,iDAAiD;IACjD,kBAAkB,EAAE;SACjB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAE5B,CAAC;gBACF,8DAA8D;gBAC9D,2DAA2D;gBAC3D,0DAA0D;gBAC1D,6DAA6D;gBAC7D,2DAA2D;gBAC3D,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;wBAC1C,MAAM,IAAI,GAAG,MAAM,gBAAgB,CACjC,KAAK,CAAC,EAAE,EACR,CAAC,CAAC,IAAI,EACN,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,EAC5C,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CACrB,CAAC;wBACF,IAAI,IAAI,EAAE,CAAC;4BACT,IAAI,CAAC,KAAK,CAAC,WAAW;gCAAE,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;4BAC/C,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC;oBACD,OAAO,KAAK,CAAC,mBAAmB,CAAC;gBACnC,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;QACH,CAAC;IACH,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnB,iBAAiB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export type LaunchCrashInfo = {
2
+ /** Consecutive failed launches detected so far (this one inclusive). */
3
+ consecutiveCount: number;
4
+ /** OTA bundle id of the crashing launch, if known. */
5
+ crashedBundle: null | string;
6
+ /** Most recent bundle id that *did* reach `markLaunchCompleted`. */
7
+ lastSafeBundle: null | string;
8
+ /** Store-binary release of the crashing launch. */
9
+ release: string;
10
+ };
11
+ export type LaunchCrashAction = {
12
+ action: 'continue';
13
+ } | {
14
+ action: 'reset';
15
+ clearKeys: string[];
16
+ } | {
17
+ action: 'rollback';
18
+ toBundle?: null | string;
19
+ };
20
+ export type LaunchCrashGuardOptions = {
21
+ enabled: boolean;
22
+ onLaunchCrashDetected?: (info: LaunchCrashInfo) => LaunchCrashAction | Promise<LaunchCrashAction>;
23
+ /** Default 2 — fires after the second consecutive failed launch. */
24
+ threshold?: number;
25
+ /** Default 200 — D3 decision. */
26
+ timeoutMs?: number;
27
+ };
28
+ /** Returns `false` iff we triggered a bundle rollback / reset and
29
+ * expect the app to reload momentarily; the caller (init) should
30
+ * short-circuit further setup. */
31
+ export declare function runLaunchCrashGuard(opts: LaunchCrashGuardOptions, release: string, currentBundleId: null | string): Promise<{
32
+ shouldContinueInit: boolean;
33
+ info?: LaunchCrashInfo;
34
+ }>;
35
+ export declare function markLaunchCompleted(currentBundleId: null | string): Promise<void>;
36
+ export declare function raceWithTimeout<T>(p: Promise<T>, ms: number, fallback: T): Promise<T>;
37
+ //# sourceMappingURL=launch-crash-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-crash-guard.d.ts","sourceRoot":"","sources":["../src/launch-crash-guard.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,eAAe,GAAG;IAC5B,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC;IAC7B,oEAAoE;IACpE,cAAc,EAAE,IAAI,GAAG,MAAM,CAAC;IAC9B,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,GACtB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClG,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAqBF;;mCAEmC;AACnC,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,IAAI,GAAG,MAAM,GAC7B,OAAO,CAAC;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAyDlE;AAED,wBAAsB,mBAAmB,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYvF;AAyCD,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA0BrF"}
@@ -0,0 +1,163 @@
1
+ // v0.9.0 #3 — launch-crash loop guard.
2
+ //
3
+ // On every init we write a "launch_marker" to AsyncStorage. On
4
+ // `markLaunchCompleted()` we write a sibling "launch_completed". On
5
+ // startup we look at the previous launch state: marker present but
6
+ // completed missing → previous launch did not finish → increment a
7
+ // consecutive-crash counter.
8
+ //
9
+ // When the counter crosses `threshold` (default 2), we invoke the
10
+ // host-supplied `onLaunchCrashDetected` callback with a 200 ms timeout
11
+ // (D3) and follow its action: rollback the OTA bundle, reset a list
12
+ // of AsyncStorage keys, or continue. Rollback / reset trigger an
13
+ // `expo-updates` reload when available.
14
+ //
15
+ // v0.9.0 scope: JS-only — catches everything that runs after the JS
16
+ // bridge is up (almost every OTA-induced launch crash). v0.9.1 will
17
+ // add a native marker for the small set of "crashed before bridge"
18
+ // cases.
19
+ const MARKER_KEY = '@sentori/launch_marker';
20
+ const COMPLETED_KEY = '@sentori/launch_completed';
21
+ const COUNT_KEY = '@sentori/launch_crash_count';
22
+ function loadAsyncStorage() {
23
+ try {
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
+ const mod = require('@react-native-async-storage/async-storage');
26
+ return mod.default ?? mod;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /** Returns `false` iff we triggered a bundle rollback / reset and
33
+ * expect the app to reload momentarily; the caller (init) should
34
+ * short-circuit further setup. */
35
+ export async function runLaunchCrashGuard(opts, release, currentBundleId) {
36
+ if (!opts.enabled)
37
+ return { shouldContinueInit: true };
38
+ const storage = loadAsyncStorage();
39
+ if (!storage)
40
+ return { shouldContinueInit: true };
41
+ try {
42
+ const marker = await storage.getItem(MARKER_KEY);
43
+ const completed = await storage.getItem(COMPLETED_KEY);
44
+ if (marker && !completed) {
45
+ const m = safeJsonParse(marker) ?? {};
46
+ const prevCount = parseInt((await storage.getItem(COUNT_KEY)) ?? '0', 10) || 0;
47
+ const consecutiveCount = prevCount + 1;
48
+ await storage.setItem(COUNT_KEY, String(consecutiveCount));
49
+ if (consecutiveCount >= (opts.threshold ?? 2) && opts.onLaunchCrashDetected) {
50
+ const info = {
51
+ consecutiveCount,
52
+ crashedBundle: m.bundleId ?? null,
53
+ lastSafeBundle: m.lastSafeBundle ?? null,
54
+ release,
55
+ };
56
+ const action = await raceWithTimeout(Promise.resolve(opts.onLaunchCrashDetected(info)), opts.timeoutMs ?? 200, { action: 'continue' });
57
+ const handled = await applyAction(action, storage);
58
+ if (!handled.shouldContinueInit) {
59
+ return { ...handled, info };
60
+ }
61
+ return { ...handled, info };
62
+ }
63
+ }
64
+ else {
65
+ // Previous launch completed; clean the counter.
66
+ await storage.setItem(COUNT_KEY, '0');
67
+ }
68
+ // Write the marker for THIS launch. lastSafeBundle = previous
69
+ // completed bundle id, so the user's callback can target it.
70
+ const lastSafeBundle = (completed && safeJsonParse(completed)?.bundleId) ?? null;
71
+ await storage.setItem(MARKER_KEY, JSON.stringify({
72
+ bundleId: currentBundleId,
73
+ lastSafeBundle,
74
+ release,
75
+ ts: Date.now(),
76
+ }));
77
+ await storage.removeItem(COMPLETED_KEY);
78
+ }
79
+ catch {
80
+ // AsyncStorage glitches must never block init.
81
+ }
82
+ return { shouldContinueInit: true };
83
+ }
84
+ export async function markLaunchCompleted(currentBundleId) {
85
+ const storage = loadAsyncStorage();
86
+ if (!storage)
87
+ return;
88
+ try {
89
+ await storage.setItem(COMPLETED_KEY, JSON.stringify({ bundleId: currentBundleId, ts: Date.now() }));
90
+ await storage.setItem(COUNT_KEY, '0');
91
+ }
92
+ catch {
93
+ // ignore
94
+ }
95
+ }
96
+ async function applyAction(action, storage) {
97
+ if (action.action === 'continue')
98
+ return { shouldContinueInit: true };
99
+ if (action.action === 'reset') {
100
+ if (storage.multiRemove && Array.isArray(action.clearKeys)) {
101
+ try {
102
+ await storage.multiRemove(action.clearKeys);
103
+ }
104
+ catch {
105
+ // ignore
106
+ }
107
+ }
108
+ await reloadOTAIfPossible();
109
+ return { shouldContinueInit: false };
110
+ }
111
+ if (action.action === 'rollback') {
112
+ await reloadOTAIfPossible();
113
+ return { shouldContinueInit: false };
114
+ }
115
+ return { shouldContinueInit: true };
116
+ }
117
+ async function reloadOTAIfPossible() {
118
+ try {
119
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
120
+ const Updates = require('expo-updates');
121
+ if (typeof Updates.reloadAsync === 'function') {
122
+ await Updates.reloadAsync();
123
+ }
124
+ }
125
+ catch {
126
+ // expo-updates not installed — caller will fall through and
127
+ // continue init; their callback returned `rollback` but we can't
128
+ // perform it without the OTA library. Document accordingly.
129
+ }
130
+ }
131
+ export function raceWithTimeout(p, ms, fallback) {
132
+ return new Promise((resolve) => {
133
+ let done = false;
134
+ const t = setTimeout(() => {
135
+ if (!done) {
136
+ done = true;
137
+ resolve(fallback);
138
+ }
139
+ }, ms);
140
+ p.then((v) => {
141
+ if (!done) {
142
+ done = true;
143
+ clearTimeout(t);
144
+ resolve(v);
145
+ }
146
+ }, () => {
147
+ if (!done) {
148
+ done = true;
149
+ clearTimeout(t);
150
+ resolve(fallback);
151
+ }
152
+ });
153
+ });
154
+ }
155
+ function safeJsonParse(s) {
156
+ try {
157
+ return JSON.parse(s);
158
+ }
159
+ catch {
160
+ return null;
161
+ }
162
+ }
163
+ //# sourceMappingURL=launch-crash-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-crash-guard.js","sourceRoot":"","sources":["../src/launch-crash-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function measureFn<T>(name: string, fn: () => Promise<T> | T, opts?: {
2
+ tags?: Record<string, string>;
3
+ }): Promise<T>;
4
+ //# sourceMappingURL=measure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AASA,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvC,OAAO,CAAC,CAAC,CAAC,CAcZ"}
package/lib/measure.js ADDED
@@ -0,0 +1,25 @@
1
+ // v0.9.0 #14 — `sentori.measureFn(name, fn)`. Profile-lite. Wrap an
2
+ // async (or sync) function call in a span so it shows on the issue
3
+ // detail trace waterfall without writing the boilerplate every time.
4
+ // The full Hermes-sampler profiler (#4) is the deep version of this
5
+ // idea; `measureFn` is the cheap version that doesn't need a native
6
+ // module.
7
+ import { startSpan } from '@goliapkg/sentori-core';
8
+ export async function measureFn(name, fn, opts) {
9
+ const span = startSpan('sentori.measureFn', {
10
+ name,
11
+ tags: opts?.tags ?? {},
12
+ });
13
+ try {
14
+ const result = await fn();
15
+ span.finish({ status: 'ok' });
16
+ return result;
17
+ }
18
+ catch (e) {
19
+ if (e instanceof Error)
20
+ span.setTag('error.message', e.message);
21
+ span.finish({ status: 'error' });
22
+ throw e;
23
+ }
24
+ }
25
+ //# sourceMappingURL=measure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.js","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,mEAAmE;AACnE,qEAAqE;AACrE,oEAAoE;AACpE,oEAAoE;AACpE,UAAU;AAEV,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAY,EACZ,EAAwB,EACxB,IAAwC;IAExC,MAAM,IAAI,GAAG,SAAS,CAAC,mBAAmB,EAAE;QAC1C,IAAI;QACJ,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE;KACvB,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function recordMetric(name: string, value: number, tags?: Record<string, string>): void;
2
+ export declare function flushMetrics(): Promise<void>;
3
+ /**
4
+ * Start the 30 s flush timer. Called once from `init()`. Idempotent.
5
+ * `clearMetricsTimer` is exposed for tests / teardown.
6
+ */
7
+ export declare function startMetricsTimer(): void;
8
+ export declare function __resetMetricsForTests(): void;
9
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AA6BA,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,IAAI,CASN;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAOlD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAQxC;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAM7C"}
package/lib/metrics.js ADDED
@@ -0,0 +1,64 @@
1
+ // v0.8.3 — custom metrics buffer.
2
+ //
3
+ // `recordMetric(name, value, tags?)` pushes a point into a fixed-size
4
+ // ring. A timer flushes the ring every 30 s (or when the buffer is
5
+ // full); captureException also forces a flush so the metrics line up
6
+ // with the error event in the dashboard. Best-effort: a flush failure
7
+ // drops the batch on the floor — metrics aren't critical telemetry.
8
+ //
9
+ // Why not one fetch per point: noisy loops (`recordMetric('frame', 1)`
10
+ // in a render hook) would burn the JS thread + saturate the device's
11
+ // outgoing connection pool. Batching makes the SDK safe to use as a
12
+ // cheap counter primitive.
13
+ import { getConfig, isInitialized } from './config';
14
+ import { sendMetricsBatch } from './transport';
15
+ const MAX_BUFFER = 500;
16
+ const FLUSH_INTERVAL_MS = 30_000;
17
+ let _buf = [];
18
+ let _timer = null;
19
+ export function recordMetric(name, value, tags) {
20
+ if (!isInitialized())
21
+ return;
22
+ if (typeof name !== 'string' || name.length === 0 || name.length > 200)
23
+ return;
24
+ if (typeof value !== 'number' || !Number.isFinite(value))
25
+ return;
26
+ if (tags && Object.keys(tags).length > 20)
27
+ return;
28
+ _buf.push({ name, tags, ts: new Date().toISOString(), value });
29
+ if (_buf.length >= MAX_BUFFER) {
30
+ void flushMetrics();
31
+ }
32
+ }
33
+ export async function flushMetrics() {
34
+ if (_buf.length === 0)
35
+ return;
36
+ const config = getConfig();
37
+ if (!config)
38
+ return;
39
+ const batch = _buf;
40
+ _buf = [];
41
+ await sendMetricsBatch(config.ingestUrl, config.token, batch);
42
+ }
43
+ /**
44
+ * Start the 30 s flush timer. Called once from `init()`. Idempotent.
45
+ * `clearMetricsTimer` is exposed for tests / teardown.
46
+ */
47
+ export function startMetricsTimer() {
48
+ if (_timer !== null)
49
+ return;
50
+ _timer = setInterval(() => {
51
+ void flushMetrics();
52
+ }, FLUSH_INTERVAL_MS);
53
+ // Don't keep the process alive solely for this timer (Node would).
54
+ // In RN setInterval is a NoopRef so this is harmless there.
55
+ _timer.unref?.();
56
+ }
57
+ export function __resetMetricsForTests() {
58
+ if (_timer !== null) {
59
+ clearInterval(_timer);
60
+ _timer = null;
61
+ }
62
+ _buf = [];
63
+ }
64
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,qEAAqE;AACrE,sEAAsE;AACtE,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,2BAA2B;AAE3B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAS/C,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC,IAAI,IAAI,GAAY,EAAE,CAAC;AACvB,IAAI,MAAM,GAA0C,IAAI,CAAC;AAEzD,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,KAAa,EACb,IAA6B;IAE7B,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO;IAC/E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO;IACjE,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO;IAClD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;QAC9B,KAAK,YAAY,EAAE,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,KAAK,GAAG,IAAI,CAAC;IACnB,IAAI,GAAG,EAAE,CAAC;IACV,MAAM,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO;IAC5B,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QACxB,KAAK,YAAY,EAAE,CAAC;IACtB,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACtB,mEAAmE;IACnE,4DAA4D;IAC3D,MAA4C,CAAC,KAAK,EAAE,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,aAAa,CAAC,MAAM,CAAC,CAAC;QACtB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,GAAG,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const RAGE_WINDOW_MS = 800;
2
+ export declare const RAGE_THRESHOLD = 3;
3
+ /** Given the per-target recent-tap buckets, a target id, and `now`,
4
+ * return `true` iff this tap crosses the rage threshold. Side
5
+ * effect: writes/clears the bucket inside `map` so successive
6
+ * taps after a triggered rage event don't immediately re-trigger. */
7
+ export declare function recordTap(map: Map<number, number[]>, target: number, now: number): boolean;
8
+ //# sourceMappingURL=rage-tap-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-tap-detector.d.ts","sourceRoot":"","sources":["../src/rage-tap-detector.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;sEAGsE;AACtE,wBAAgB,SAAS,CACvB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAUT"}
@@ -0,0 +1,21 @@
1
+ // v0.9.0 #12 — pure rage-tap detection logic. Lives outside the .tsx
2
+ // component so unit tests can import it without dragging in
3
+ // `react-native` (whose flow syntax breaks bun:test parser).
4
+ export const RAGE_WINDOW_MS = 800;
5
+ export const RAGE_THRESHOLD = 3;
6
+ /** Given the per-target recent-tap buckets, a target id, and `now`,
7
+ * return `true` iff this tap crosses the rage threshold. Side
8
+ * effect: writes/clears the bucket inside `map` so successive
9
+ * taps after a triggered rage event don't immediately re-trigger. */
10
+ export function recordTap(map, target, now) {
11
+ const previous = map.get(target) ?? [];
12
+ const fresh = previous.filter((t) => now - t <= RAGE_WINDOW_MS);
13
+ fresh.push(now);
14
+ if (fresh.length >= RAGE_THRESHOLD) {
15
+ map.delete(target);
16
+ return true;
17
+ }
18
+ map.set(target, fresh);
19
+ return false;
20
+ }
21
+ //# sourceMappingURL=rage-tap-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-tap-detector.js","sourceRoot":"","sources":["../src/rage-tap-detector.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,4DAA4D;AAC5D,6DAA6D;AAE7D,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC;;;sEAGsE;AACtE,MAAM,UAAU,SAAS,CACvB,GAA0B,EAC1B,MAAc,EACd,GAAW;IAEX,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,cAAc,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,IAAI,KAAK,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;QACnC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { type ViewProps } from 'react-native';
3
+ export declare function RageTapCapture({ children, ...rest }: ViewProps & {
4
+ children?: React.ReactNode;
5
+ }): React.JSX.Element;
6
+ //# sourceMappingURL=rage-tap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-tap.d.ts","sourceRoot":"","sources":["../src/rage-tap.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAShF,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,SAAS,GAAG;IAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAwBhE"}
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // v0.9.0 #12 — rage-tap / multi-click detection.
3
+ //
4
+ // Wrap your app root (typically next to ErrorBoundary) with
5
+ // `<sentori.RageTapCapture>{children}</sentori.RageTapCapture>`.
6
+ // We listen to bubble-phase `onTouchEnd` and emit a `ui.multiClick`
7
+ // breadcrumb when the same native target receives ≥ 3 taps within
8
+ // 800 ms. Pure observation — no event capture, no gesture
9
+ // interference; existing Touchables / Pressables / GestureHandler
10
+ // continue to fire normally.
11
+ import { useCallback, useRef } from 'react';
12
+ import { View } from 'react-native';
13
+ import { addBreadcrumb } from './breadcrumbs';
14
+ import { RAGE_THRESHOLD, RAGE_WINDOW_MS, recordTap, } from './rage-tap-detector';
15
+ export function RageTapCapture({ children, ...rest }) {
16
+ const recent = useRef(new Map());
17
+ const onTouchEnd = useCallback((e) => {
18
+ const target = e.nativeEvent?.target;
19
+ if (typeof target !== 'number')
20
+ return;
21
+ if (recordTap(recent.current, target, Date.now())) {
22
+ addBreadcrumb({
23
+ type: 'user',
24
+ data: {
25
+ kind: 'ui.multiClick',
26
+ target: String(target),
27
+ taps: RAGE_THRESHOLD,
28
+ windowMs: RAGE_WINDOW_MS,
29
+ },
30
+ });
31
+ }
32
+ }, []);
33
+ return (_jsx(View, { ...rest, onTouchEnd: onTouchEnd, children: children }));
34
+ }
35
+ //# sourceMappingURL=rage-tap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-tap.js","sourceRoot":"","sources":["../src/rage-tap.tsx"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,EAAE;AACF,4DAA4D;AAC5D,iEAAiE;AACjE,oEAAoE;AACpE,kEAAkE;AAClE,0DAA0D;AAC1D,kEAAkE;AAClE,6BAA6B;AAE7B,OAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,IAAI,EAA8C,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,cAAc,EACd,SAAS,GACV,MAAM,qBAAqB,CAAC;AAE7B,MAAM,UAAU,cAAc,CAAC,EAC7B,QAAQ,EACR,GAAG,IAAI,EACoC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAwB,IAAI,GAAG,EAAE,CAAC,CAAC;IAExD,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAwB,EAAE,EAAE;QAC1D,MAAM,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC;QACrC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO;QACvC,IAAI,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YAClD,aAAa,CAAC;gBACZ,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACJ,IAAI,EAAE,eAAe;oBACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;oBACtB,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,cAAc;iBACzB;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,KAAC,IAAI,OAAK,IAAI,EAAE,UAAU,EAAE,UAAU,YACnC,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
@@ -14,6 +14,18 @@ export declare const __peekQueue: () => readonly Event[];
14
14
  * this.
15
15
  */
16
16
  export declare const sendSessionPing: (ingestUrl: string, token: string, ping: unknown) => Promise<void>;
17
+ /**
18
+ * v0.8.3 — flush a batched set of custom metrics. The host SDK
19
+ * batches recordMetric() calls into a fixed-size ring (drained on
20
+ * a timer + at next captureException) so a busy loop doesn't spin
21
+ * up one fetch per point. Best-effort, no retry.
22
+ */
23
+ export declare const sendMetricsBatch: (ingestUrl: string, token: string, metrics: Array<{
24
+ name: string;
25
+ tags?: Record<string, string>;
26
+ ts?: string;
27
+ value: number;
28
+ }>) => Promise<void>;
17
29
  /**
18
30
  * v0.8.2 — submit a user-supplied bug report. Fire-and-forget; resolves
19
31
  * with the server-assigned id on success or `null` on any failure.
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAqBrC,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,IAUtC,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,IAOjC,CAAC;AAEF,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,IAAI,CAe/C,CAAC;AAqBF,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,IAAI,CAkB1C,CAAC;AA4FF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CAatD,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAOlC,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,SAAS,KAAK,EAAY,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,MAAM,OAAO,KACZ,OAAO,CAAC,IAAI,CAcd,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GACzB,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,QAAQ;IACN,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,KACA,OAAO,CAAC,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAiBvD,CAAC;AAMF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,EACf,MAAM,OAAO,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,EAC9C,MAAM;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAM;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,IAAI,CAAA;CAAO,KAC/C,OAAO,CAAC,OAAO,SAAS,EAAE,cAAc,GAAG,IAAI,CAmDjD,CAAC"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAqBrC,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,IAUtC,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,IAOjC,CAAC;AAEF,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,IAAI,CAe/C,CAAC;AAqBF,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,IAAI,CAkB1C,CAAC;AA4FF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CAatD,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAOlC,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,SAAS,KAAK,EAAY,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,MAAM,OAAO,KACZ,OAAO,CAAC,IAAI,CAcd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,SAAS,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,KACD,OAAO,CAAC,IAAI,CAed,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GACzB,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,QAAQ;IACN,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,KACA,OAAO,CAAC,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAiBvD,CAAC;AAMF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,EACf,MAAM,OAAO,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,EAC9C,MAAM;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAM;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,IAAI,CAAA;CAAO,KAC/C,OAAO,CAAC,OAAO,SAAS,EAAE,cAAc,GAAG,IAAI,CAmDjD,CAAC"}