@allstak/react-native 0.3.1 → 0.3.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@allstak/react-native` are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.1] — 2026-05-11
9
+
10
+ ### Added
11
+
12
+ - Runtime `debugId` resolution per error frame via `globalThis._allstakDebugIds`.
13
+ - `debugMeta.images[]` aggregation in error payloads.
14
+
15
+ ### Fixed
16
+
17
+ - Error frames now include `debugId` field for precise source map matching.
18
+
19
+ ## [0.3.0] — 2026-05-08
20
+
21
+ ### Added
22
+
23
+ - Full automatic HTTP instrumentation (fetch interception).
24
+ - Hermes source map injection and upload pipeline.
25
+ - Expo config plugin for automatic source map handling.
26
+ - EAS Build post-bundle hook for CI source map uploads.
27
+
28
+ ## [0.2.0] — 2026-04-25
29
+
30
+ ### Added
31
+
32
+ - Scope management for tags, extras, and context.
33
+ - Distributed tracing with automatic request header propagation.
34
+ - Replay surrogate events for session context.
35
+ - Expo integration with config plugin.
36
+ - New Architecture (Fabric) detection.
37
+ - Navigation breadcrumb helpers.
38
+
39
+ ## [0.1.4] — 2026-04-10
40
+
41
+ ### Changed
42
+
43
+ - Standalone release on public npm as `@allstak/react-native`.
44
+
45
+ ### Added
46
+
47
+ - Native crash capture via `ErrorUtils.setGlobalHandler`.
48
+ - Unhandled promise rejection capture.
49
+ - `beforeSend` callback, `sampleRate`, `setTags`/`setExtra`/`setContext`.
50
+ - `flush()` with bounded timeout.
51
+ - Hermes stack trace parsing.
52
+ - Android and iOS native crash handler modules.
53
+
54
+ ## [0.1.1] — 2026-03-28
55
+
56
+ Initial professional release.
57
+
58
+ ### Added
59
+
60
+ - Core error capture with React Native stack parsing.
61
+ - Breadcrumb ring buffer (max 50).
62
+ - Fail-open transport with exponential backoff.
63
+ - Circuit breaker on 401 responses.
package/README.md CHANGED
@@ -215,7 +215,17 @@ React Native source maps become hands-off after adding one build hook for your b
215
215
 
216
216
  ### EAS / Expo
217
217
 
218
- Add the EAS post-build hook:
218
+ Add the AllStak config plugin to your `app.json` (or `app.config.js`):
219
+
220
+ ```json
221
+ {
222
+ "expo": {
223
+ "plugins": ["@allstak/react-native"]
224
+ }
225
+ }
226
+ ```
227
+
228
+ Then add the EAS post-build hook:
219
229
 
220
230
  ```json
