@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 +63 -0
- package/README.md +11 -1
- package/dist/expo-plugin.js +1 -1
- package/dist/expo-plugin.js.map +1 -1
- package/dist/expo-plugin.mjs +1 -1
- package/dist/expo-plugin.mjs.map +1 -1
- package/dist/index.d.mts +169 -10
- package/dist/index.d.ts +169 -10
- package/dist/index.js +748 -86
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +748 -86
- package/dist/index.mjs.map +1 -1
- package/native/android/build.gradle +3 -1
- package/package.json +5 -2
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
|
|
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
|
{
|
package/dist/expo-plugin.js
CHANGED
|
@@ -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.
|
|
35
|
+
pluginVersion: "0.3.1"
|
|
36
36
|
};
|
|
37
37
|
return next;
|
|
38
38
|
}
|
package/dist/expo-plugin.js.map
CHANGED
|
@@ -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.
|
|
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":[]}
|
package/dist/expo-plugin.mjs
CHANGED
|
@@ -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.
|
|
13
|
+
pluginVersion: "0.3.1"
|
|
14
14
|
};
|
|
15
15
|
return next;
|
|
16
16
|
}
|
package/dist/expo-plugin.mjs.map
CHANGED
|
@@ -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.
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* in-memory ring buffer
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 };
|