@goliapkg/sentori-react-native 0.9.9 → 0.9.11

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.
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "platforms": ["apple", "android"],
3
3
  "apple": {
4
- "modules": ["SentoriModule"]
4
+ "modules": ["SentoriModule"],
5
+ "podspecPath": "SentoriReactNative.podspec"
5
6
  },
6
7
  "android": {
7
8
  "modules": ["com.sentori.SentoriModule"]
@@ -1 +1 @@
1
- {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AA+CA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B,mCAAmC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAoCrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAOjC;AA6CD;;2BAE2B;AAC3B,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AA8CA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B,mCAAmC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAkCrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAsED;;2BAE2B;AAC3B,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
package/lib/replay.js CHANGED
@@ -19,7 +19,6 @@
19
19
  import { startSpan } from '@goliapkg/sentori-core';
20
20
  import { getRegisteredMaskQuery } from './mask';
21
21
  import { describeWireframeNative } from './native';
22
- import { isNativeModuleLinked } from './native-loader';
23
22
  const TICK_INTERVAL_MS = 1000;
24
23
  const RING_SIZE = 60;
25
24
  /** Floor on tick period. < 250 ms (4 Hz) the native view-tree walk
@@ -41,23 +40,21 @@ export function startReplay(opts) {
41
40
  return;
42
41
  if (opts.mode !== 'wireframe')
43
42
  return;
44
- // Native replay needs the Sentori native module linked. Defensive
45
- // same pattern as other native peers — for Expo Go / unlinked
46
- // builds.
47
- if (!isNativeModuleLinked('Sentori') && !isNativeModuleLinked('SentoriModule')) {
43
+ // v0.9.10 gate via expo-modules-core's registry (same path the
44
+ // screenshot capture uses). The previous `isNativeModuleLinked`
45
+ // check looked at the legacy `RN.NativeModules` map, but the
46
+ // Sentori module is registered through expo-modules-core; the
47
+ // legacy map never sees it, so this branch returned "not linked"
48
+ // forever even with the pod correctly attached (Insight 2026-05-17).
49
+ const info = describeWireframeNative();
50
+ if (!info.bound) {
48
51
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
49
52
  // eslint-disable-next-line no-console
50
- console.warn('[sentori] replay: Sentori native module not linked — replay attachments will stay empty');
53
+ console.warn('[sentori] replay: Sentori native module not bound (expo-modules-core) — replay attachments will stay empty');
51
54
  }
52
- // Falls back silently. Replay rings stay empty; captureException
53
- // simply doesn't attach a replay.
54
55
  return;
55
56
  }
56
- // v0.9.9 — log once per start so Insight (or anyone) can confirm
57
- // whether the native module exposes captureWireframe at all,
58
- // distinguishing this from "ring never filled because tick threw".
59
57
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
60
- const info = describeWireframeNative();
61
58
  // eslint-disable-next-line no-console
62
59
  console.warn('[sentori] replay: starting', 'bound=', info.bound, 'hasCaptureWireframe=', info.hasCaptureWireframe);
63
60
  }
@@ -76,7 +73,11 @@ export function stopReplay() {
76
73
  _timer = null;
77
74
  }
78
75
  _nativeMod = null;
76
+ _emptyTickCount = 0;
77
+ _emptyTickLogStride = 1;
79
78
  }
79
+ let _emptyTickCount = 0;
80
+ let _emptyTickLogStride = 1;
80
81
  function captureTick() {
81
82
  if (!_running)
82
83
  return;
@@ -88,6 +89,25 @@ function captureTick() {
88
89
  _ring.push(snapshot);
89
90
  while (_ring.length > RING_SIZE)
90
91
  _ring.shift();
92
+ _emptyTickCount = 0;
93
+ _emptyTickLogStride = 1;
94
+ }
95
+ else if (typeof __DEV__ !== 'undefined' && __DEV__) {
96
+ // v0.9.11 — Insight 2026-05-17 Finding 6: tick fires hundreds
97
+ // of times but ring stays empty → native returned null/empty.
98
+ // Log on a back-off schedule (1st, 10th, 100th, …) so the
99
+ // diagnostic is visible without spamming Metro at 1 Hz for a
100
+ // 15-minute session.
101
+ _emptyTickCount += 1;
102
+ if (_emptyTickCount === 1 || _emptyTickCount === _emptyTickLogStride) {
103
+ // eslint-disable-next-line no-console
104
+ console.warn('[sentori] replay tick: native returned', snapshot === null
105
+ ? 'null'
106
+ : typeof snapshot === 'string'
107
+ ? `empty (length=${snapshot.length})`
108
+ : typeof snapshot, `(empty ticks so far: ${_emptyTickCount})`);
109
+ _emptyTickLogStride = Math.max(_emptyTickLogStride * 10, 10);
110
+ }
91
111
  }
92
112
  tickSpan.finish({ status: 'ok' });
93
113
  }
package/lib/replay.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.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.9",
3
+ "version": "0.9.11",
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/replay.ts CHANGED
@@ -21,7 +21,6 @@ import { startSpan } from '@goliapkg/sentori-core';
21
21
 
22
22
  import { getRegisteredMaskQuery } from './mask';
23
23
  import { describeWireframeNative } from './native';
24
- import { isNativeModuleLinked } from './native-loader';
25
24
 
26
25
  declare const __DEV__: boolean | undefined;
27
26
 
@@ -54,25 +53,23 @@ export type ReplayOptions = {
54
53
  export function startReplay(opts: ReplayOptions): void {
55
54
  if (_running) return;
56
55
  if (opts.mode !== 'wireframe') return;
57
- // Native replay needs the Sentori native module linked. Defensive
58
- // same pattern as other native peers — for Expo Go / unlinked
59
- // builds.
60
- if (!isNativeModuleLinked('Sentori') && !isNativeModuleLinked('SentoriModule')) {
56
+ // v0.9.10 gate via expo-modules-core's registry (same path the
57
+ // screenshot capture uses). The previous `isNativeModuleLinked`
58
+ // check looked at the legacy `RN.NativeModules` map, but the
59
+ // Sentori module is registered through expo-modules-core; the
60
+ // legacy map never sees it, so this branch returned "not linked"
61
+ // forever even with the pod correctly attached (Insight 2026-05-17).
62
+ const info = describeWireframeNative();
63
+ if (!info.bound) {
61
64
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
62
65
  // eslint-disable-next-line no-console
63
66
  console.warn(
64
- '[sentori] replay: Sentori native module not linked — replay attachments will stay empty',
67
+ '[sentori] replay: Sentori native module not bound (expo-modules-core) — replay attachments will stay empty',
65
68
  );
66
69
  }
67
- // Falls back silently. Replay rings stay empty; captureException
68
- // simply doesn't attach a replay.
69
70
  return;
70
71
  }
71
- // v0.9.9 — log once per start so Insight (or anyone) can confirm
72
- // whether the native module exposes captureWireframe at all,
73
- // distinguishing this from "ring never filled because tick threw".
74
72
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
75
- const info = describeWireframeNative();
76
73
  // eslint-disable-next-line no-console
77
74
  console.warn(
78
75
  '[sentori] replay: starting',
@@ -96,8 +93,13 @@ export function stopReplay(): void {
96
93
  _timer = null;
97
94
  }
98
95
  _nativeMod = null;
96
+ _emptyTickCount = 0;
97
+ _emptyTickLogStride = 1;
99
98
  }
100
99
 
100
+ let _emptyTickCount = 0;
101
+ let _emptyTickLogStride = 1;
102
+
101
103
  function captureTick(): void {
102
104
  if (!_running) return;
103
105
  const tickSpan = startSpan('sentori.replay.tick', { name: 'tick' });
@@ -107,6 +109,28 @@ function captureTick(): void {
107
109
  if (typeof snapshot === 'string' && snapshot.length > 0) {
108
110
  _ring.push(snapshot);
109
111
  while (_ring.length > RING_SIZE) _ring.shift();
112
+ _emptyTickCount = 0;
113
+ _emptyTickLogStride = 1;
114
+ } else if (typeof __DEV__ !== 'undefined' && __DEV__) {
115
+ // v0.9.11 — Insight 2026-05-17 Finding 6: tick fires hundreds
116
+ // of times but ring stays empty → native returned null/empty.
117
+ // Log on a back-off schedule (1st, 10th, 100th, …) so the
118
+ // diagnostic is visible without spamming Metro at 1 Hz for a
119
+ // 15-minute session.
120
+ _emptyTickCount += 1;
121
+ if (_emptyTickCount === 1 || _emptyTickCount === _emptyTickLogStride) {
122
+ // eslint-disable-next-line no-console
123
+ console.warn(
124
+ '[sentori] replay tick: native returned',
125
+ snapshot === null
126
+ ? 'null'
127
+ : typeof snapshot === 'string'
128
+ ? `empty (length=${snapshot.length})`
129
+ : typeof snapshot,
130
+ `(empty ticks so far: ${_emptyTickCount})`,
131
+ );
132
+ _emptyTickLogStride = Math.max(_emptyTickLogStride * 10, 10);
133
+ }
110
134
  }
111
135
  tickSpan.finish({ status: 'ok' });
112
136
  } catch (e) {