221
231
  {
@@ -32,7 +32,7 @@ function withAllStak(config, options = {}) {
32
32
  release: options.release ?? existing.release,
33
33
  environment: options.environment ?? existing.environment,
34
34
  dist: options.dist ?? existing.dist,
35
- pluginVersion: "0.3.0"
35
+ pluginVersion: "0.3.1"
36
36
  };
37
37
  return next;
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/expo-plugin.ts"],"sourcesContent":["/**\n * Expo config plugin.\n *\n * Apply via `app.json`:\n *\n * {\n * \"expo\": {\n * \"plugins\": [\n * [\"@allstak/react-native\", { \"release\": \"mobile@1.2.3\", \"environment\": \"production\" }]\n * ]\n * }\n * }\n *\n * The plugin runs at `expo prebuild` / EAS build time and:\n *\n * 1. Adds the AllStak iOS pod (declared in `react-native.config.js`).\n * Expo's autolinking already picks this up — we just record metadata\n * so `expo doctor` can verify the install is wired.\n * 2. Stamps the chosen `release` into `expo-constants` extras so the JS\n * layer can read it at runtime via `Constants.expoConfig.extra._allstak`\n * without the host app needing to plumb it through env vars.\n * 3. Records that `@allstak/react-native` was loaded as an Expo plugin\n * for diagnostics.\n *\n * Pure config mutation — no native code is patched here. The native iOS\n * + Android modules under ./native are linked by Expo's existing\n * autolinking flow (which honors the `react-native.config.js` manifest).\n */\n\nexport interface AllStakExpoOptions {\n /** Release identifier (e.g. `mobile@1.2.3`). Stamped into `Constants.expoConfig.extra._allstak.release`. */\n release?: string;\n /** Environment label — `production`, `staging`, etc. */\n environment?: string;\n /** Optional dist tag (e.g. `ios-hermes`). Auto-detected at runtime if unset. */\n dist?: string;\n}\n\ninterface ExpoConfig {\n name?: string;\n extra?: Record<string, unknown>;\n plugins?: any[];\n [key: string]: any;\n}\n\ninterface ExpoConfigContext {\n modResults?: any;\n modRawConfig?: ExpoConfig;\n [key: string]: any;\n}\n\n/**\n * The plugin function itself. Expo's plugin runner calls it as\n * `(config, options) => modifiedConfig`. We avoid importing\n * `@expo/config-plugins` so the package has zero hard dependencies on the\n * Expo toolchain — the type checking happens at usage site instead.\n */\nfunction withAllStak(config: ExpoConfig & ExpoConfigContext, options: AllStakExpoOptions = {}): ExpoConfig {\n const next: ExpoConfig = { ...config };\n next.extra = { ...(config.extra ?? {}) };\n\n // Embed runtime-readable metadata under a namespaced key so we never\n // collide with the host app's other extras.\n const existing = (next.extra as any)._allstak ?? {};\n (next.extra as any)._allstak = {\n ...existing,\n release: options.release ?? existing.release,\n environment: options.environment ?? existing.environment,\n dist: options.dist ?? existing.dist,\n pluginVersion: '0.3.0',\n };\n\n return next;\n}\n\nexport default withAllStak;\n\n// Expose as a CommonJS function so `app.plugin.js`'s `require('./dist/expo-plugin.js')`\n// returns the plugin directly. The `declare const module` keeps the TS\n// type-checker happy without dragging in @types/node.\ndeclare const module: { exports: any };\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = withAllStak;\n module.exports.default = withAllStak;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDA,SAAS,YAAY,QAAwC,UAA8B,CAAC,GAAe;AACzG,QAAM,OAAmB,EAAE,GAAG,OAAO;AACrC,OAAK,QAAQ,EAAE,GAAI,OAAO,SAAS,CAAC,EAAG;AAIvC,QAAM,WAAY,KAAK,MAAc,YAAY,CAAC;AAClD,EAAC,KAAK,MAAc,WAAW;AAAA,IAC7B,GAAG;AAAA,IACH,SAAS,QAAQ,WAAW,SAAS;AAAA,IACrC,aAAa,QAAQ,eAAe,SAAS;AAAA,IAC7C,MAAM,QAAQ,QAAQ,SAAS;AAAA,IAC/B,eAAe;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,IAAO,sBAAQ;AAMf,IAAI,OAAO,WAAW,eAAe,OAAO,SAAS;AACnD,SAAO,UAAU;AACjB,SAAO,QAAQ,UAAU;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../src/expo-plugin.ts"],"sourcesContent":["/**\n * Expo config plugin.\n *\n * Apply via `app.json`:\n *\n * {\n * \"expo\": {\n * \"plugins\": [\n * [\"@allstak/react-native\", { \"release\": \"mobile@1.2.3\", \"environment\": \"production\" }]\n * ]\n * }\n * }\n *\n * The plugin runs at `expo prebuild` / EAS build time and:\n *\n * 1. Adds the AllStak iOS pod (declared in `react-native.config.js`).\n * Expo's autolinking already picks this up — we just record metadata\n * so `expo doctor` can verify the install is wired.\n * 2. Stamps the chosen `release` into `expo-constants` extras so the JS\n * layer can read it at runtime via `Constants.expoConfig.extra._allstak`\n * without the host app needing to plumb it through env vars.\n * 3. Records that `@allstak/react-native` was loaded as an Expo plugin\n * for diagnostics.\n *\n * Pure config mutation — no native code is patched here. The native iOS\n * + Android modules under ./native are linked by Expo's existing\n * autolinking flow (which honors the `react-native.config.js` manifest).\n */\n\nexport interface AllStakExpoOptions {\n /** Release identifier (e.g. `mobile@1.2.3`). Stamped into `Constants.expoConfig.extra._allstak.release`. */\n release?: string;\n /** Environment label — `production`, `staging`, etc. */\n environment?: string;\n /** Optional dist tag (e.g. `ios-hermes`). Auto-detected at runtime if unset. */\n dist?: string;\n}\n\ninterface ExpoConfig {\n name?: string;\n extra?: Record<string, unknown>;\n plugins?: any[];\n [key: string]: any;\n}\n\ninterface ExpoConfigContext {\n modResults?: any;\n modRawConfig?: ExpoConfig;\n [key: string]: any;\n}\n\n/**\n * The plugin function itself. Expo's plugin runner calls it as\n * `(config, options) => modifiedConfig`. We avoid importing\n * `@expo/config-plugins` so the package has zero hard dependencies on the\n * Expo toolchain — the type checking happens at usage site instead.\n */\nfunction withAllStak(config: ExpoConfig & ExpoConfigContext, options: AllStakExpoOptions = {}): ExpoConfig {\n const next: ExpoConfig = { ...config };\n next.extra = { ...(config.extra ?? {}) };\n\n // Embed runtime-readable metadata under a namespaced key so we never\n // collide with the host app's other extras.\n const existing = (next.extra as any)._allstak ?? {};\n (next.extra as any)._allstak = {\n ...existing,\n release: options.release ?? existing.release,\n environment: options.environment ?? existing.environment,\n dist: options.dist ?? existing.dist,\n pluginVersion: '0.3.1',\n };\n\n return next;\n}\n\nexport default withAllStak;\n\n// Expose as a CommonJS function so `app.plugin.js`'s `require('./dist/expo-plugin.js')`\n// returns the plugin directly. The `declare const module` keeps the TS\n// type-checker happy without dragging in @types/node.\ndeclare const module: { exports: any };\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = withAllStak;\n module.exports.default = withAllStak;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDA,SAAS,YAAY,QAAwC,UAA8B,CAAC,GAAe;AACzG,QAAM,OAAmB,EAAE,GAAG,OAAO;AACrC,OAAK,QAAQ,EAAE,GAAI,OAAO,SAAS,CAAC,EAAG;AAIvC,QAAM,WAAY,KAAK,MAAc,YAAY,CAAC;AAClD,EAAC,KAAK,MAAc,WAAW;AAAA,IAC7B,GAAG;AAAA,IACH,SAAS,QAAQ,WAAW,SAAS;AAAA,IACrC,aAAa,QAAQ,eAAe,SAAS;AAAA,IAC7C,MAAM,QAAQ,QAAQ,SAAS;AAAA,IAC/B,eAAe;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,IAAO,sBAAQ;AAMf,IAAI,OAAO,WAAW,eAAe,OAAO,SAAS;AACnD,SAAO,UAAU;AACjB,SAAO,QAAQ,UAAU;AAC3B;","names":[]}
@@ -10,7 +10,7 @@ function withAllStak(config, options = {}) {
10
10
  release: options.release ?? existing.release,
11
11
  environment: options.environment ?? existing.environment,
12
12
  dist: options.dist ?? existing.dist,
13
- pluginVersion: "0.3.0"
13
+ pluginVersion: "0.3.1"
14
14
  };
15
15
  return next;
16
16
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/expo-plugin.ts"],"sourcesContent":["/**\n * Expo config plugin.\n *\n * Apply via `app.json`:\n *\n * {\n * \"expo\": {\n * \"plugins\": [\n * [\"@allstak/react-native\", { \"release\": \"mobile@1.2.3\", \"environment\": \"production\" }]\n * ]\n * }\n * }\n *\n * The plugin runs at `expo prebuild` / EAS build time and:\n *\n * 1. Adds the AllStak iOS pod (declared in `react-native.config.js`).\n * Expo's autolinking already picks this up — we just record metadata\n * so `expo doctor` can verify the install is wired.\n * 2. Stamps the chosen `release` into `expo-constants` extras so the JS\n * layer can read it at runtime via `Constants.expoConfig.extra._allstak`\n * without the host app needing to plumb it through env vars.\n * 3. Records that `@allstak/react-native` was loaded as an Expo plugin\n * for diagnostics.\n *\n * Pure config mutation — no native code is patched here. The native iOS\n * + Android modules under ./native are linked by Expo's existing\n * autolinking flow (which honors the `react-native.config.js` manifest).\n */\n\nexport interface AllStakExpoOptions {\n /** Release identifier (e.g. `mobile@1.2.3`). Stamped into `Constants.expoConfig.extra._allstak.release`. */\n release?: string;\n /** Environment label — `production`, `staging`, etc. */\n environment?: string;\n /** Optional dist tag (e.g. `ios-hermes`). Auto-detected at runtime if unset. */\n dist?: string;\n}\n\ninterface ExpoConfig {\n name?: string;\n extra?: Record<string, unknown>;\n plugins?: any[];\n [key: string]: any;\n}\n\ninterface ExpoConfigContext {\n modResults?: any;\n modRawConfig?: ExpoConfig;\n [key: string]: any;\n}\n\n/**\n * The plugin function itself. Expo's plugin runner calls it as\n * `(config, options) => modifiedConfig`. We avoid importing\n * `@expo/config-plugins` so the package has zero hard dependencies on the\n * Expo toolchain — the type checking happens at usage site instead.\n */\nfunction withAllStak(config: ExpoConfig & ExpoConfigContext, options: AllStakExpoOptions = {}): ExpoConfig {\n const next: ExpoConfig = { ...config };\n next.extra = { ...(config.extra ?? {}) };\n\n // Embed runtime-readable metadata under a namespaced key so we never\n // collide with the host app's other extras.\n const existing = (next.extra as any)._allstak ?? {};\n (next.extra as any)._allstak = {\n ...existing,\n release: options.release ?? existing.release,\n environment: options.environment ?? existing.environment,\n dist: options.dist ?? existing.dist,\n pluginVersion: '0.3.0',\n };\n\n return next;\n}\n\nexport default withAllStak;\n\n// Expose as a CommonJS function so `app.plugin.js`'s `require('./dist/expo-plugin.js')`\n// returns the plugin directly. The `declare const module` keeps the TS\n// type-checker happy without dragging in @types/node.\ndeclare const module: { exports: any };\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = withAllStak;\n module.exports.default = withAllStak;\n}\n"],"mappings":";;;AAyDA,SAAS,YAAY,QAAwC,UAA8B,CAAC,GAAe;AACzG,QAAM,OAAmB,EAAE,GAAG,OAAO;AACrC,OAAK,QAAQ,EAAE,GAAI,OAAO,SAAS,CAAC,EAAG;AAIvC,QAAM,WAAY,KAAK,MAAc,YAAY,CAAC;AAClD,EAAC,KAAK,MAAc,WAAW;AAAA,IAC7B,GAAG;AAAA,IACH,SAAS,QAAQ,WAAW,SAAS;AAAA,IACrC,aAAa,QAAQ,eAAe,SAAS;AAAA,IAC7C,MAAM,QAAQ,QAAQ,SAAS;AAAA,IAC/B,eAAe;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,IAAO,sBAAQ;AAMf,IAAI,OAAO,WAAW,eAAe,OAAO,SAAS;AACnD,SAAO,UAAU;AACjB,SAAO,QAAQ,UAAU;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../src/expo-plugin.ts"],"sourcesContent":["/**\n * Expo config plugin.\n *\n * Apply via `app.json`:\n *\n * {\n * \"expo\": {\n * \"plugins\": [\n * [\"@allstak/react-native\", { \"release\": \"mobile@1.2.3\", \"environment\": \"production\" }]\n * ]\n * }\n * }\n *\n * The plugin runs at `expo prebuild` / EAS build time and:\n *\n * 1. Adds the AllStak iOS pod (declared in `react-native.config.js`).\n * Expo's autolinking already picks this up — we just record metadata\n * so `expo doctor` can verify the install is wired.\n * 2. Stamps the chosen `release` into `expo-constants` extras so the JS\n * layer can read it at runtime via `Constants.expoConfig.extra._allstak`\n * without the host app needing to plumb it through env vars.\n * 3. Records that `@allstak/react-native` was loaded as an Expo plugin\n * for diagnostics.\n *\n * Pure config mutation — no native code is patched here. The native iOS\n * + Android modules under ./native are linked by Expo's existing\n * autolinking flow (which honors the `react-native.config.js` manifest).\n */\n\nexport interface AllStakExpoOptions {\n /** Release identifier (e.g. `mobile@1.2.3`). Stamped into `Constants.expoConfig.extra._allstak.release`. */\n release?: string;\n /** Environment label — `production`, `staging`, etc. */\n environment?: string;\n /** Optional dist tag (e.g. `ios-hermes`). Auto-detected at runtime if unset. */\n dist?: string;\n}\n\ninterface ExpoConfig {\n name?: string;\n extra?: Record<string, unknown>;\n plugins?: any[];\n [key: string]: any;\n}\n\ninterface ExpoConfigContext {\n modResults?: any;\n modRawConfig?: ExpoConfig;\n [key: string]: any;\n}\n\n/**\n * The plugin function itself. Expo's plugin runner calls it as\n * `(config, options) => modifiedConfig`. We avoid importing\n * `@expo/config-plugins` so the package has zero hard dependencies on the\n * Expo toolchain — the type checking happens at usage site instead.\n */\nfunction withAllStak(config: ExpoConfig & ExpoConfigContext, options: AllStakExpoOptions = {}): ExpoConfig {\n const next: ExpoConfig = { ...config };\n next.extra = { ...(config.extra ?? {}) };\n\n // Embed runtime-readable metadata under a namespaced key so we never\n // collide with the host app's other extras.\n const existing = (next.extra as any)._allstak ?? {};\n (next.extra as any)._allstak = {\n ...existing,\n release: options.release ?? existing.release,\n environment: options.environment ?? existing.environment,\n dist: options.dist ?? existing.dist,\n pluginVersion: '0.3.1',\n };\n\n return next;\n}\n\nexport default withAllStak;\n\n// Expose as a CommonJS function so `app.plugin.js`'s `require('./dist/expo-plugin.js')`\n// returns the plugin directly. The `declare const module` keeps the TS\n// type-checker happy without dragging in @types/node.\ndeclare const module: { exports: any };\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = withAllStak;\n module.exports.default = withAllStak;\n}\n"],"mappings":";;;AAyDA,SAAS,YAAY,QAAwC,UAA8B,CAAC,GAAe;AACzG,QAAM,OAAmB,EAAE,GAAG,OAAO;AACrC,OAAK,QAAQ,EAAE,GAAI,OAAO,SAAS,CAAC,EAAG;AAIvC,QAAM,WAAY,KAAK,MAAc,YAAY,CAAC;AAClD,EAAC,KAAK,MAAc,WAAW;AAAA,IAC7B,GAAG;AAAA,IACH,SAAS,QAAQ,WAAW,SAAS;AAAA,IACrC,aAAa,QAAQ,eAAe,SAAS;AAAA,IAC7C,MAAM,QAAQ,QAAQ,SAAS;AAAA,IAC/B,eAAe;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,IAAO,sBAAQ;AAMf,IAAI,OAAO,WAAW,eAAe,OAAO,SAAS;AACnD,SAAO,UAAU;AACjB,SAAO,QAAQ,UAAU;AAC3B;","names":[]}
package/dist/index.d.mts CHANGED
@@ -1,22 +1,48 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  /**
4
- * Minimal HTTP transport for React Native. Uses the global `fetch` (always
5
- * present in RN >= 0.60) with a 3s timeout. Failed sends fall into a small
6
- * in-memory ring buffer that we retry on the next successful flush.
4
+ * Fail-open HTTP transport for React Native. Telemetry sends are best-effort:
5
+ * they use a short timeout, never reject into the host app, and fall into a
6
+ * bounded in-memory ring buffer with circuit-breaker backoff when AllStak is
7
+ * unavailable.
7
8
  *
8
9
  * No window, no AbortController fallback shims — RN exposes both natively.
9
10
  */
11
+ interface TransportStats {
12
+ queued: number;
13
+ sent: number;
14
+ failed: number;
15
+ dropped: number;
16
+ consecutiveFailures: number;
17
+ circuitOpenUntil: number;
18
+ lastTransportLatencyMs?: number;
19
+ lastFlushDurationMs?: number;
20
+ }
10
21
  declare class HttpTransport {
11
22
  private baseUrl;
12
23
  private apiKey;
24
+ private enabled;
13
25
  private buffer;
14
26
  private flushing;
15
- constructor(baseUrl: string, apiKey: string);
27
+ private consecutiveFailures;
28
+ private circuitOpenUntil;
29
+ private sent;
30
+ private failed;
31
+ private dropped;
32
+ private lastTransportLatencyMs;
33
+ private lastFlushDurationMs;
34
+ constructor(baseUrl: string, apiKey: string, enabled?: boolean);
16
35
  send(path: string, payload: unknown): Promise<void>;
36
+ private enqueueOrDispatch;
37
+ private dispatch;
17
38
  private doFetch;
39
+ private push;
40
+ private scheduleFlush;
18
41
  private flushBuffer;
42
+ private recordFailure;
19
43
  getBufferSize(): number;
44
+ noteDropped(count?: number): void;
45
+ getStats(): TransportStats;
20
46
  /**
21
47
  * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
22
48
  * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
@@ -44,6 +70,10 @@ declare class HttpTransport {
44
70
  /** What instrumentation hands to the module per request. */
45
71
  interface HttpRequestEvent {
46
72
  type: 'http_request';
73
+ traceId: string;
74
+ requestId: string;
75
+ spanId?: string;
76
+ parentSpanId?: string;
47
77
  method: string;
48
78
  url: string;
49
79
  statusCode?: number;
@@ -55,11 +85,19 @@ interface HttpRequestEvent {
55
85
  requestHeaders?: Record<string, string>;
56
86
  responseHeaders?: Record<string, string>;
57
87
  error?: string;
58
- traceId?: string;
88
+ requestBodyStatus?: string;
89
+ responseBodyStatus?: string;
90
+ requestBodyRedactedFields?: string[];
91
+ responseBodyRedactedFields?: string[];
92
+ requestBodyTruncated?: boolean;
93
+ responseBodyTruncated?: boolean;
94
+ capturePolicy?: string;
95
+ linkConfidence?: 'exact' | 'inferred' | 'weak' | 'none';
59
96
  }
60
97
  interface HttpRequestIngestItem {
61
98
  type: 'http_request';
62
99
  traceId: string;
100
+ requestId: string;
63
101
  direction: 'outbound';
64
102
  method: string;
65
103
  host: string;
@@ -74,6 +112,16 @@ interface HttpRequestIngestItem {
74
112
  requestHeaders?: Record<string, string>;
75
113
  responseHeaders?: Record<string, string>;
76
114
  error?: string;
115
+ spanId?: string;
116
+ parentSpanId?: string;
117
+ requestBodyStatus?: string;
118
+ responseBodyStatus?: string;
119
+ requestBodyRedactedFields?: string[];
120
+ responseBodyRedactedFields?: string[];
121
+ requestBodyTruncated?: boolean;
122
+ responseBodyTruncated?: boolean;
123
+ capturePolicy?: string;
124
+ linkConfidence?: 'exact' | 'inferred' | 'weak' | 'none';
77
125
  environment?: string;
78
126
  release?: string;
79
127
  dist?: string;
@@ -241,9 +289,19 @@ interface ReplaySurrogateOptions {
241
289
  }
242
290
  interface SurrogateEvent {
243
291
  ts: number;
244
- k: 'screen' | 'appstate' | 'manual';
292
+ k: 'screen' | 'appstate' | 'manual' | 'request' | 'exception' | 'response' | 'action' | 'retry';
245
293
  data: Record<string, unknown>;
246
294
  }
295
+ interface TimelineContext {
296
+ traceId?: string;
297
+ requestId?: string;
298
+ spanId?: string;
299
+ eventId?: string;
300
+ release?: string;
301
+ dist?: string;
302
+ screen?: string;
303
+ route?: string;
304
+ }
247
305
  declare class ReplaySurrogate {
248
306
  private transport;
249
307
  private buffer;
@@ -256,11 +314,13 @@ declare class ReplaySurrogate {
256
314
  /** Enable recording for this session if sample-rate roll passes. */
257
315
  start(): boolean;
258
316
  /** Record a screen view. Filters params through the safeParams allow-list. */
259
- recordScreenView(routeName: string, params?: Record<string, unknown>): void;
317
+ recordScreenView(routeName: string, params?: Record<string, unknown>, context?: TimelineContext): void;
260
318
  /** Record an AppState transition (foreground/background/inactive). */
261
- recordAppState(next: string): void;
319
+ recordAppState(next: string, context?: TimelineContext): void;
262
320
  /** Record a free-form, customer-validated checkpoint. */
263
- recordManual(label: string, data?: Record<string, unknown>): void;
321
+ recordManual(label: string, data?: Record<string, unknown>, context?: TimelineContext): void;
322
+ /** Record a forensic mobile session timeline marker. This is not replay. */
323
+ recordTimelineMarker(kind: SurrogateEvent['k'], label: string, data?: Record<string, unknown>, context?: TimelineContext): void;
264
324
  destroy(): void;
265
325
  /** @internal — for tests. */
266
326
  isActive(): boolean;
@@ -270,6 +330,28 @@ declare class ReplaySurrogate {
270
330
  private flush;
271
331
  }
272
332
 
333
+ /**
334
+ * URL + header + body redaction utilities for HTTP instrumentation.
335
+ *
336
+ * Hard rules:
337
+ * - Authorization, Cookie, X-API-Key, Set-Cookie are ALWAYS redacted
338
+ * (host app cannot opt back into capturing them).
339
+ * - Query params named `token`, `password`, `api_key`, `apikey`,
340
+ * `authorization`, `auth`, `secret`, `access_token`, `refresh_token`,
341
+ * `session` are ALWAYS redacted.
342
+ * - Host app may add additional names via `redactHeaders` /
343
+ * `redactQueryParams`; the always-list is the floor, not the ceiling.
344
+ * - Bodies are truncated to `maxBodyBytes` (default 4096) and replaced
345
+ * with `'<binary>'` when not safely-stringifiable.
346
+ *
347
+ * URL pattern matching for ignoredUrls / allowedUrls accepts strings
348
+ * (substring match) or RegExp (test-based). String matching is
349
+ * case-insensitive on the URL.
350
+ */
351
+ declare const ALWAYS_REDACT_HEADERS: Set<string>;
352
+ declare const ALWAYS_REDACT_QUERY: Set<string>;
353
+ declare const REDACTED = "[REDACTED]";
354
+ declare const DEFAULT_REDACT_BODY_FIELDS: string[];
273
355
  interface HttpTrackingOptions {
274
356
  /** Capture request body. Default false. Truncated to maxBodyBytes. */
275
357
  captureRequestBody?: boolean;
@@ -296,7 +378,38 @@ interface HttpTrackingOptions {
296
378
  allowedUrls?: (string | RegExp)[];
297
379
  /** Max bytes per captured body. Default 4096. */
298
380
  maxBodyBytes?: number;
381
+ /** Content types eligible for body capture. Default JSON + text payloads. */
382
+ allowedContentTypes?: string[];
383
+ /** Additional JSON body fields to redact recursively. */
384
+ redactBodyFields?: string[];
299
385
  }
386
+ interface CapturedBody {
387
+ body?: string;
388
+ status: 'disabled' | 'captured' | 'redacted' | 'truncated' | 'unsupported' | 'empty';
389
+ redactedFields: string[];
390
+ truncated: boolean;
391
+ capturePolicy: string;
392
+ }
393
+ /**
394
+ * Redact sensitive query-string params in a URL. Returns the sanitized
395
+ * URL string. Falls back to the input when URL parsing fails (relative
396
+ * URLs in test environments).
397
+ */
398
+ declare function redactUrl(url: string, opts: HttpTrackingOptions): string;
399
+ /**
400
+ * Filter + redact an HTTP header dictionary. Returns a NEW object — does
401
+ * not mutate the input. When `captureHeaders` is false returns undefined
402
+ * (no headers in the wire payload at all).
403
+ */
404
+ declare function sanitizeHeaders(headers: Record<string, string | string[] | undefined> | undefined, opts: HttpTrackingOptions): Record<string, string> | undefined;
405
+ /**
406
+ * Truncate + safely-stringify a body. Returns:
407
+ * - undefined when capture is disabled
408
+ * - the stringified body when it's a string / number / plain object
409
+ * - '<binary>' when it's a Blob / FormData / ArrayBuffer / etc
410
+ * - truncated string with `…[truncated]` suffix when over maxBodyBytes
411
+ */
412
+ declare function captureBodyResult(body: unknown, enabled: boolean, maxBodyBytes: number, opts?: HttpTrackingOptions, contentType?: string): CapturedBody;
300
413
 
301
414
  /**
302
415
  * Per-console-method capture flags. Defaults are set to keep the
@@ -398,6 +511,13 @@ interface AllStakConfig {
398
511
  * — the event is sent as-is so a buggy hook can't black-hole telemetry.
399
512
  */
400
513
  beforeSend?: (event: ErrorIngestPayload) => ErrorIngestPayload | null | undefined | Promise<ErrorIngestPayload | null | undefined>;
514
+ /**
515
+ * Optional fail-open screenshot capture. Off by default and provider-based
516
+ * so Expo/RN apps choose their own native or JS screenshot implementation.
517
+ * The SDK bounds timeout/size/sampling and drops screenshots before it can
518
+ * hurt app navigation, JS thread responsiveness, or telemetry delivery.
519
+ */
520
+ screenshot?: ScreenshotCaptureOptions;
401
521
  /** SDK identity overrides (set automatically by installReactNative). */
402
522
  sdkName?: string;
403
523
  sdkVersion?: string;
@@ -406,6 +526,28 @@ interface AllStakConfig {
406
526
  commitSha?: string;
407
527
  branch?: string;
408
528
  }
529
+ interface ScreenshotArtifact {
530
+ data?: string;
531
+ contentType?: 'image/png' | 'image/jpeg' | 'image/webp';
532
+ width?: number;
533
+ height?: number;
534
+ sizeBytes?: number;
535
+ redacted?: boolean;
536
+ redactionStrategy?: string;
537
+ }
538
+ interface ScreenshotCaptureOptions {
539
+ enabled?: boolean;
540
+ captureOnError?: boolean;
541
+ timeoutMs?: number;
542
+ maxBytes?: number;
543
+ sampleRate?: number;
544
+ provider?: (reason: {
545
+ type: 'error';
546
+ error: Error;
547
+ traceId?: string;
548
+ requestId?: string;
549
+ }) => ScreenshotArtifact | null | undefined | Promise<ScreenshotArtifact | null | undefined>;
550
+ }
409
551
  interface Breadcrumb {
410
552
  timestamp: string;
411
553
  type: string;
@@ -421,6 +563,7 @@ interface PayloadFrame {
421
563
  colno?: number;
422
564
  inApp?: boolean;
423
565
  platform?: string;
566
+ debugId?: string;
424
567
  }
425
568
  interface ErrorIngestPayload {
426
569
  exceptionClass: string;
@@ -435,6 +578,12 @@ interface ErrorIngestPayload {
435
578
  environment?: string;
436
579
  release?: string;
437
580
  sessionId?: string;
581
+ traceId?: string;
582
+ spanId?: string;
583
+ parentSpanId?: string;
584
+ requestId?: string;
585
+ replayId?: string;
586
+ service?: string;
438
587
  user?: {
439
588
  id?: string;
440
589
  email?: string;
@@ -442,6 +591,12 @@ interface ErrorIngestPayload {
442
591
  metadata?: Record<string, unknown>;
443
592
  breadcrumbs?: Breadcrumb[];
444
593
  fingerprint?: string[];
594
+ debugMeta?: {
595
+ images: Array<{
596
+ type: string;
597
+ debugId: string;
598
+ }>;
599
+ };
445
600
  }
446
601
  declare class AllStakClient {
447
602
  private transport;
@@ -517,8 +672,11 @@ declare class AllStakClient {
517
672
  }): void;
518
673
  getSessionId(): string;
519
674
  getConfig(): AllStakConfig;
675
+ getTransportStats(): TransportStats;
520
676
  destroy(): void;
521
677
  private sendLog;
678
+ private shouldCaptureScreenshot;
679
+ private withScreenshotMetadata;
522
680
  private passesSampleRate;
523
681
  /**
524
682
  * Returns the effective config layer = base config + every scope on the
@@ -590,6 +748,7 @@ declare const AllStak: {
590
748
  instrumentAxios<T = any>(axios: T): T;
591
749
  getSessionId(): string;
592
750
  getConfig(): AllStakConfig | null;
751
+ getTransportStats(): TransportStats;
593
752
  destroy(): void;
594
753
  /** @internal — exposed for testing */
595
754
  _getInstance(): AllStakClient | null;
@@ -870,4 +1029,4 @@ declare function __devTriggerNativeCrash(): Promise<void>;
870
1029
  */
871
1030
  declare function drainPendingNativeCrashes(release?: string): Promise<void>;
872
1031
 
873
- export { AllStak, AllStakClient, type AllStakConfig, AllStakProvider, type AllStakProviderProps, type ArchitectureInfo, type Breadcrumb, type ConsoleCaptureOptions, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, SDK_NAME, SDK_VERSION, Scope, __devTriggerNativeCrash, __resetAutoNavigationFlagForTest, __resetConsoleInstrumentationFlagForTest, __resetProviderInstanceForTest, __setNativeModuleForTest, applyArchitectureTags, detectArchitecture, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation, tryAutoInstrumentNavigation, useAllStak };
1032
+ export { ALWAYS_REDACT_HEADERS, ALWAYS_REDACT_QUERY, AllStak, AllStakClient, type AllStakConfig, AllStakProvider, type AllStakProviderProps, type ArchitectureInfo, type Breadcrumb, type ConsoleCaptureOptions, DEFAULT_REDACT_BODY_FIELDS, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, REDACTED, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, SDK_NAME, SDK_VERSION, Scope, type ScreenshotArtifact, type ScreenshotCaptureOptions, type TransportStats, __devTriggerNativeCrash, __resetAutoNavigationFlagForTest, __resetConsoleInstrumentationFlagForTest, __resetProviderInstanceForTest, __setNativeModuleForTest, applyArchitectureTags, captureBodyResult, detectArchitecture, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation, redactUrl, sanitizeHeaders, tryAutoInstrumentNavigation, useAllStak };