@allstak/react-native 0.3.0 → 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/AllStakRN.podspec +25 -0
- package/CHANGELOG.md +63 -0
- package/README.md +379 -145
- package/build-hooks/allstak-sourcemaps.gradle +132 -0
- package/build-hooks/eas-post-bundle.js +127 -0
- package/build-hooks/upload-sourcemaps.js +175 -0
- package/build-hooks/xcode-build-phase.sh +90 -0
- package/dist/build/sourcemaps.d.mts +94 -0
- package/dist/build/sourcemaps.d.ts +94 -0
- package/dist/build/sourcemaps.js +142 -0
- package/dist/build/sourcemaps.js.map +1 -0
- package/dist/build/sourcemaps.mjs +115 -0
- package/dist/build/sourcemaps.mjs.map +1 -0
- 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 +366 -29
- package/dist/index.d.ts +366 -29
- package/dist/index.js +1131 -160
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1126 -165
- package/dist/index.mjs.map +1 -1
- package/native/android/build.gradle +3 -1
- package/native/android/src/main/java/io/allstak/rn/AllStakRNModule.java +17 -0
- package/native/ios/AllStakRNModule.m +16 -0
- package/package.json +21 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,52 +17,103 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
33
|
+
ALWAYS_REDACT_HEADERS: () => ALWAYS_REDACT_HEADERS,
|
|
34
|
+
ALWAYS_REDACT_QUERY: () => ALWAYS_REDACT_QUERY,
|
|
23
35
|
AllStak: () => AllStak,
|
|
24
36
|
AllStakClient: () => AllStakClient,
|
|
37
|
+
AllStakProvider: () => AllStakProvider,
|
|
38
|
+
DEFAULT_REDACT_BODY_FIELDS: () => DEFAULT_REDACT_BODY_FIELDS,
|
|
25
39
|
HttpRequestModule: () => HttpRequestModule,
|
|
26
40
|
INGEST_HOST: () => INGEST_HOST,
|
|
41
|
+
REDACTED: () => REDACTED,
|
|
27
42
|
ReplaySurrogate: () => ReplaySurrogate,
|
|
28
43
|
SDK_NAME: () => SDK_NAME,
|
|
29
44
|
SDK_VERSION: () => SDK_VERSION,
|
|
30
45
|
Scope: () => Scope,
|
|
46
|
+
__devTriggerNativeCrash: () => __devTriggerNativeCrash,
|
|
47
|
+
__resetAutoNavigationFlagForTest: () => __resetAutoNavigationFlagForTest,
|
|
48
|
+
__resetConsoleInstrumentationFlagForTest: () => __resetConsoleInstrumentationFlagForTest,
|
|
49
|
+
__resetProviderInstanceForTest: () => __resetProviderInstanceForTest,
|
|
31
50
|
__setNativeModuleForTest: () => __setNativeModuleForTest,
|
|
32
51
|
applyArchitectureTags: () => applyArchitectureTags,
|
|
52
|
+
captureBodyResult: () => captureBodyResult,
|
|
33
53
|
detectArchitecture: () => detectArchitecture,
|
|
34
54
|
drainPendingNativeCrashes: () => drainPendingNativeCrashes,
|
|
35
55
|
installReactNative: () => installReactNative,
|
|
36
56
|
instrumentNavigationFromLinking: () => instrumentNavigationFromLinking,
|
|
37
|
-
instrumentReactNavigation: () => instrumentReactNavigation
|
|
57
|
+
instrumentReactNavigation: () => instrumentReactNavigation,
|
|
58
|
+
redactUrl: () => redactUrl,
|
|
59
|
+
sanitizeHeaders: () => sanitizeHeaders,
|
|
60
|
+
tryAutoInstrumentNavigation: () => tryAutoInstrumentNavigation,
|
|
61
|
+
useAllStak: () => useAllStak
|
|
38
62
|
});
|
|
39
63
|
module.exports = __toCommonJS(index_exports);
|
|
40
64
|
|
|
41
65
|
// src/transport.ts
|
|
42
|
-
var REQUEST_TIMEOUT =
|
|
66
|
+
var REQUEST_TIMEOUT = 2e3;
|
|
43
67
|
var MAX_BUFFER = 100;
|
|
68
|
+
var FAILURE_THRESHOLD = 3;
|
|
69
|
+
var BACKOFF_BASE_MS = 500;
|
|
70
|
+
var BACKOFF_MAX_MS = 3e4;
|
|
44
71
|
var HttpTransport = class {
|
|
45
|
-
constructor(baseUrl, apiKey) {
|
|
72
|
+
constructor(baseUrl, apiKey, enabled = true) {
|
|
46
73
|
this.baseUrl = baseUrl;
|
|
47
74
|
this.apiKey = apiKey;
|
|
75
|
+
this.enabled = enabled;
|
|
48
76
|
this.buffer = [];
|
|
49
77
|
this.flushing = false;
|
|
78
|
+
this.consecutiveFailures = 0;
|
|
79
|
+
this.circuitOpenUntil = 0;
|
|
80
|
+
this.sent = 0;
|
|
81
|
+
this.failed = 0;
|
|
82
|
+
this.dropped = 0;
|
|
83
|
+
}
|
|
84
|
+
send(path, payload) {
|
|
85
|
+
if (!this.enabled) {
|
|
86
|
+
this.noteDropped();
|
|
87
|
+
return Promise.resolve();
|
|
88
|
+
}
|
|
89
|
+
this.enqueueOrDispatch({ path, payload });
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
}
|
|
92
|
+
enqueueOrDispatch(item) {
|
|
93
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
94
|
+
this.push(item);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
void this.dispatch(item).catch(() => void 0);
|
|
50
98
|
}
|
|
51
|
-
async
|
|
99
|
+
async dispatch(item) {
|
|
52
100
|
try {
|
|
53
|
-
await this.doFetch(path, payload);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.
|
|
101
|
+
await this.doFetch(item.path, item.payload);
|
|
102
|
+
this.sent++;
|
|
103
|
+
this.consecutiveFailures = 0;
|
|
104
|
+
this.circuitOpenUntil = 0;
|
|
105
|
+
this.scheduleFlush();
|
|
106
|
+
} catch (err) {
|
|
107
|
+
this.failed++;
|
|
108
|
+
this.recordFailure(err);
|
|
109
|
+
this.push(item);
|
|
58
110
|
}
|
|
59
111
|
}
|
|
60
112
|
async doFetch(path, payload) {
|
|
61
113
|
const url = `${this.baseUrl}${path}`;
|
|
62
114
|
const controller = new AbortController();
|
|
63
115
|
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
116
|
+
const started = Date.now();
|
|
64
117
|
try {
|
|
65
118
|
const res = await fetch(url, {
|
|
66
119
|
method: "POST",
|
|
@@ -74,26 +127,77 @@ var HttpTransport = class {
|
|
|
74
127
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
75
128
|
} finally {
|
|
76
129
|
clearTimeout(timeoutId);
|
|
130
|
+
this.lastTransportLatencyMs = Date.now() - started;
|
|
77
131
|
}
|
|
78
132
|
}
|
|
133
|
+
push(item) {
|
|
134
|
+
if (this.buffer.length >= MAX_BUFFER) {
|
|
135
|
+
this.buffer.shift();
|
|
136
|
+
this.dropped++;
|
|
137
|
+
}
|
|
138
|
+
this.buffer.push(item);
|
|
139
|
+
}
|
|
140
|
+
scheduleFlush() {
|
|
141
|
+
if (this.flushing || this.buffer.length === 0) return;
|
|
142
|
+
const delay = Math.max(0, this.circuitOpenUntil - Date.now());
|
|
143
|
+
const timer = setTimeout(() => {
|
|
144
|
+
void this.flushBuffer().catch(() => void 0);
|
|
145
|
+
}, delay);
|
|
146
|
+
if (typeof timer === "object" && typeof timer.unref === "function") timer.unref();
|
|
147
|
+
}
|
|
79
148
|
async flushBuffer() {
|
|
80
149
|
if (this.flushing || this.buffer.length === 0) return;
|
|
81
150
|
this.flushing = true;
|
|
151
|
+
const started = Date.now();
|
|
82
152
|
try {
|
|
83
153
|
const items = this.buffer.splice(0, this.buffer.length);
|
|
84
154
|
for (const item of items) {
|
|
155
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
156
|
+
this.push(item);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
85
159
|
try {
|
|
86
160
|
await this.doFetch(item.path, item.payload);
|
|
87
|
-
|
|
161
|
+
this.sent++;
|
|
162
|
+
this.consecutiveFailures = 0;
|
|
163
|
+
this.circuitOpenUntil = 0;
|
|
164
|
+
} catch (err) {
|
|
165
|
+
this.failed++;
|
|
166
|
+
this.recordFailure(err);
|
|
167
|
+
this.push(item);
|
|
88
168
|
}
|
|
89
169
|
}
|
|
90
170
|
} finally {
|
|
171
|
+
this.lastFlushDurationMs = Date.now() - started;
|
|
91
172
|
this.flushing = false;
|
|
173
|
+
if (this.buffer.length > 0) this.scheduleFlush();
|
|
92
174
|
}
|
|
93
175
|
}
|
|
176
|
+
recordFailure(error) {
|
|
177
|
+
this.consecutiveFailures++;
|
|
178
|
+
if (this.consecutiveFailures < FAILURE_THRESHOLD) return;
|
|
179
|
+
const retryAfterMs = retryAfterFromError(error);
|
|
180
|
+
const backoff = retryAfterMs ?? jitteredBackoff(this.consecutiveFailures);
|
|
181
|
+
this.circuitOpenUntil = Date.now() + backoff;
|
|
182
|
+
}
|
|
94
183
|
getBufferSize() {
|
|
95
184
|
return this.buffer.length;
|
|
96
185
|
}
|
|
186
|
+
noteDropped(count = 1) {
|
|
187
|
+
this.dropped += Math.max(0, count);
|
|
188
|
+
}
|
|
189
|
+
getStats() {
|
|
190
|
+
return {
|
|
191
|
+
queued: this.buffer.length,
|
|
192
|
+
sent: this.sent,
|
|
193
|
+
failed: this.failed,
|
|
194
|
+
dropped: this.dropped,
|
|
195
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
196
|
+
circuitOpenUntil: this.circuitOpenUntil,
|
|
197
|
+
lastTransportLatencyMs: this.lastTransportLatencyMs,
|
|
198
|
+
lastFlushDurationMs: this.lastFlushDurationMs
|
|
199
|
+
};
|
|
200
|
+
}
|
|
97
201
|
/**
|
|
98
202
|
* Wait for the in-flight retry-buffer to drain. Resolves `true` if the
|
|
99
203
|
* buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
|
|
@@ -110,6 +214,14 @@ var HttpTransport = class {
|
|
|
110
214
|
return true;
|
|
111
215
|
}
|
|
112
216
|
};
|
|
217
|
+
function jitteredBackoff(failures) {
|
|
218
|
+
const exp = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** Math.min(8, failures - FAILURE_THRESHOLD));
|
|
219
|
+
return Math.floor(exp / 2 + Math.random() * (exp / 2));
|
|
220
|
+
}
|
|
221
|
+
function retryAfterFromError(error) {
|
|
222
|
+
const message = error instanceof Error ? error.message : "";
|
|
223
|
+
return /HTTP\s+(429|503)/.test(message) ? BACKOFF_MAX_MS : null;
|
|
224
|
+
}
|
|
113
225
|
|
|
114
226
|
// src/stack.ts
|
|
115
227
|
var V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?((?:.+?):(\d+):(\d+))\)?\s*$/;
|
|
@@ -164,6 +276,24 @@ function isInApp(filename) {
|
|
|
164
276
|
return true;
|
|
165
277
|
}
|
|
166
278
|
|
|
279
|
+
// src/utils/debug-id.ts
|
|
280
|
+
var REGISTRY_KEY = "_allstakDebugIds";
|
|
281
|
+
var cache = /* @__PURE__ */ new Map();
|
|
282
|
+
function resolveDebugId(filename) {
|
|
283
|
+
if (!filename) return void 0;
|
|
284
|
+
if (cache.has(filename)) return cache.get(filename) ?? void 0;
|
|
285
|
+
const registry = globalThis[REGISTRY_KEY];
|
|
286
|
+
if (registry && typeof registry === "object") {
|
|
287
|
+
const hit = registry[filename];
|
|
288
|
+
if (typeof hit === "string" && hit.length > 0) {
|
|
289
|
+
cache.set(filename, hit);
|
|
290
|
+
return hit;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
cache.set(filename, null);
|
|
294
|
+
return void 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
167
297
|
// src/scope.ts
|
|
168
298
|
var Scope = class {
|
|
169
299
|
constructor() {
|
|
@@ -375,6 +505,7 @@ var TracingModule = class {
|
|
|
375
505
|
}
|
|
376
506
|
if (!this.flushTimer) {
|
|
377
507
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
|
|
508
|
+
this.flushTimer?.unref?.();
|
|
378
509
|
}
|
|
379
510
|
}
|
|
380
511
|
flush() {
|
|
@@ -420,10 +551,11 @@ var ReplaySurrogate = class {
|
|
|
420
551
|
if (Math.random() >= this.opts.sampleRate) return false;
|
|
421
552
|
this.active = true;
|
|
422
553
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS2);
|
|
554
|
+
this.flushTimer?.unref?.();
|
|
423
555
|
return true;
|
|
424
556
|
}
|
|
425
557
|
/** Record a screen view. Filters params through the safeParams allow-list. */
|
|
426
|
-
recordScreenView(routeName, params) {
|
|
558
|
+
recordScreenView(routeName, params, context) {
|
|
427
559
|
if (!this.active) return;
|
|
428
560
|
const safe = {};
|
|
429
561
|
if (params && this.opts.safeParams.length > 0) {
|
|
@@ -431,17 +563,22 @@ var ReplaySurrogate = class {
|
|
|
431
563
|
if (key in params) safe[key] = params[key];
|
|
432
564
|
}
|
|
433
565
|
}
|
|
434
|
-
this.push({ ts: Date.now(), k: "screen", data: { route: routeName, params: safe } });
|
|
566
|
+
this.push({ ts: Date.now(), k: "screen", data: { route: routeName, params: safe, ...compact(context) } });
|
|
435
567
|
}
|
|
436
568
|
/** Record an AppState transition (foreground/background/inactive). */
|
|
437
|
-
recordAppState(next) {
|
|
569
|
+
recordAppState(next, context) {
|
|
438
570
|
if (!this.active) return;
|
|
439
|
-
this.push({ ts: Date.now(), k: "appstate", data: { state: next } });
|
|
571
|
+
this.push({ ts: Date.now(), k: "appstate", data: { state: next, ...compact(context) } });
|
|
440
572
|
}
|
|
441
573
|
/** Record a free-form, customer-validated checkpoint. */
|
|
442
|
-
recordManual(label, data) {
|
|
574
|
+
recordManual(label, data, context) {
|
|
575
|
+
if (!this.active) return;
|
|
576
|
+
this.push({ ts: Date.now(), k: "manual", data: { label, ...data ?? {}, ...compact(context) } });
|
|
577
|
+
}
|
|
578
|
+
/** Record a forensic mobile session timeline marker. This is not replay. */
|
|
579
|
+
recordTimelineMarker(kind, label, data, context) {
|
|
443
580
|
if (!this.active) return;
|
|
444
|
-
this.push({ ts: Date.now(), k:
|
|
581
|
+
this.push({ ts: Date.now(), k: kind, data: { label, ...data ?? {}, ...compact(context) } });
|
|
445
582
|
}
|
|
446
583
|
destroy() {
|
|
447
584
|
this.destroyed = true;
|
|
@@ -475,6 +612,14 @@ var ReplaySurrogate = class {
|
|
|
475
612
|
});
|
|
476
613
|
}
|
|
477
614
|
};
|
|
615
|
+
function compact(context) {
|
|
616
|
+
if (!context) return {};
|
|
617
|
+
const out = {};
|
|
618
|
+
for (const [key, value] of Object.entries(context)) {
|
|
619
|
+
if (value !== void 0 && value !== null && value !== "") out[key] = value;
|
|
620
|
+
}
|
|
621
|
+
return out;
|
|
622
|
+
}
|
|
478
623
|
|
|
479
624
|
// src/http-requests.ts
|
|
480
625
|
var INGEST_PATH = "/ingest/v1/http-requests";
|
|
@@ -486,6 +631,12 @@ function genTraceId() {
|
|
|
486
631
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
487
632
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
488
633
|
}
|
|
634
|
+
function genRequestId() {
|
|
635
|
+
return genTraceId();
|
|
636
|
+
}
|
|
637
|
+
function generateHttpId() {
|
|
638
|
+
return genTraceId();
|
|
639
|
+
}
|
|
489
640
|
function splitHostPath(url) {
|
|
490
641
|
try {
|
|
491
642
|
const u = new URL(url);
|
|
@@ -512,6 +663,7 @@ var HttpRequestModule = class {
|
|
|
512
663
|
const item = {
|
|
513
664
|
type: "http_request",
|
|
514
665
|
traceId: ev.traceId ?? genTraceId(),
|
|
666
|
+
requestId: ev.requestId ?? genRequestId(),
|
|
515
667
|
direction: "outbound",
|
|
516
668
|
method: (ev.method || "GET").toUpperCase(),
|
|
517
669
|
host,
|
|
@@ -526,6 +678,16 @@ var HttpRequestModule = class {
|
|
|
526
678
|
requestHeaders: ev.requestHeaders,
|
|
527
679
|
responseHeaders: ev.responseHeaders,
|
|
528
680
|
error: ev.error,
|
|
681
|
+
spanId: ev.spanId,
|
|
682
|
+
parentSpanId: ev.parentSpanId,
|
|
683
|
+
requestBodyStatus: ev.requestBodyStatus,
|
|
684
|
+
responseBodyStatus: ev.responseBodyStatus,
|
|
685
|
+
requestBodyRedactedFields: ev.requestBodyRedactedFields,
|
|
686
|
+
responseBodyRedactedFields: ev.responseBodyRedactedFields,
|
|
687
|
+
requestBodyTruncated: ev.requestBodyTruncated,
|
|
688
|
+
responseBodyTruncated: ev.responseBodyTruncated,
|
|
689
|
+
capturePolicy: ev.capturePolicy,
|
|
690
|
+
linkConfidence: ev.linkConfidence ?? "exact",
|
|
529
691
|
environment: this.defaults.environment,
|
|
530
692
|
release: this.defaults.release,
|
|
531
693
|
dist: this.defaults.dist,
|
|
@@ -544,7 +706,10 @@ var HttpRequestModule = class {
|
|
|
544
706
|
this.flush();
|
|
545
707
|
return;
|
|
546
708
|
}
|
|
547
|
-
if (!this.flushTimer)
|
|
709
|
+
if (!this.flushTimer) {
|
|
710
|
+
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS3);
|
|
711
|
+
this.flushTimer?.unref?.();
|
|
712
|
+
}
|
|
548
713
|
}
|
|
549
714
|
/** Snapshot of the last failed requests for error-linking. Newest last. */
|
|
550
715
|
getRecentFailed() {
|
|
@@ -596,6 +761,24 @@ var ALWAYS_REDACT_QUERY = /* @__PURE__ */ new Set([
|
|
|
596
761
|
"jwt"
|
|
597
762
|
]);
|
|
598
763
|
var REDACTED = "[REDACTED]";
|
|
764
|
+
var DEFAULT_REDACT_BODY_FIELDS = [
|
|
765
|
+
"password",
|
|
766
|
+
"passcode",
|
|
767
|
+
"otp",
|
|
768
|
+
"token",
|
|
769
|
+
"authorization",
|
|
770
|
+
"cookie",
|
|
771
|
+
"session",
|
|
772
|
+
"refresh_token",
|
|
773
|
+
"access_token",
|
|
774
|
+
"jwt",
|
|
775
|
+
"card",
|
|
776
|
+
"credit_card",
|
|
777
|
+
"iban",
|
|
778
|
+
"national_id",
|
|
779
|
+
"secret",
|
|
780
|
+
"api_key"
|
|
781
|
+
];
|
|
599
782
|
function shouldCaptureUrl(url, opts) {
|
|
600
783
|
if (!url) return false;
|
|
601
784
|
const lower = url.toLowerCase();
|
|
@@ -663,25 +846,125 @@ function sanitizeHeaders(headers, opts) {
|
|
|
663
846
|
}
|
|
664
847
|
return out;
|
|
665
848
|
}
|
|
666
|
-
function
|
|
667
|
-
if (!enabled)
|
|
668
|
-
|
|
849
|
+
function captureBodyResult(body, enabled, maxBodyBytes, opts = {}, contentType) {
|
|
850
|
+
if (!enabled) {
|
|
851
|
+
return {
|
|
852
|
+
status: "disabled",
|
|
853
|
+
redactedFields: [],
|
|
854
|
+
truncated: false,
|
|
855
|
+
capturePolicy: "body_capture_disabled"
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
if (body == null) {
|
|
859
|
+
return {
|
|
860
|
+
status: "empty",
|
|
861
|
+
redactedFields: [],
|
|
862
|
+
truncated: false,
|
|
863
|
+
capturePolicy: "empty_body"
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
const allowed = opts.allowedContentTypes ?? ["application/json", "text/", "application/problem+json"];
|
|
867
|
+
if (contentType && !allowed.some((needle) => contentType.toLowerCase().includes(needle.toLowerCase()))) {
|
|
868
|
+
return {
|
|
869
|
+
status: "unsupported",
|
|
870
|
+
redactedFields: [],
|
|
871
|
+
truncated: false,
|
|
872
|
+
capturePolicy: `unsupported_content_type:${contentType}`
|
|
873
|
+
};
|
|
874
|
+
}
|
|
669
875
|
let str;
|
|
876
|
+
let redactedFields = [];
|
|
670
877
|
if (typeof body === "string") str = body;
|
|
671
878
|
else if (typeof body === "number" || typeof body === "boolean") str = String(body);
|
|
672
879
|
else if (typeof body === "object") {
|
|
673
880
|
const tag = Object.prototype.toString.call(body);
|
|
674
|
-
if (tag !== "[object Object]" && tag !== "[object Array]")
|
|
881
|
+
if (tag !== "[object Object]" && tag !== "[object Array]") {
|
|
882
|
+
return {
|
|
883
|
+
body: "<binary>",
|
|
884
|
+
status: "unsupported",
|
|
885
|
+
redactedFields: [],
|
|
886
|
+
truncated: false,
|
|
887
|
+
capturePolicy: "unsupported_binary_body"
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
const redacted = redactJsonValue(body, opts);
|
|
891
|
+
redactedFields = redacted.redactedFields;
|
|
675
892
|
try {
|
|
676
|
-
str = JSON.stringify(
|
|
893
|
+
str = JSON.stringify(redacted.value);
|
|
677
894
|
} catch {
|
|
678
|
-
return
|
|
895
|
+
return {
|
|
896
|
+
body: "<unserializable>",
|
|
897
|
+
status: "unsupported",
|
|
898
|
+
redactedFields,
|
|
899
|
+
truncated: false,
|
|
900
|
+
capturePolicy: "unserializable_body"
|
|
901
|
+
};
|
|
679
902
|
}
|
|
680
903
|
} else {
|
|
681
|
-
return
|
|
904
|
+
return {
|
|
905
|
+
body: "<binary>",
|
|
906
|
+
status: "unsupported",
|
|
907
|
+
redactedFields: [],
|
|
908
|
+
truncated: false,
|
|
909
|
+
capturePolicy: "unsupported_body_type"
|
|
910
|
+
};
|
|
682
911
|
}
|
|
683
|
-
if (
|
|
684
|
-
|
|
912
|
+
if (typeof body === "string" && looksJson(contentType, str)) {
|
|
913
|
+
try {
|
|
914
|
+
const redacted = redactJsonValue(JSON.parse(str), opts);
|
|
915
|
+
redactedFields = redacted.redactedFields;
|
|
916
|
+
str = JSON.stringify(redacted.value);
|
|
917
|
+
} catch {
|
|
918
|
+
str = redactSensitiveText(str, opts);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
let truncated = false;
|
|
922
|
+
if (str.length > maxBodyBytes) {
|
|
923
|
+
str = str.slice(0, maxBodyBytes) + "\u2026[truncated]";
|
|
924
|
+
truncated = true;
|
|
925
|
+
}
|
|
926
|
+
return {
|
|
927
|
+
body: str,
|
|
928
|
+
status: truncated ? "truncated" : redactedFields.length > 0 ? "redacted" : "captured",
|
|
929
|
+
redactedFields: Array.from(new Set(redactedFields)).sort(),
|
|
930
|
+
truncated,
|
|
931
|
+
capturePolicy: "opt_in_body_capture"
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function looksJson(contentType, body) {
|
|
935
|
+
if (contentType && contentType.toLowerCase().includes("json")) return true;
|
|
936
|
+
const trimmed = body.trim();
|
|
937
|
+
return trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
938
|
+
}
|
|
939
|
+
function redactJsonValue(value, opts, path = "") {
|
|
940
|
+
const fieldSet = new Set([...DEFAULT_REDACT_BODY_FIELDS, ...opts.redactBodyFields ?? []].map((v) => v.toLowerCase()));
|
|
941
|
+
const redactedFields = [];
|
|
942
|
+
const walk = (input, currentPath) => {
|
|
943
|
+
if (Array.isArray(input)) return input.map((item, index) => walk(item, `${currentPath}[${index}]`));
|
|
944
|
+
if (!input || typeof input !== "object") return input;
|
|
945
|
+
const out = {};
|
|
946
|
+
for (const [key, raw] of Object.entries(input)) {
|
|
947
|
+
const keyLower = key.toLowerCase();
|
|
948
|
+
const nextPath = currentPath ? `${currentPath}.${key}` : key;
|
|
949
|
+
if (fieldSet.has(keyLower) || keyLower.includes("token") || keyLower.includes("password")) {
|
|
950
|
+
out[key] = REDACTED;
|
|
951
|
+
redactedFields.push(nextPath);
|
|
952
|
+
} else {
|
|
953
|
+
out[key] = walk(raw, nextPath);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return out;
|
|
957
|
+
};
|
|
958
|
+
return { value: walk(value, path), redactedFields };
|
|
959
|
+
}
|
|
960
|
+
function redactSensitiveText(input, opts) {
|
|
961
|
+
const fields = [...DEFAULT_REDACT_BODY_FIELDS, ...opts.redactBodyFields ?? []];
|
|
962
|
+
let out = input;
|
|
963
|
+
for (const key of fields) {
|
|
964
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
965
|
+
out = out.replace(new RegExp(`("${escaped}"\\s*:\\s*)"[^"]*"`, "gi"), `$1"${REDACTED}"`);
|
|
966
|
+
}
|
|
967
|
+
return out;
|
|
685
968
|
}
|
|
686
969
|
|
|
687
970
|
// src/http-instrumentation.ts
|
|
@@ -691,12 +974,16 @@ var AXIOS_FLAG = /* @__PURE__ */ Symbol.for("allstak.http.axios.instrumented");
|
|
|
691
974
|
var DEFAULT_MAX_BODY = 4096;
|
|
692
975
|
var _currentModule = null;
|
|
693
976
|
var _currentOpts = null;
|
|
977
|
+
var _currentRuntime = null;
|
|
694
978
|
function currentModule() {
|
|
695
979
|
return _currentModule;
|
|
696
980
|
}
|
|
697
981
|
function currentOpts() {
|
|
698
982
|
return _currentOpts;
|
|
699
983
|
}
|
|
984
|
+
function currentRuntime() {
|
|
985
|
+
return _currentRuntime;
|
|
986
|
+
}
|
|
700
987
|
function safeCapture(ev) {
|
|
701
988
|
try {
|
|
702
989
|
currentModule()?.capture(ev);
|
|
@@ -713,6 +1000,8 @@ function bind(opts, ownIngestHost) {
|
|
|
713
1000
|
ignoredUrls: opts.ignoredUrls ?? [],
|
|
714
1001
|
allowedUrls: opts.allowedUrls ?? [],
|
|
715
1002
|
maxBodyBytes: opts.maxBodyBytes ?? DEFAULT_MAX_BODY,
|
|
1003
|
+
allowedContentTypes: opts.allowedContentTypes ?? ["application/json", "text/", "application/problem+json"],
|
|
1004
|
+
redactBodyFields: opts.redactBodyFields ?? [],
|
|
716
1005
|
ownIngestPrefix: ownIngestHost.replace(/\/$/, "")
|
|
717
1006
|
};
|
|
718
1007
|
}
|
|
@@ -759,6 +1048,77 @@ function headersToObject(h) {
|
|
|
759
1048
|
}
|
|
760
1049
|
return {};
|
|
761
1050
|
}
|
|
1051
|
+
function normalizeTraceId(traceId) {
|
|
1052
|
+
const hex = traceId.replace(/[^a-fA-F0-9]/g, "").toLowerCase();
|
|
1053
|
+
return (hex + "00000000000000000000000000000000").slice(0, 32);
|
|
1054
|
+
}
|
|
1055
|
+
function normalizeSpanId(spanId) {
|
|
1056
|
+
const hex = spanId.replace(/[^a-fA-F0-9]/g, "").toLowerCase();
|
|
1057
|
+
return (hex + "0000000000000000").slice(0, 16);
|
|
1058
|
+
}
|
|
1059
|
+
function createRequestContext(method, url) {
|
|
1060
|
+
const runtime = currentRuntime();
|
|
1061
|
+
if (!runtime) return null;
|
|
1062
|
+
const requestId = generateHttpId();
|
|
1063
|
+
const parentSpanId = runtime.tracing.getCurrentSpanId() ?? "";
|
|
1064
|
+
const span = runtime.tracing.startSpan("mobile.http", {
|
|
1065
|
+
description: `${method.toUpperCase()} ${url}`,
|
|
1066
|
+
tags: { requestId, method: method.toUpperCase(), platform: runtime.platform ?? "react-native" }
|
|
1067
|
+
});
|
|
1068
|
+
const traceId = runtime.tracing.getTraceId();
|
|
1069
|
+
const spanId = span.spanId;
|
|
1070
|
+
return {
|
|
1071
|
+
traceId,
|
|
1072
|
+
requestId,
|
|
1073
|
+
spanId,
|
|
1074
|
+
parentSpanId,
|
|
1075
|
+
traceparent: `00-${normalizeTraceId(traceId)}-${normalizeSpanId(spanId)}-01`,
|
|
1076
|
+
span
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function propagationHeaders(ctx) {
|
|
1080
|
+
const headers = {
|
|
1081
|
+
traceparent: ctx.traceparent,
|
|
1082
|
+
"x-allstak-trace-id": ctx.traceId,
|
|
1083
|
+
"x-allstak-request-id": ctx.requestId
|
|
1084
|
+
};
|
|
1085
|
+
if (ctx.parentSpanId) headers["x-allstak-parent-span-id"] = ctx.parentSpanId;
|
|
1086
|
+
return headers;
|
|
1087
|
+
}
|
|
1088
|
+
function mergeHeaders(headers, propagation) {
|
|
1089
|
+
const entries = Object.entries(propagation);
|
|
1090
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
1091
|
+
const next2 = new Headers(headers);
|
|
1092
|
+
for (const [k, v] of entries) if (!next2.has(k)) next2.set(k, v);
|
|
1093
|
+
return next2;
|
|
1094
|
+
}
|
|
1095
|
+
if (Array.isArray(headers)) {
|
|
1096
|
+
const existing = new Set(headers.map(([k]) => String(k).toLowerCase()));
|
|
1097
|
+
const next2 = [...headers];
|
|
1098
|
+
for (const [k, v] of entries) if (!existing.has(k.toLowerCase())) next2.push([k, v]);
|
|
1099
|
+
return next2;
|
|
1100
|
+
}
|
|
1101
|
+
const next = { ...headers ?? {} };
|
|
1102
|
+
const lower = new Set(Object.keys(next).map((k) => k.toLowerCase()));
|
|
1103
|
+
for (const [k, v] of entries) if (!lower.has(k.toLowerCase())) next[k] = v;
|
|
1104
|
+
return next;
|
|
1105
|
+
}
|
|
1106
|
+
function injectFetchHeaders(input, init, ctx) {
|
|
1107
|
+
const headers = mergeHeaders(init?.headers ?? (input && typeof input === "object" ? input.headers : void 0), propagationHeaders(ctx));
|
|
1108
|
+
return { input, init: { ...init ?? {}, headers } };
|
|
1109
|
+
}
|
|
1110
|
+
function recordTimeline(kind, label, ctx, data) {
|
|
1111
|
+
try {
|
|
1112
|
+
currentRuntime()?.replay?.recordTimelineMarker?.(kind, label, data, {
|
|
1113
|
+
traceId: ctx.traceId,
|
|
1114
|
+
requestId: ctx.requestId,
|
|
1115
|
+
spanId: ctx.spanId,
|
|
1116
|
+
release: currentRuntime()?.release,
|
|
1117
|
+
dist: currentRuntime()?.dist
|
|
1118
|
+
});
|
|
1119
|
+
} catch {
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
762
1122
|
function patchFetch() {
|
|
763
1123
|
const g = globalThis;
|
|
764
1124
|
if (typeof g.fetch !== "function") return;
|
|
@@ -776,23 +1136,37 @@ function patchFetch() {
|
|
|
776
1136
|
return original.call(this, input, init);
|
|
777
1137
|
}
|
|
778
1138
|
const start = Date.now();
|
|
779
|
-
const
|
|
780
|
-
const
|
|
1139
|
+
const ctx = createRequestContext(method, sanitizedUrl);
|
|
1140
|
+
const requestInit = ctx ? injectFetchHeaders(input, init, ctx).init : init;
|
|
1141
|
+
if (ctx) recordTimeline("request", "request_started", ctx, { method, url: sanitizedUrl });
|
|
1142
|
+
const reqHeaders = sanitizeHeaders(headersToObject(requestInit?.headers ?? (input && input.headers)), opts);
|
|
1143
|
+
const reqBody = captureBodyResult(requestInit?.body, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
781
1144
|
const reqSize = safeByteLength(typeof init?.body === "string" ? init.body : void 0);
|
|
782
1145
|
let response;
|
|
783
1146
|
try {
|
|
784
|
-
response = await original.call(this, input,
|
|
1147
|
+
response = await original.call(this, input, requestInit);
|
|
785
1148
|
} catch (err) {
|
|
1149
|
+
ctx?.span.finish("error");
|
|
1150
|
+
if (ctx) recordTimeline("exception", "request_failed", ctx, { method, url: sanitizedUrl, error: String(err?.message ?? err) });
|
|
786
1151
|
safeCapture({
|
|
787
1152
|
type: "http_request",
|
|
1153
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1154
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1155
|
+
spanId: ctx?.spanId,
|
|
1156
|
+
parentSpanId: ctx?.parentSpanId,
|
|
788
1157
|
method,
|
|
789
1158
|
url: sanitizedUrl,
|
|
790
1159
|
statusCode: 0,
|
|
791
1160
|
durationMs: Date.now() - start,
|
|
792
|
-
requestBody: reqBody,
|
|
1161
|
+
requestBody: reqBody.body,
|
|
793
1162
|
requestHeaders: reqHeaders,
|
|
794
1163
|
requestSize: reqSize,
|
|
795
|
-
|
|
1164
|
+
requestBodyStatus: reqBody.status,
|
|
1165
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1166
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1167
|
+
capturePolicy: reqBody.capturePolicy,
|
|
1168
|
+
error: String(err?.message ?? err),
|
|
1169
|
+
linkConfidence: "exact"
|
|
796
1170
|
});
|
|
797
1171
|
throw err;
|
|
798
1172
|
}
|
|
@@ -808,25 +1182,41 @@ function patchFetch() {
|
|
|
808
1182
|
try {
|
|
809
1183
|
const cloned = response.clone();
|
|
810
1184
|
const text = await cloned.text();
|
|
811
|
-
respBody =
|
|
1185
|
+
respBody = captureBodyResult(text, true, opts.maxBodyBytes, opts, respHeaders?.["content-type"]).body;
|
|
812
1186
|
if (respSize == null) respSize = safeByteLength(text);
|
|
813
1187
|
} catch {
|
|
814
1188
|
}
|
|
815
1189
|
}
|
|
816
1190
|
} catch {
|
|
817
1191
|
}
|
|
1192
|
+
const respBodyResult = captureBodyResult(respBody, opts.captureResponseBody && respBody !== void 0, opts.maxBodyBytes, opts, respHeaders?.["content-type"]);
|
|
1193
|
+
const isError = response.status >= 400;
|
|
1194
|
+
ctx?.span.setTag("requestId", ctx.requestId).setTag("http.status_code", String(response.status)).finish(isError ? "error" : "ok");
|
|
1195
|
+
if (ctx) recordTimeline(isError ? "exception" : "response", isError ? "request_failed" : "response_received", ctx, { statusCode: response.status, durationMs });
|
|
818
1196
|
safeCapture({
|
|
819
1197
|
type: "http_request",
|
|
1198
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1199
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1200
|
+
spanId: ctx?.spanId,
|
|
1201
|
+
parentSpanId: ctx?.parentSpanId,
|
|
820
1202
|
method,
|
|
821
1203
|
url: sanitizedUrl,
|
|
822
1204
|
statusCode: response.status,
|
|
823
1205
|
durationMs,
|
|
824
|
-
requestBody: reqBody,
|
|
1206
|
+
requestBody: reqBody.body,
|
|
825
1207
|
requestHeaders: reqHeaders,
|
|
826
1208
|
requestSize: reqSize,
|
|
827
|
-
responseBody:
|
|
1209
|
+
responseBody: respBodyResult.body,
|
|
828
1210
|
responseHeaders: respHeaders,
|
|
829
|
-
responseSize: respSize
|
|
1211
|
+
responseSize: respSize,
|
|
1212
|
+
requestBodyStatus: reqBody.status,
|
|
1213
|
+
responseBodyStatus: respBodyResult.status,
|
|
1214
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1215
|
+
responseBodyRedactedFields: respBodyResult.redactedFields,
|
|
1216
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1217
|
+
responseBodyTruncated: respBodyResult.truncated,
|
|
1218
|
+
capturePolicy: `${reqBody.capturePolicy};${respBodyResult.capturePolicy}`,
|
|
1219
|
+
linkConfidence: "exact"
|
|
830
1220
|
});
|
|
831
1221
|
return response;
|
|
832
1222
|
};
|
|
@@ -864,7 +1254,17 @@ function patchXhr() {
|
|
|
864
1254
|
return origSend.call(this, body);
|
|
865
1255
|
}
|
|
866
1256
|
const reqHeaders = sanitizeHeaders(this.__allstak_headers__, opts);
|
|
867
|
-
const
|
|
1257
|
+
const ctx = createRequestContext(method, sanitizedUrl);
|
|
1258
|
+
if (ctx) {
|
|
1259
|
+
for (const [k, v] of Object.entries(propagationHeaders(ctx))) {
|
|
1260
|
+
try {
|
|
1261
|
+
origSetRequestHeader.call(this, k, v);
|
|
1262
|
+
} catch {
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
recordTimeline("request", "request_started", ctx, { method, url: sanitizedUrl });
|
|
1266
|
+
}
|
|
1267
|
+
const reqBody = captureBodyResult(body, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
868
1268
|
const reqSize = safeByteLength(typeof body === "string" ? body : void 0);
|
|
869
1269
|
const finish = (statusCode, error) => {
|
|
870
1270
|
const durationMs = Date.now() - start;
|
|
@@ -882,28 +1282,43 @@ function patchXhr() {
|
|
|
882
1282
|
}
|
|
883
1283
|
respHeaders = sanitizeHeaders(dict, liveOpts);
|
|
884
1284
|
}
|
|
1285
|
+
let respBodyResult = captureBodyResult(void 0, false, liveOpts.maxBodyBytes, liveOpts);
|
|
885
1286
|
if (liveOpts.captureResponseBody) {
|
|
886
1287
|
const text = this.responseText;
|
|
887
1288
|
if (typeof text === "string") {
|
|
888
|
-
|
|
1289
|
+
respBodyResult = captureBodyResult(text, true, liveOpts.maxBodyBytes, liveOpts, respHeaders?.["content-type"]);
|
|
1290
|
+
respBody = respBodyResult.body;
|
|
889
1291
|
respSize = safeByteLength(text);
|
|
890
1292
|
}
|
|
891
1293
|
}
|
|
892
1294
|
} catch {
|
|
893
1295
|
}
|
|
1296
|
+
const failed = !!error || statusCode >= 400;
|
|
1297
|
+
ctx?.span.setTag("requestId", ctx.requestId).setTag("http.status_code", String(statusCode)).finish(failed ? "error" : "ok");
|
|
1298
|
+
if (ctx) recordTimeline(failed ? "exception" : "response", failed ? "request_failed" : "response_received", ctx, { statusCode, durationMs, error });
|
|
894
1299
|
safeCapture({
|
|
895
1300
|
type: "http_request",
|
|
1301
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1302
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1303
|
+
spanId: ctx?.spanId,
|
|
1304
|
+
parentSpanId: ctx?.parentSpanId,
|
|
896
1305
|
method,
|
|
897
1306
|
url: sanitizedUrl,
|
|
898
1307
|
statusCode,
|
|
899
1308
|
durationMs,
|
|
900
|
-
requestBody: reqBody,
|
|
1309
|
+
requestBody: reqBody.body,
|
|
901
1310
|
requestHeaders: reqHeaders,
|
|
902
1311
|
requestSize: reqSize,
|
|
903
1312
|
responseBody: respBody,
|
|
904
1313
|
responseHeaders: respHeaders,
|
|
905
1314
|
responseSize: respSize,
|
|
906
|
-
|
|
1315
|
+
requestBodyStatus: reqBody.status,
|
|
1316
|
+
responseBodyStatus: respBody ? "captured" : opts.captureResponseBody ? "empty" : "disabled",
|
|
1317
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1318
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1319
|
+
capturePolicy: reqBody.capturePolicy,
|
|
1320
|
+
error,
|
|
1321
|
+
linkConfidence: "exact"
|
|
907
1322
|
});
|
|
908
1323
|
};
|
|
909
1324
|
this.addEventListener?.("load", () => finish(this.status || 0));
|
|
@@ -922,10 +1337,17 @@ function instrumentAxiosInstance(axiosInstance, module2, opts) {
|
|
|
922
1337
|
axiosInstance.interceptors.request.use((config) => {
|
|
923
1338
|
try {
|
|
924
1339
|
const rawUrl = (config.baseURL ? config.baseURL.replace(/\/$/, "") : "") + (config.url || "");
|
|
1340
|
+
const method = String(config.method || "GET").toUpperCase();
|
|
1341
|
+
const ctx = createRequestContext(method, rawUrl);
|
|
1342
|
+
if (ctx) {
|
|
1343
|
+
config.headers = mergeHeaders(config.headers, propagationHeaders(ctx));
|
|
1344
|
+
recordTimeline("request", "request_started", ctx, { method, url: rawUrl });
|
|
1345
|
+
}
|
|
925
1346
|
reqStarts.set(config, {
|
|
926
1347
|
start: Date.now(),
|
|
927
|
-
method
|
|
928
|
-
rawUrl
|
|
1348
|
+
method,
|
|
1349
|
+
rawUrl,
|
|
1350
|
+
ctx
|
|
929
1351
|
});
|
|
930
1352
|
} catch {
|
|
931
1353
|
}
|
|
@@ -939,21 +1361,36 @@ function instrumentAxiosInstance(axiosInstance, module2, opts) {
|
|
|
939
1361
|
if (!shouldCaptureUrl(meta.rawUrl, opts)) return;
|
|
940
1362
|
const sanitizedUrl = redactUrl(meta.rawUrl, opts);
|
|
941
1363
|
const reqHeaders = sanitizeHeaders(headersToObject(cfg.headers), opts);
|
|
942
|
-
const reqBody =
|
|
1364
|
+
const reqBody = captureBodyResult(cfg.data, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
943
1365
|
const respHeaders = sanitizeHeaders(headersToObject(response?.headers), opts);
|
|
944
|
-
const respBody =
|
|
1366
|
+
const respBody = captureBodyResult(response?.data, opts.captureResponseBody, opts.maxBodyBytes, opts, respHeaders?.["content-type"]);
|
|
1367
|
+
const failed = !!error || statusCode >= 400;
|
|
1368
|
+
meta.ctx?.span.setTag("requestId", meta.ctx.requestId).setTag("http.status_code", String(statusCode)).finish(failed ? "error" : "ok");
|
|
1369
|
+
if (meta.ctx) recordTimeline(failed ? "exception" : "response", failed ? "request_failed" : "response_received", meta.ctx, { statusCode, error });
|
|
945
1370
|
try {
|
|
946
1371
|
module2.capture({
|
|
947
1372
|
type: "http_request",
|
|
1373
|
+
traceId: meta.ctx?.traceId ?? generateHttpId(),
|
|
1374
|
+
requestId: meta.ctx?.requestId ?? generateHttpId(),
|
|
1375
|
+
spanId: meta.ctx?.spanId,
|
|
1376
|
+
parentSpanId: meta.ctx?.parentSpanId,
|
|
948
1377
|
method: meta.method,
|
|
949
1378
|
url: sanitizedUrl,
|
|
950
1379
|
statusCode,
|
|
951
1380
|
durationMs: Date.now() - meta.start,
|
|
952
|
-
requestBody: reqBody,
|
|
1381
|
+
requestBody: reqBody.body,
|
|
953
1382
|
requestHeaders: reqHeaders,
|
|
954
|
-
responseBody: respBody,
|
|
1383
|
+
responseBody: respBody.body,
|
|
955
1384
|
responseHeaders: respHeaders,
|
|
956
|
-
|
|
1385
|
+
requestBodyStatus: reqBody.status,
|
|
1386
|
+
responseBodyStatus: respBody.status,
|
|
1387
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1388
|
+
responseBodyRedactedFields: respBody.redactedFields,
|
|
1389
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1390
|
+
responseBodyTruncated: respBody.truncated,
|
|
1391
|
+
capturePolicy: `${reqBody.capturePolicy};${respBody.capturePolicy}`,
|
|
1392
|
+
error,
|
|
1393
|
+
linkConfidence: "exact"
|
|
957
1394
|
});
|
|
958
1395
|
} catch {
|
|
959
1396
|
}
|
|
@@ -979,10 +1416,11 @@ function tryAutoInstrumentAxios(module2, opts) {
|
|
|
979
1416
|
} catch {
|
|
980
1417
|
}
|
|
981
1418
|
}
|
|
982
|
-
function installHttpInstrumentation(module2, options, ownIngestHost) {
|
|
1419
|
+
function installHttpInstrumentation(module2, options, ownIngestHost, runtime) {
|
|
983
1420
|
const bound = bind(options, ownIngestHost);
|
|
984
1421
|
_currentModule = module2;
|
|
985
1422
|
_currentOpts = bound;
|
|
1423
|
+
_currentRuntime = runtime;
|
|
986
1424
|
try {
|
|
987
1425
|
patchFetch();
|
|
988
1426
|
} catch {
|
|
@@ -999,11 +1437,16 @@ function installHttpInstrumentation(module2, options, ownIngestHost) {
|
|
|
999
1437
|
instrumentAxios: (axios) => instrumentAxiosInstance(axios, module2, bound)
|
|
1000
1438
|
};
|
|
1001
1439
|
}
|
|
1440
|
+
function unbindHttpInstrumentation() {
|
|
1441
|
+
_currentModule = null;
|
|
1442
|
+
_currentOpts = null;
|
|
1443
|
+
_currentRuntime = null;
|
|
1444
|
+
}
|
|
1002
1445
|
|
|
1003
1446
|
// src/client.ts
|
|
1004
1447
|
var INGEST_HOST = "https://api.allstak.sa";
|
|
1005
1448
|
var SDK_NAME = "allstak-react-native";
|
|
1006
|
-
var SDK_VERSION = "0.3.
|
|
1449
|
+
var SDK_VERSION = "0.3.1";
|
|
1007
1450
|
var ERRORS_PATH = "/ingest/v1/errors";
|
|
1008
1451
|
var LOGS_PATH = "/ingest/v1/logs";
|
|
1009
1452
|
var VALID_BREADCRUMB_TYPES = /* @__PURE__ */ new Set(["http", "log", "ui", "navigation", "query", "default"]);
|
|
@@ -1019,6 +1462,17 @@ function generateId() {
|
|
|
1019
1462
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
1020
1463
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
1021
1464
|
}
|
|
1465
|
+
function stringContextValue(context, key) {
|
|
1466
|
+
const value = context[key];
|
|
1467
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1468
|
+
}
|
|
1469
|
+
function firstRecentRequestId(recentFailed) {
|
|
1470
|
+
for (let i = recentFailed.length - 1; i >= 0; i--) {
|
|
1471
|
+
const requestId = recentFailed[i]?.requestId;
|
|
1472
|
+
if (requestId && requestId.trim().length > 0) return requestId;
|
|
1473
|
+
}
|
|
1474
|
+
return void 0;
|
|
1475
|
+
}
|
|
1022
1476
|
var AllStakClient = class {
|
|
1023
1477
|
constructor(config) {
|
|
1024
1478
|
this.breadcrumbs = [];
|
|
@@ -1026,9 +1480,6 @@ var AllStakClient = class {
|
|
|
1026
1480
|
this.replay = null;
|
|
1027
1481
|
this.httpRequests = null;
|
|
1028
1482
|
this._instrumentAxios = null;
|
|
1029
|
-
if (!config.apiKey) {
|
|
1030
|
-
throw new Error("AllStak: config.apiKey is required");
|
|
1031
|
-
}
|
|
1032
1483
|
this.config = { ...config };
|
|
1033
1484
|
if (!this.config.environment) this.config.environment = "production";
|
|
1034
1485
|
if (!this.config.sdkName) this.config.sdkName = SDK_NAME;
|
|
@@ -1037,7 +1488,7 @@ var AllStakClient = class {
|
|
|
1037
1488
|
this.sessionId = generateId();
|
|
1038
1489
|
this.maxBreadcrumbs = config.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS;
|
|
1039
1490
|
const baseUrl = (config.host ?? INGEST_HOST).replace(/\/$/, "");
|
|
1040
|
-
this.transport = new HttpTransport(baseUrl, config.apiKey);
|
|
1491
|
+
this.transport = new HttpTransport(baseUrl, config.apiKey ?? "", Boolean(config.apiKey));
|
|
1041
1492
|
this.tracing = new TracingModule(this.transport, {
|
|
1042
1493
|
service: config.service ?? config.release ?? "",
|
|
1043
1494
|
environment: this.config.environment ?? "production",
|
|
@@ -1064,7 +1515,15 @@ var AllStakClient = class {
|
|
|
1064
1515
|
const { instrumentAxios } = installHttpInstrumentation(
|
|
1065
1516
|
this.httpRequests,
|
|
1066
1517
|
config.httpTracking ?? {},
|
|
1067
|
-
baseUrl
|
|
1518
|
+
baseUrl,
|
|
1519
|
+
{
|
|
1520
|
+
tracing: this.tracing,
|
|
1521
|
+
replay: this.replay,
|
|
1522
|
+
release: this.config.release,
|
|
1523
|
+
dist: this.config.dist,
|
|
1524
|
+
platform: this.config.platform,
|
|
1525
|
+
environment: this.config.environment
|
|
1526
|
+
}
|
|
1068
1527
|
);
|
|
1069
1528
|
this._instrumentAxios = instrumentAxios;
|
|
1070
1529
|
} catch {
|
|
@@ -1088,33 +1547,67 @@ var AllStakClient = class {
|
|
|
1088
1547
|
if (!this.passesSampleRate()) return;
|
|
1089
1548
|
const frames = parseStack(error.stack).map((f) => ({
|
|
1090
1549
|
...f,
|
|
1091
|
-
platform: this.config.platform
|
|
1550
|
+
platform: this.config.platform,
|
|
1551
|
+
debugId: resolveDebugId(f.filename)
|
|
1092
1552
|
}));
|
|
1553
|
+
const debugIdSet = /* @__PURE__ */ new Set();
|
|
1554
|
+
for (const f of frames) if (f.debugId) debugIdSet.add(f.debugId);
|
|
1555
|
+
const debugMeta = debugIdSet.size > 0 ? { images: Array.from(debugIdSet).map((id2) => ({ type: "sourcemap", debugId: id2 })) } : void 0;
|
|
1093
1556
|
const stackTrace = frames.length > 0 ? frames.map(frameToString) : void 0;
|
|
1094
1557
|
const currentBreadcrumbs = this.breadcrumbs.length > 0 ? [...this.breadcrumbs] : void 0;
|
|
1095
1558
|
this.breadcrumbs = [];
|
|
1096
1559
|
const exceptionClass = (error.name && error.name !== "Error" ? error.name : void 0) || error.constructor?.name || "Error";
|
|
1097
1560
|
const eff = this.effective();
|
|
1098
1561
|
const traceContext = {};
|
|
1099
|
-
const
|
|
1562
|
+
const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
|
|
1563
|
+
const linkedRequest = recentFailed.length > 0 ? recentFailed[recentFailed.length - 1] : void 0;
|
|
1564
|
+
if (linkedRequest?.traceId) this.tracing.setTraceId(linkedRequest.traceId);
|
|
1565
|
+
const exceptionSpan = linkedRequest ? this.tracing.startSpan("mobile.exception", {
|
|
1566
|
+
description: error.message,
|
|
1567
|
+
tags: {
|
|
1568
|
+
requestId: linkedRequest.requestId,
|
|
1569
|
+
exceptionClass
|
|
1570
|
+
}
|
|
1571
|
+
}) : null;
|
|
1572
|
+
exceptionSpan?.finish("error");
|
|
1573
|
+
const traceId = linkedRequest?.traceId ?? this.tracing.getTraceId();
|
|
1100
1574
|
if (traceId) traceContext.traceId = traceId;
|
|
1101
|
-
const spanId = this.tracing.getCurrentSpanId();
|
|
1575
|
+
const spanId = exceptionSpan?.spanId || this.tracing.getCurrentSpanId();
|
|
1102
1576
|
if (spanId) traceContext.spanId = spanId;
|
|
1103
|
-
const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
|
|
1104
1577
|
if (recentFailed.length > 0) {
|
|
1105
1578
|
traceContext["http.recentFailed"] = recentFailed.map((r) => ({
|
|
1106
1579
|
method: r.method,
|
|
1107
1580
|
url: r.url,
|
|
1108
1581
|
statusCode: r.statusCode,
|
|
1109
1582
|
durationMs: r.durationMs,
|
|
1110
|
-
error: r.error
|
|
1583
|
+
error: r.error,
|
|
1584
|
+
requestId: r.requestId,
|
|
1585
|
+
traceId: r.traceId,
|
|
1586
|
+
confidence: r.requestId === linkedRequest?.requestId ? "inferred" : "weak"
|
|
1111
1587
|
}));
|
|
1588
|
+
traceContext["http.linkConfidence"] = "inferred";
|
|
1589
|
+
}
|
|
1590
|
+
try {
|
|
1591
|
+
if (!linkedRequest) throw new Error("no linked request");
|
|
1592
|
+
this.replay?.recordTimelineMarker?.("exception", "exception_captured", {
|
|
1593
|
+
exceptionClass,
|
|
1594
|
+
message: error.message,
|
|
1595
|
+
requestLinkConfidence: linkedRequest ? "inferred" : "none"
|
|
1596
|
+
}, {
|
|
1597
|
+
traceId,
|
|
1598
|
+
requestId: linkedRequest?.requestId,
|
|
1599
|
+
spanId: spanId ?? void 0,
|
|
1600
|
+
release: this.config.release,
|
|
1601
|
+
dist: this.config.dist
|
|
1602
|
+
});
|
|
1603
|
+
} catch {
|
|
1112
1604
|
}
|
|
1113
1605
|
const payload = {
|
|
1114
1606
|
exceptionClass,
|
|
1115
1607
|
message: error.message,
|
|
1116
1608
|
stackTrace,
|
|
1117
1609
|
frames: frames.length > 0 ? frames : void 0,
|
|
1610
|
+
debugMeta,
|
|
1118
1611
|
platform: this.config.platform,
|
|
1119
1612
|
sdkName: this.config.sdkName,
|
|
1120
1613
|
sdkVersion: this.config.sdkVersion,
|
|
@@ -1123,12 +1616,29 @@ var AllStakClient = class {
|
|
|
1123
1616
|
environment: this.config.environment,
|
|
1124
1617
|
release: this.config.release,
|
|
1125
1618
|
sessionId: this.sessionId,
|
|
1619
|
+
traceId: stringContextValue(traceContext, "traceId"),
|
|
1620
|
+
spanId: stringContextValue(traceContext, "spanId"),
|
|
1621
|
+
requestId: linkedRequest?.requestId ?? firstRecentRequestId(recentFailed),
|
|
1622
|
+
service: this.config.service,
|
|
1126
1623
|
user: eff.user,
|
|
1127
1624
|
metadata: { ...this.buildMetadata(context), ...traceContext },
|
|
1128
1625
|
breadcrumbs: currentBreadcrumbs,
|
|
1129
1626
|
fingerprint: eff.fingerprint
|
|
1130
1627
|
};
|
|
1131
|
-
this.
|
|
1628
|
+
if (this.shouldCaptureScreenshot()) {
|
|
1629
|
+
void this.withScreenshotMetadata(error, payload).then((enriched) => this.sendThroughBeforeSend(enriched)).catch(() => this.sendThroughBeforeSend({
|
|
1630
|
+
...payload,
|
|
1631
|
+
metadata: { ...payload.metadata ?? {}, "screenshot.status": "failed" }
|
|
1632
|
+
}));
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
this.sendThroughBeforeSend({
|
|
1636
|
+
...payload,
|
|
1637
|
+
metadata: {
|
|
1638
|
+
...payload.metadata ?? {},
|
|
1639
|
+
"screenshot.status": this.config.screenshot?.enabled ? "unsupported" : "disabled"
|
|
1640
|
+
}
|
|
1641
|
+
});
|
|
1132
1642
|
}
|
|
1133
1643
|
/** Start a new span. Auto-parented to any currently-active span. */
|
|
1134
1644
|
startSpan(operation, options) {
|
|
@@ -1169,6 +1679,9 @@ var AllStakClient = class {
|
|
|
1169
1679
|
environment: this.config.environment,
|
|
1170
1680
|
release: this.config.release,
|
|
1171
1681
|
sessionId: this.sessionId,
|
|
1682
|
+
traceId: this.tracing.getTraceId(),
|
|
1683
|
+
spanId: this.tracing.getCurrentSpanId() ?? void 0,
|
|
1684
|
+
service: this.config.service,
|
|
1172
1685
|
user: eff.user,
|
|
1173
1686
|
metadata: this.buildMetadata(),
|
|
1174
1687
|
fingerprint: eff.fingerprint
|
|
@@ -1252,6 +1765,9 @@ var AllStakClient = class {
|
|
|
1252
1765
|
getConfig() {
|
|
1253
1766
|
return this.config;
|
|
1254
1767
|
}
|
|
1768
|
+
getTransportStats() {
|
|
1769
|
+
return this.transport.getStats();
|
|
1770
|
+
}
|
|
1255
1771
|
destroy() {
|
|
1256
1772
|
this.tracing.destroy();
|
|
1257
1773
|
if (this.replay) {
|
|
@@ -1262,6 +1778,7 @@ var AllStakClient = class {
|
|
|
1262
1778
|
this.httpRequests.destroy();
|
|
1263
1779
|
this.httpRequests = null;
|
|
1264
1780
|
}
|
|
1781
|
+
unbindHttpInstrumentation();
|
|
1265
1782
|
this._instrumentAxios = null;
|
|
1266
1783
|
this.breadcrumbs = [];
|
|
1267
1784
|
}
|
|
@@ -1280,6 +1797,58 @@ var AllStakClient = class {
|
|
|
1280
1797
|
metadata: this.buildMetadata()
|
|
1281
1798
|
});
|
|
1282
1799
|
}
|
|
1800
|
+
shouldCaptureScreenshot() {
|
|
1801
|
+
const screenshot = this.config.screenshot;
|
|
1802
|
+
if (!screenshot?.enabled || screenshot.captureOnError === false || !screenshot.provider) return false;
|
|
1803
|
+
const sampleRate = screenshot.sampleRate ?? 1;
|
|
1804
|
+
return !(sampleRate <= 0 || sampleRate < 1 && Math.random() >= sampleRate);
|
|
1805
|
+
}
|
|
1806
|
+
async withScreenshotMetadata(error, payload) {
|
|
1807
|
+
const screenshot = this.config.screenshot;
|
|
1808
|
+
if (!screenshot?.provider) {
|
|
1809
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "unsupported" } };
|
|
1810
|
+
}
|
|
1811
|
+
const timeoutMs = Math.max(100, Math.min(screenshot.timeoutMs ?? 1500, 5e3));
|
|
1812
|
+
const maxBytes = Math.max(1024, screenshot.maxBytes ?? 2e5);
|
|
1813
|
+
try {
|
|
1814
|
+
const artifact = await Promise.race([
|
|
1815
|
+
Promise.resolve(screenshot.provider({
|
|
1816
|
+
type: "error",
|
|
1817
|
+
error,
|
|
1818
|
+
traceId: payload.traceId,
|
|
1819
|
+
requestId: payload.requestId
|
|
1820
|
+
})),
|
|
1821
|
+
new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs))
|
|
1822
|
+
]);
|
|
1823
|
+
if (!artifact) {
|
|
1824
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "timeout_or_empty" } };
|
|
1825
|
+
}
|
|
1826
|
+
const size = artifact.sizeBytes ?? byteSize(artifact.data);
|
|
1827
|
+
if (size > maxBytes) {
|
|
1828
|
+
this.transport.noteDropped();
|
|
1829
|
+
return {
|
|
1830
|
+
...payload,
|
|
1831
|
+
metadata: { ...payload.metadata ?? {}, "screenshot.status": "dropped_too_large", "screenshot.sizeBytes": size }
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
return {
|
|
1835
|
+
...payload,
|
|
1836
|
+
metadata: {
|
|
1837
|
+
...payload.metadata ?? {},
|
|
1838
|
+
"screenshot.status": "captured",
|
|
1839
|
+
"screenshot.contentType": artifact.contentType,
|
|
1840
|
+
"screenshot.width": artifact.width,
|
|
1841
|
+
"screenshot.height": artifact.height,
|
|
1842
|
+
"screenshot.sizeBytes": size,
|
|
1843
|
+
"screenshot.redacted": artifact.redacted ?? false,
|
|
1844
|
+
"screenshot.redactionStrategy": artifact.redactionStrategy,
|
|
1845
|
+
...artifact.data ? { "screenshot.data": artifact.data } : {}
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
} catch {
|
|
1849
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "failed" } };
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1283
1852
|
passesSampleRate() {
|
|
1284
1853
|
const r = this.config.sampleRate;
|
|
1285
1854
|
if (typeof r !== "number" || r >= 1) return true;
|
|
@@ -1378,10 +1947,22 @@ var AllStakClient = class {
|
|
|
1378
1947
|
}
|
|
1379
1948
|
};
|
|
1380
1949
|
var instance = null;
|
|
1381
|
-
function
|
|
1382
|
-
if (!instance) throw new Error("AllStak.init() must be called before using the SDK");
|
|
1950
|
+
function maybeInit() {
|
|
1383
1951
|
return instance;
|
|
1384
1952
|
}
|
|
1953
|
+
function noopSpan(operation = "") {
|
|
1954
|
+
return new Span("", "", "", operation, "", "", "", {}, () => void 0);
|
|
1955
|
+
}
|
|
1956
|
+
function emptyStats() {
|
|
1957
|
+
return {
|
|
1958
|
+
queued: 0,
|
|
1959
|
+
sent: 0,
|
|
1960
|
+
failed: 0,
|
|
1961
|
+
dropped: 0,
|
|
1962
|
+
consecutiveFailures: 0,
|
|
1963
|
+
circuitOpenUntil: 0
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1385
1966
|
function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
1386
1967
|
try {
|
|
1387
1968
|
instance?.addBreadcrumb(type, message, level, data);
|
|
@@ -1390,51 +1971,99 @@ function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
|
1390
1971
|
}
|
|
1391
1972
|
var AllStak = {
|
|
1392
1973
|
init(config) {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1974
|
+
try {
|
|
1975
|
+
if (instance) instance.destroy();
|
|
1976
|
+
instance = new AllStakClient(config);
|
|
1977
|
+
return instance;
|
|
1978
|
+
} catch {
|
|
1979
|
+
instance = new AllStakClient({ ...config, apiKey: "" });
|
|
1980
|
+
return instance;
|
|
1981
|
+
}
|
|
1396
1982
|
},
|
|
1397
1983
|
captureException(error, context) {
|
|
1398
|
-
|
|
1984
|
+
try {
|
|
1985
|
+
maybeInit()?.captureException(error, context);
|
|
1986
|
+
} catch {
|
|
1987
|
+
}
|
|
1399
1988
|
},
|
|
1400
1989
|
captureMessage(message, level = "info", options) {
|
|
1401
|
-
|
|
1990
|
+
try {
|
|
1991
|
+
maybeInit()?.captureMessage(message, level, options);
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1402
1994
|
},
|
|
1403
1995
|
addBreadcrumb(type, message, level, data) {
|
|
1404
|
-
|
|
1996
|
+
try {
|
|
1997
|
+
maybeInit()?.addBreadcrumb(type, message, level, data);
|
|
1998
|
+
} catch {
|
|
1999
|
+
}
|
|
1405
2000
|
},
|
|
1406
2001
|
clearBreadcrumbs() {
|
|
1407
|
-
|
|
2002
|
+
try {
|
|
2003
|
+
maybeInit()?.clearBreadcrumbs();
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
1408
2006
|
},
|
|
1409
2007
|
setUser(user) {
|
|
1410
|
-
|
|
2008
|
+
try {
|
|
2009
|
+
maybeInit()?.setUser(user);
|
|
2010
|
+
} catch {
|
|
2011
|
+
}
|
|
1411
2012
|
},
|
|
1412
2013
|
setTag(key, value) {
|
|
1413
|
-
|
|
2014
|
+
try {
|
|
2015
|
+
maybeInit()?.setTag(key, value);
|
|
2016
|
+
} catch {
|
|
2017
|
+
}
|
|
1414
2018
|
},
|
|
1415
2019
|
setTags(tags) {
|
|
1416
|
-
|
|
2020
|
+
try {
|
|
2021
|
+
maybeInit()?.setTags(tags);
|
|
2022
|
+
} catch {
|
|
2023
|
+
}
|
|
1417
2024
|
},
|
|
1418
2025
|
setExtra(key, value) {
|
|
1419
|
-
|
|
2026
|
+
try {
|
|
2027
|
+
maybeInit()?.setExtra(key, value);
|
|
2028
|
+
} catch {
|
|
2029
|
+
}
|
|
1420
2030
|
},
|
|
1421
2031
|
setExtras(extras) {
|
|
1422
|
-
|
|
2032
|
+
try {
|
|
2033
|
+
maybeInit()?.setExtras(extras);
|
|
2034
|
+
} catch {
|
|
2035
|
+
}
|
|
1423
2036
|
},
|
|
1424
2037
|
setContext(name, ctx) {
|
|
1425
|
-
|
|
2038
|
+
try {
|
|
2039
|
+
maybeInit()?.setContext(name, ctx);
|
|
2040
|
+
} catch {
|
|
2041
|
+
}
|
|
1426
2042
|
},
|
|
1427
2043
|
setLevel(level) {
|
|
1428
|
-
|
|
2044
|
+
try {
|
|
2045
|
+
maybeInit()?.setLevel(level);
|
|
2046
|
+
} catch {
|
|
2047
|
+
}
|
|
1429
2048
|
},
|
|
1430
2049
|
setFingerprint(fingerprint) {
|
|
1431
|
-
|
|
2050
|
+
try {
|
|
2051
|
+
maybeInit()?.setFingerprint(fingerprint);
|
|
2052
|
+
} catch {
|
|
2053
|
+
}
|
|
1432
2054
|
},
|
|
1433
2055
|
flush(timeoutMs) {
|
|
1434
|
-
|
|
2056
|
+
try {
|
|
2057
|
+
return maybeInit()?.flush(timeoutMs) ?? Promise.resolve(true);
|
|
2058
|
+
} catch {
|
|
2059
|
+
return Promise.resolve(false);
|
|
2060
|
+
}
|
|
1435
2061
|
},
|
|
1436
2062
|
setIdentity(identity) {
|
|
1437
|
-
|
|
2063
|
+
try {
|
|
2064
|
+
maybeInit()?.setIdentity(identity);
|
|
2065
|
+
} catch {
|
|
2066
|
+
}
|
|
1438
2067
|
},
|
|
1439
2068
|
/**
|
|
1440
2069
|
* Run `callback` with a fresh scoped context. Any user/tag/extra/context/
|
|
@@ -1443,37 +2072,79 @@ var AllStak = {
|
|
|
1443
2072
|
* for async callbacks and thrown errors.
|
|
1444
2073
|
*/
|
|
1445
2074
|
withScope(callback) {
|
|
1446
|
-
|
|
2075
|
+
try {
|
|
2076
|
+
const client = maybeInit();
|
|
2077
|
+
return client ? client.withScope(callback) : callback(new Scope());
|
|
2078
|
+
} catch {
|
|
2079
|
+
return callback(new Scope());
|
|
2080
|
+
}
|
|
1447
2081
|
},
|
|
1448
2082
|
startSpan(operation, options) {
|
|
1449
|
-
|
|
2083
|
+
try {
|
|
2084
|
+
return maybeInit()?.startSpan(operation, options) ?? noopSpan(operation);
|
|
2085
|
+
} catch {
|
|
2086
|
+
return noopSpan(operation);
|
|
2087
|
+
}
|
|
1450
2088
|
},
|
|
1451
2089
|
getTraceId() {
|
|
1452
|
-
|
|
2090
|
+
try {
|
|
2091
|
+
return maybeInit()?.getTraceId() ?? "";
|
|
2092
|
+
} catch {
|
|
2093
|
+
return "";
|
|
2094
|
+
}
|
|
1453
2095
|
},
|
|
1454
2096
|
setTraceId(traceId) {
|
|
1455
|
-
|
|
2097
|
+
try {
|
|
2098
|
+
maybeInit()?.setTraceId(traceId);
|
|
2099
|
+
} catch {
|
|
2100
|
+
}
|
|
1456
2101
|
},
|
|
1457
2102
|
getCurrentSpanId() {
|
|
1458
|
-
|
|
2103
|
+
try {
|
|
2104
|
+
return maybeInit()?.getCurrentSpanId() ?? null;
|
|
2105
|
+
} catch {
|
|
2106
|
+
return null;
|
|
2107
|
+
}
|
|
1459
2108
|
},
|
|
1460
2109
|
resetTrace() {
|
|
1461
|
-
|
|
2110
|
+
try {
|
|
2111
|
+
maybeInit()?.resetTrace();
|
|
2112
|
+
} catch {
|
|
2113
|
+
}
|
|
1462
2114
|
},
|
|
1463
2115
|
/** Access the privacy-first replay surrogate (or null if disabled / sampled out). */
|
|
1464
2116
|
getReplay() {
|
|
1465
|
-
|
|
2117
|
+
try {
|
|
2118
|
+
return maybeInit()?.getReplay() ?? null;
|
|
2119
|
+
} catch {
|
|
2120
|
+
return null;
|
|
2121
|
+
}
|
|
1466
2122
|
},
|
|
1467
2123
|
/** Manually instrument an axios instance. No-op when HTTP tracking is off. */
|
|
1468
2124
|
instrumentAxios(axios) {
|
|
1469
|
-
|
|
2125
|
+
try {
|
|
2126
|
+
return maybeInit()?.instrumentAxios(axios) ?? axios;
|
|
2127
|
+
} catch {
|
|
2128
|
+
return axios;
|
|
2129
|
+
}
|
|
1470
2130
|
},
|
|
1471
2131
|
getSessionId() {
|
|
1472
|
-
|
|
2132
|
+
try {
|
|
2133
|
+
return maybeInit()?.getSessionId() ?? "";
|
|
2134
|
+
} catch {
|
|
2135
|
+
return "";
|
|
2136
|
+
}
|
|
1473
2137
|
},
|
|
1474
2138
|
getConfig() {
|
|
1475
2139
|
return instance?.getConfig() ?? null;
|
|
1476
2140
|
},
|
|
2141
|
+
getTransportStats() {
|
|
2142
|
+
try {
|
|
2143
|
+
return maybeInit()?.getTransportStats() ?? emptyStats();
|
|
2144
|
+
} catch {
|
|
2145
|
+
return emptyStats();
|
|
2146
|
+
}
|
|
2147
|
+
},
|
|
1477
2148
|
destroy() {
|
|
1478
2149
|
instance?.destroy();
|
|
1479
2150
|
instance = null;
|
|
@@ -1483,6 +2154,17 @@ var AllStak = {
|
|
|
1483
2154
|
return instance;
|
|
1484
2155
|
}
|
|
1485
2156
|
};
|
|
2157
|
+
function byteSize(value) {
|
|
2158
|
+
if (!value) return 0;
|
|
2159
|
+
try {
|
|
2160
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(value).length;
|
|
2161
|
+
} catch {
|
|
2162
|
+
}
|
|
2163
|
+
return value.length;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// src/provider.tsx
|
|
2167
|
+
var React = __toESM(require("react"));
|
|
1486
2168
|
|
|
1487
2169
|
// src/auto-breadcrumbs.ts
|
|
1488
2170
|
var FETCH_FLAG2 = "__allstak_fetch_patched__";
|
|
@@ -1530,36 +2212,92 @@ function instrumentFetch(addBreadcrumb, ownBaseUrl) {
|
|
|
1530
2212
|
wrapped[FETCH_FLAG2] = true;
|
|
1531
2213
|
g.fetch = wrapped;
|
|
1532
2214
|
}
|
|
1533
|
-
|
|
2215
|
+
var CONSOLE_DEFAULTS = {
|
|
2216
|
+
log: false,
|
|
2217
|
+
info: false,
|
|
2218
|
+
warn: true,
|
|
2219
|
+
error: true
|
|
2220
|
+
};
|
|
2221
|
+
var CONSOLE_METHOD_TO_LEVEL = {
|
|
2222
|
+
log: "info",
|
|
2223
|
+
info: "info",
|
|
2224
|
+
warn: "warn",
|
|
2225
|
+
error: "error"
|
|
2226
|
+
};
|
|
2227
|
+
var MAX_ARG_BYTES = 5e3;
|
|
2228
|
+
function instrumentConsole(addBreadcrumb, options = {}) {
|
|
1534
2229
|
if (typeof console === "undefined") return;
|
|
1535
2230
|
if (console[CONSOLE_FLAG]) return;
|
|
1536
|
-
const
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
} catch {
|
|
1542
|
-
}
|
|
1543
|
-
return origWarn.apply(console, args);
|
|
2231
|
+
const opts = {
|
|
2232
|
+
log: options.log ?? CONSOLE_DEFAULTS.log,
|
|
2233
|
+
info: options.info ?? CONSOLE_DEFAULTS.info,
|
|
2234
|
+
warn: options.warn ?? CONSOLE_DEFAULTS.warn,
|
|
2235
|
+
error: options.error ?? CONSOLE_DEFAULTS.error
|
|
1544
2236
|
};
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2237
|
+
const wrap = (method) => {
|
|
2238
|
+
const orig = console[method];
|
|
2239
|
+
if (typeof orig !== "function") return;
|
|
2240
|
+
const level = CONSOLE_METHOD_TO_LEVEL[method];
|
|
2241
|
+
console[method] = function(...args) {
|
|
2242
|
+
if (opts[method]) {
|
|
2243
|
+
try {
|
|
2244
|
+
const serialized = args.map(safeStringifyArg);
|
|
2245
|
+
const message = truncate(serialized.join(" "));
|
|
2246
|
+
addBreadcrumb("log", message, level, {
|
|
2247
|
+
category: "console",
|
|
2248
|
+
method,
|
|
2249
|
+
args: serialized
|
|
2250
|
+
});
|
|
2251
|
+
} catch {
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
return orig.apply(console, args);
|
|
2255
|
+
};
|
|
1551
2256
|
};
|
|
2257
|
+
if (opts.log) wrap("log");
|
|
2258
|
+
if (opts.info) wrap("info");
|
|
2259
|
+
if (opts.warn) wrap("warn");
|
|
2260
|
+
if (opts.error) wrap("error");
|
|
1552
2261
|
console[CONSOLE_FLAG] = true;
|
|
1553
2262
|
}
|
|
1554
|
-
function
|
|
1555
|
-
if (
|
|
2263
|
+
function __resetConsoleInstrumentationFlagForTest() {
|
|
2264
|
+
if (typeof console !== "undefined") {
|
|
2265
|
+
delete console[CONSOLE_FLAG];
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
function safeStringifyArg(v) {
|
|
2269
|
+
if (v === null || v === void 0) return String(v);
|
|
1556
2270
|
if (typeof v === "string") return v;
|
|
1557
|
-
if (v
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
return
|
|
2271
|
+
if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
|
|
2272
|
+
if (typeof v === "symbol") return v.toString();
|
|
2273
|
+
if (typeof v === "function") return `[Function${v.name ? ` ${v.name}` : ""}]`;
|
|
2274
|
+
if (v instanceof Error) {
|
|
2275
|
+
return `${v.name || "Error"}: ${v.message}${v.stack ? `
|
|
2276
|
+
${v.stack}` : ""}`;
|
|
2277
|
+
}
|
|
2278
|
+
if (typeof v === "object") {
|
|
2279
|
+
try {
|
|
2280
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2281
|
+
const out = JSON.stringify(v, (_key, val) => {
|
|
2282
|
+
if (typeof val === "object" && val !== null) {
|
|
2283
|
+
if (seen.has(val)) return "[Circular]";
|
|
2284
|
+
seen.add(val);
|
|
2285
|
+
}
|
|
2286
|
+
if (typeof val === "bigint") return val.toString();
|
|
2287
|
+
if (typeof val === "function") return `[Function${val.name ? ` ${val.name}` : ""}]`;
|
|
2288
|
+
if (typeof val === "symbol") return val.toString();
|
|
2289
|
+
return val;
|
|
2290
|
+
});
|
|
2291
|
+
return out ?? Object.prototype.toString.call(v);
|
|
2292
|
+
} catch {
|
|
2293
|
+
return Object.prototype.toString.call(v);
|
|
2294
|
+
}
|
|
1562
2295
|
}
|
|
2296
|
+
return String(v);
|
|
2297
|
+
}
|
|
2298
|
+
function truncate(s) {
|
|
2299
|
+
if (s.length <= MAX_ARG_BYTES) return s;
|
|
2300
|
+
return s.slice(0, MAX_ARG_BYTES) + "\u2026[truncated]";
|
|
1563
2301
|
}
|
|
1564
2302
|
|
|
1565
2303
|
// src/architecture.ts
|
|
@@ -1587,6 +2325,7 @@ function applyArchitectureTags(setTag) {
|
|
|
1587
2325
|
// src/navigation.ts
|
|
1588
2326
|
var NAV_FLAG = /* @__PURE__ */ Symbol.for("allstak.nav.subscribed");
|
|
1589
2327
|
var LINKING_FLAG = "__allstak_linking_patched__";
|
|
2328
|
+
var NAV_AUTO_PATCH_FLAG = /* @__PURE__ */ Symbol.for("allstak.nav.autoPatched");
|
|
1590
2329
|
function instrumentReactNavigation(navigationRef, options = {}) {
|
|
1591
2330
|
if (!navigationRef || typeof navigationRef.addListener !== "function") {
|
|
1592
2331
|
return () => {
|
|
@@ -1654,8 +2393,59 @@ function instrumentNavigationFromLinking() {
|
|
|
1654
2393
|
} catch {
|
|
1655
2394
|
}
|
|
1656
2395
|
}
|
|
2396
|
+
function tryAutoInstrumentNavigation() {
|
|
2397
|
+
const g = globalThis;
|
|
2398
|
+
const isMetro = typeof g.__METRO_GLOBAL_PREFIX__ !== "undefined" || typeof g.__r === "function" || typeof g.HermesInternal !== "undefined";
|
|
2399
|
+
if (isMetro) return false;
|
|
2400
|
+
try {
|
|
2401
|
+
const rnav = require("@react-navigation/native");
|
|
2402
|
+
if (!rnav || !rnav.NavigationContainer) return false;
|
|
2403
|
+
if (rnav[NAV_AUTO_PATCH_FLAG]) return true;
|
|
2404
|
+
const React2 = require("react");
|
|
2405
|
+
if (!React2 || typeof React2.forwardRef !== "function") return false;
|
|
2406
|
+
const OrigContainer = rnav.NavigationContainer;
|
|
2407
|
+
const Wrapped = React2.forwardRef(function AllStakNavigationContainer(props, userRef) {
|
|
2408
|
+
const internalRef = React2.useRef(null);
|
|
2409
|
+
const setRef = React2.useCallback((r) => {
|
|
2410
|
+
internalRef.current = r;
|
|
2411
|
+
if (typeof userRef === "function") userRef(r);
|
|
2412
|
+
else if (userRef) userRef.current = r;
|
|
2413
|
+
}, [userRef]);
|
|
2414
|
+
React2.useEffect(() => {
|
|
2415
|
+
if (internalRef.current) {
|
|
2416
|
+
try {
|
|
2417
|
+
instrumentReactNavigation(internalRef.current);
|
|
2418
|
+
} catch {
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
}, []);
|
|
2422
|
+
return React2.createElement(OrigContainer, { ...props, ref: setRef });
|
|
2423
|
+
});
|
|
2424
|
+
Wrapped.displayName = "AllStakNavigationContainer";
|
|
2425
|
+
try {
|
|
2426
|
+
Object.defineProperty(rnav, "NavigationContainer", {
|
|
2427
|
+
value: Wrapped,
|
|
2428
|
+
configurable: true,
|
|
2429
|
+
writable: true
|
|
2430
|
+
});
|
|
2431
|
+
rnav[NAV_AUTO_PATCH_FLAG] = true;
|
|
2432
|
+
return true;
|
|
2433
|
+
} catch {
|
|
2434
|
+
return false;
|
|
2435
|
+
}
|
|
2436
|
+
} catch {
|
|
2437
|
+
return false;
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
function __resetAutoNavigationFlagForTest() {
|
|
2441
|
+
try {
|
|
2442
|
+
const rnav = require("@react-navigation/native");
|
|
2443
|
+
if (rnav) delete rnav[NAV_AUTO_PATCH_FLAG];
|
|
2444
|
+
} catch {
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
1657
2447
|
|
|
1658
|
-
// src/
|
|
2448
|
+
// src/install.ts
|
|
1659
2449
|
function instrumentXmlHttpRequest() {
|
|
1660
2450
|
const flag = "__allstak_xhr_patched__";
|
|
1661
2451
|
const X = globalThis.XMLHttpRequest;
|
|
@@ -1707,43 +2497,6 @@ function instrumentXmlHttpRequest() {
|
|
|
1707
2497
|
};
|
|
1708
2498
|
X.prototype[flag] = true;
|
|
1709
2499
|
}
|
|
1710
|
-
var __testNativeModule = null;
|
|
1711
|
-
function __setNativeModuleForTest(mod) {
|
|
1712
|
-
__testNativeModule = mod;
|
|
1713
|
-
}
|
|
1714
|
-
async function drainPendingNativeCrashes(release) {
|
|
1715
|
-
try {
|
|
1716
|
-
let native = __testNativeModule;
|
|
1717
|
-
if (!native) {
|
|
1718
|
-
const rn = require("react-native");
|
|
1719
|
-
native = rn?.NativeModules?.AllStakNative;
|
|
1720
|
-
}
|
|
1721
|
-
if (!native) return;
|
|
1722
|
-
if (typeof native.install === "function") {
|
|
1723
|
-
try {
|
|
1724
|
-
await native.install(release ?? "");
|
|
1725
|
-
} catch {
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
if (typeof native.drainPendingCrash === "function") {
|
|
1729
|
-
const json = await native.drainPendingCrash();
|
|
1730
|
-
if (json && json !== "") {
|
|
1731
|
-
try {
|
|
1732
|
-
const payload = JSON.parse(json);
|
|
1733
|
-
const err = new Error(payload?.message ?? "Native crash");
|
|
1734
|
-
err.name = payload?.exceptionClass ?? "NativeCrash";
|
|
1735
|
-
err.stack = Array.isArray(payload?.stackTrace) ? payload.stackTrace.join("\n") : String(payload?.stackTrace ?? "");
|
|
1736
|
-
AllStak.captureException(err, {
|
|
1737
|
-
...payload?.metadata || {},
|
|
1738
|
-
"native.crash": "true"
|
|
1739
|
-
});
|
|
1740
|
-
} catch {
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
} catch {
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
2500
|
function installReactNative(options = {}) {
|
|
1748
2501
|
const autoError = options.autoErrorHandler !== false;
|
|
1749
2502
|
const autoPromise = options.autoPromiseRejections !== false;
|
|
@@ -1768,7 +2521,7 @@ function installReactNative(options = {}) {
|
|
|
1768
2521
|
}
|
|
1769
2522
|
AllStak.setIdentity({
|
|
1770
2523
|
sdkName: "allstak-react-native",
|
|
1771
|
-
sdkVersion:
|
|
2524
|
+
sdkVersion: SDK_VERSION,
|
|
1772
2525
|
platform: "react-native",
|
|
1773
2526
|
dist
|
|
1774
2527
|
});
|
|
@@ -1790,10 +2543,22 @@ function installReactNative(options = {}) {
|
|
|
1790
2543
|
}
|
|
1791
2544
|
if (options.autoConsoleBreadcrumbs !== false) {
|
|
1792
2545
|
try {
|
|
1793
|
-
|
|
2546
|
+
const cfg = AllStak.getConfig();
|
|
2547
|
+
instrumentConsole(__safeAddBreadcrumbForInstrumentation, cfg?.captureConsole);
|
|
1794
2548
|
} catch {
|
|
1795
2549
|
}
|
|
1796
2550
|
}
|
|
2551
|
+
if (options.autoNavigationBreadcrumbs !== false) {
|
|
2552
|
+
let navResult = false;
|
|
2553
|
+
try {
|
|
2554
|
+
navResult = tryAutoInstrumentNavigation();
|
|
2555
|
+
} catch {
|
|
2556
|
+
}
|
|
2557
|
+
if (options.debugLogs) {
|
|
2558
|
+
if (navResult) console.log("[AllStak] Navigation auto-instrumentation enabled");
|
|
2559
|
+
else console.log("[AllStak] Navigation auto-instrumentation not applied; use instrumentReactNavigation(ref) fallback");
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
1797
2562
|
if (autoDevice) {
|
|
1798
2563
|
try {
|
|
1799
2564
|
const rn = require("react-native");
|
|
@@ -1843,17 +2608,30 @@ function installReactNative(options = {}) {
|
|
|
1843
2608
|
}
|
|
1844
2609
|
}
|
|
1845
2610
|
if (autoPromise) {
|
|
2611
|
+
const wrapTrackerReason = (rejection) => rejection instanceof Error ? rejection : new Error(`Unhandled promise rejection: ${String(rejection)}`);
|
|
2612
|
+
const ship = (err) => {
|
|
2613
|
+
try {
|
|
2614
|
+
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
2615
|
+
} catch {
|
|
2616
|
+
}
|
|
2617
|
+
};
|
|
2618
|
+
try {
|
|
2619
|
+
const hermesInternal = globalThis.HermesInternal;
|
|
2620
|
+
if (hermesInternal && typeof hermesInternal.enablePromiseRejectionTracker === "function") {
|
|
2621
|
+
hermesInternal.enablePromiseRejectionTracker({
|
|
2622
|
+
allRejections: true,
|
|
2623
|
+
onUnhandled: (_id, rejection) => ship(wrapTrackerReason(rejection)),
|
|
2624
|
+
onHandled: () => {
|
|
2625
|
+
}
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
} catch {
|
|
2629
|
+
}
|
|
1846
2630
|
try {
|
|
1847
2631
|
const tracking = require("promise/setimmediate/rejection-tracking");
|
|
1848
2632
|
tracking.enable({
|
|
1849
2633
|
allRejections: true,
|
|
1850
|
-
onUnhandled: (_id, rejection) =>
|
|
1851
|
-
const err = rejection instanceof Error ? rejection : new Error(`Unhandled promise rejection: ${String(rejection)}`);
|
|
1852
|
-
try {
|
|
1853
|
-
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
1854
|
-
} catch {
|
|
1855
|
-
}
|
|
1856
|
-
},
|
|
2634
|
+
onUnhandled: (_id, rejection) => ship(wrapTrackerReason(rejection)),
|
|
1857
2635
|
onHandled: () => {
|
|
1858
2636
|
}
|
|
1859
2637
|
});
|
|
@@ -1863,13 +2641,206 @@ function installReactNative(options = {}) {
|
|
|
1863
2641
|
g.addEventListener("unhandledrejection", (ev) => {
|
|
1864
2642
|
const reason = ev?.reason;
|
|
1865
2643
|
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
1866
|
-
|
|
1867
|
-
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
1868
|
-
} catch {
|
|
1869
|
-
}
|
|
2644
|
+
ship(err);
|
|
1870
2645
|
});
|
|
1871
2646
|
}
|
|
1872
2647
|
}
|
|
1873
2648
|
}
|
|
1874
2649
|
}
|
|
2650
|
+
|
|
2651
|
+
// src/provider.tsx
|
|
2652
|
+
var AllStakContext = React.createContext(null);
|
|
2653
|
+
var __providerOwnedInstance = null;
|
|
2654
|
+
var AllStakErrorBoundary = class extends React.Component {
|
|
2655
|
+
constructor() {
|
|
2656
|
+
super(...arguments);
|
|
2657
|
+
this.state = { error: null };
|
|
2658
|
+
this.resetError = () => this.setState({ error: null });
|
|
2659
|
+
}
|
|
2660
|
+
static getDerivedStateFromError(error) {
|
|
2661
|
+
return { error };
|
|
2662
|
+
}
|
|
2663
|
+
componentDidCatch(error, info) {
|
|
2664
|
+
try {
|
|
2665
|
+
AllStak.addBreadcrumb("ui", "React error boundary caught error", "error", {
|
|
2666
|
+
componentStack: info.componentStack ?? ""
|
|
2667
|
+
});
|
|
2668
|
+
AllStak.captureException(error, {
|
|
2669
|
+
componentStack: info.componentStack ?? "",
|
|
2670
|
+
source: "AllStakProvider.ErrorBoundary"
|
|
2671
|
+
});
|
|
2672
|
+
if (this.props.debug) {
|
|
2673
|
+
console.log(`[AllStak] Captured render error: ${error.message}`);
|
|
2674
|
+
}
|
|
2675
|
+
} catch {
|
|
2676
|
+
}
|
|
2677
|
+
try {
|
|
2678
|
+
this.props.onError?.(error, info.componentStack ?? void 0);
|
|
2679
|
+
} catch {
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
render() {
|
|
2683
|
+
if (this.state.error) {
|
|
2684
|
+
const { fallback } = this.props;
|
|
2685
|
+
if (typeof fallback === "function") {
|
|
2686
|
+
return fallback({ error: this.state.error, resetError: this.resetError });
|
|
2687
|
+
}
|
|
2688
|
+
if (fallback !== void 0) return fallback;
|
|
2689
|
+
return null;
|
|
2690
|
+
}
|
|
2691
|
+
return this.props.children;
|
|
2692
|
+
}
|
|
2693
|
+
};
|
|
2694
|
+
function AllStakProvider({
|
|
2695
|
+
children,
|
|
2696
|
+
apiKey,
|
|
2697
|
+
environment,
|
|
2698
|
+
release,
|
|
2699
|
+
host,
|
|
2700
|
+
user,
|
|
2701
|
+
tags,
|
|
2702
|
+
debug,
|
|
2703
|
+
enableHttpTracking,
|
|
2704
|
+
httpTracking,
|
|
2705
|
+
captureConsole,
|
|
2706
|
+
sampleRate,
|
|
2707
|
+
beforeSend,
|
|
2708
|
+
replay,
|
|
2709
|
+
tracesSampleRate,
|
|
2710
|
+
service,
|
|
2711
|
+
dist,
|
|
2712
|
+
destroyOnUnmount = false,
|
|
2713
|
+
fallback,
|
|
2714
|
+
onError,
|
|
2715
|
+
autoErrorHandler,
|
|
2716
|
+
autoPromiseRejections,
|
|
2717
|
+
autoDeviceTags,
|
|
2718
|
+
autoAppStateBreadcrumbs,
|
|
2719
|
+
autoNetworkCapture,
|
|
2720
|
+
autoFetchBreadcrumbs,
|
|
2721
|
+
autoConsoleBreadcrumbs,
|
|
2722
|
+
autoNavigationBreadcrumbs
|
|
2723
|
+
}) {
|
|
2724
|
+
const clientRef = React.useRef(null);
|
|
2725
|
+
if (!clientRef.current) {
|
|
2726
|
+
const existing = AllStak._getInstance();
|
|
2727
|
+
if (existing && __providerOwnedInstance === existing) {
|
|
2728
|
+
clientRef.current = existing;
|
|
2729
|
+
if (debug) {
|
|
2730
|
+
console.log(`[AllStak] Reusing session ${AllStak.getSessionId()}`);
|
|
2731
|
+
}
|
|
2732
|
+
} else {
|
|
2733
|
+
const config = {
|
|
2734
|
+
apiKey,
|
|
2735
|
+
environment,
|
|
2736
|
+
release,
|
|
2737
|
+
host,
|
|
2738
|
+
user,
|
|
2739
|
+
tags,
|
|
2740
|
+
enableHttpTracking,
|
|
2741
|
+
httpTracking,
|
|
2742
|
+
captureConsole,
|
|
2743
|
+
sampleRate,
|
|
2744
|
+
beforeSend,
|
|
2745
|
+
replay,
|
|
2746
|
+
tracesSampleRate,
|
|
2747
|
+
service,
|
|
2748
|
+
dist
|
|
2749
|
+
};
|
|
2750
|
+
clientRef.current = AllStak.init(config);
|
|
2751
|
+
__providerOwnedInstance = clientRef.current;
|
|
2752
|
+
installReactNative({
|
|
2753
|
+
autoErrorHandler,
|
|
2754
|
+
autoPromiseRejections,
|
|
2755
|
+
autoDeviceTags,
|
|
2756
|
+
autoAppStateBreadcrumbs,
|
|
2757
|
+
autoNetworkCapture,
|
|
2758
|
+
autoFetchBreadcrumbs,
|
|
2759
|
+
autoConsoleBreadcrumbs,
|
|
2760
|
+
autoNavigationBreadcrumbs,
|
|
2761
|
+
debugLogs: debug
|
|
2762
|
+
});
|
|
2763
|
+
if (debug) {
|
|
2764
|
+
console.log(`[AllStak] Initialized \u2014 session ${AllStak.getSessionId()}`);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
React.useEffect(() => {
|
|
2769
|
+
return () => {
|
|
2770
|
+
if (destroyOnUnmount) {
|
|
2771
|
+
AllStak.destroy();
|
|
2772
|
+
__providerOwnedInstance = null;
|
|
2773
|
+
clientRef.current = null;
|
|
2774
|
+
if (debug) console.log("[AllStak] Destroyed on unmount");
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
}, [destroyOnUnmount, debug]);
|
|
2778
|
+
return /* @__PURE__ */ React.createElement(AllStakContext.Provider, { value: clientRef.current }, /* @__PURE__ */ React.createElement(AllStakErrorBoundary, { fallback, onError, debug }, children));
|
|
2779
|
+
}
|
|
2780
|
+
function useAllStak() {
|
|
2781
|
+
return React.useMemo(
|
|
2782
|
+
() => ({
|
|
2783
|
+
captureException: (error, ctx) => AllStak.captureException(error, ctx),
|
|
2784
|
+
captureMessage: (msg, level = "info") => AllStak.captureMessage(msg, level),
|
|
2785
|
+
setUser: (user) => AllStak.setUser(user),
|
|
2786
|
+
setTag: (key, value) => AllStak.setTag(key, value),
|
|
2787
|
+
addBreadcrumb: (type, message, level, data) => AllStak.addBreadcrumb(type, message, level, data)
|
|
2788
|
+
}),
|
|
2789
|
+
[]
|
|
2790
|
+
);
|
|
2791
|
+
}
|
|
2792
|
+
function __resetProviderInstanceForTest() {
|
|
2793
|
+
__providerOwnedInstance = null;
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
// src/index.ts
|
|
2797
|
+
var __testNativeModule = null;
|
|
2798
|
+
function __setNativeModuleForTest(mod) {
|
|
2799
|
+
__testNativeModule = mod;
|
|
2800
|
+
}
|
|
2801
|
+
async function __devTriggerNativeCrash() {
|
|
2802
|
+
try {
|
|
2803
|
+
let native = __testNativeModule;
|
|
2804
|
+
if (!native) {
|
|
2805
|
+
const rn = require("react-native");
|
|
2806
|
+
native = rn?.NativeModules?.AllStakNative;
|
|
2807
|
+
}
|
|
2808
|
+
if (!native || typeof native.__devTriggerCrash !== "function") return;
|
|
2809
|
+
await native.__devTriggerCrash();
|
|
2810
|
+
} catch {
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
async function drainPendingNativeCrashes(release) {
|
|
2814
|
+
try {
|
|
2815
|
+
let native = __testNativeModule;
|
|
2816
|
+
if (!native) {
|
|
2817
|
+
const rn = require("react-native");
|
|
2818
|
+
native = rn?.NativeModules?.AllStakNative;
|
|
2819
|
+
}
|
|
2820
|
+
if (!native) return;
|
|
2821
|
+
if (typeof native.install === "function") {
|
|
2822
|
+
try {
|
|
2823
|
+
await native.install(release ?? "");
|
|
2824
|
+
} catch {
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
if (typeof native.drainPendingCrash === "function") {
|
|
2828
|
+
const json = await native.drainPendingCrash();
|
|
2829
|
+
if (json && json !== "") {
|
|
2830
|
+
try {
|
|
2831
|
+
const payload = JSON.parse(json);
|
|
2832
|
+
const err = new Error(payload?.message ?? "Native crash");
|
|
2833
|
+
err.name = payload?.exceptionClass ?? "NativeCrash";
|
|
2834
|
+
err.stack = Array.isArray(payload?.stackTrace) ? payload.stackTrace.join("\n") : String(payload?.stackTrace ?? "");
|
|
2835
|
+
AllStak.captureException(err, {
|
|
2836
|
+
...payload?.metadata || {},
|
|
2837
|
+
"native.crash": "true"
|
|
2838
|
+
});
|
|
2839
|
+
} catch {
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
} catch {
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
1875
2846
|
//# sourceMappingURL=index.js.map
|