@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/dist/index.js
CHANGED
|
@@ -30,11 +30,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
ALWAYS_REDACT_HEADERS: () => ALWAYS_REDACT_HEADERS,
|
|
34
|
+
ALWAYS_REDACT_QUERY: () => ALWAYS_REDACT_QUERY,
|
|
33
35
|
AllStak: () => AllStak,
|
|
34
36
|
AllStakClient: () => AllStakClient,
|
|
35
37
|
AllStakProvider: () => AllStakProvider,
|
|
38
|
+
DEFAULT_REDACT_BODY_FIELDS: () => DEFAULT_REDACT_BODY_FIELDS,
|
|
36
39
|
HttpRequestModule: () => HttpRequestModule,
|
|
37
40
|
INGEST_HOST: () => INGEST_HOST,
|
|
41
|
+
REDACTED: () => REDACTED,
|
|
38
42
|
ReplaySurrogate: () => ReplaySurrogate,
|
|
39
43
|
SDK_NAME: () => SDK_NAME,
|
|
40
44
|
SDK_VERSION: () => SDK_VERSION,
|
|
@@ -45,39 +49,71 @@ __export(index_exports, {
|
|
|
45
49
|
__resetProviderInstanceForTest: () => __resetProviderInstanceForTest,
|
|
46
50
|
__setNativeModuleForTest: () => __setNativeModuleForTest,
|
|
47
51
|
applyArchitectureTags: () => applyArchitectureTags,
|
|
52
|
+
captureBodyResult: () => captureBodyResult,
|
|
48
53
|
detectArchitecture: () => detectArchitecture,
|
|
49
54
|
drainPendingNativeCrashes: () => drainPendingNativeCrashes,
|
|
50
55
|
installReactNative: () => installReactNative,
|
|
51
56
|
instrumentNavigationFromLinking: () => instrumentNavigationFromLinking,
|
|
52
57
|
instrumentReactNavigation: () => instrumentReactNavigation,
|
|
58
|
+
redactUrl: () => redactUrl,
|
|
59
|
+
sanitizeHeaders: () => sanitizeHeaders,
|
|
53
60
|
tryAutoInstrumentNavigation: () => tryAutoInstrumentNavigation,
|
|
54
61
|
useAllStak: () => useAllStak
|
|
55
62
|
});
|
|
56
63
|
module.exports = __toCommonJS(index_exports);
|
|
57
64
|
|
|
58
65
|
// src/transport.ts
|
|
59
|
-
var REQUEST_TIMEOUT =
|
|
66
|
+
var REQUEST_TIMEOUT = 2e3;
|
|
60
67
|
var MAX_BUFFER = 100;
|
|
68
|
+
var FAILURE_THRESHOLD = 3;
|
|
69
|
+
var BACKOFF_BASE_MS = 500;
|
|
70
|
+
var BACKOFF_MAX_MS = 3e4;
|
|
61
71
|
var HttpTransport = class {
|
|
62
|
-
constructor(baseUrl, apiKey) {
|
|
72
|
+
constructor(baseUrl, apiKey, enabled = true) {
|
|
63
73
|
this.baseUrl = baseUrl;
|
|
64
74
|
this.apiKey = apiKey;
|
|
75
|
+
this.enabled = enabled;
|
|
65
76
|
this.buffer = [];
|
|
66
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);
|
|
67
98
|
}
|
|
68
|
-
async
|
|
99
|
+
async dispatch(item) {
|
|
69
100
|
try {
|
|
70
|
-
await this.doFetch(path, payload);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
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);
|
|
75
110
|
}
|
|
76
111
|
}
|
|
77
112
|
async doFetch(path, payload) {
|
|
78
113
|
const url = `${this.baseUrl}${path}`;
|
|
79
114
|
const controller = new AbortController();
|
|
80
115
|
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
116
|
+
const started = Date.now();
|
|
81
117
|
try {
|
|
82
118
|
const res = await fetch(url, {
|
|
83
119
|
method: "POST",
|
|
@@ -91,26 +127,77 @@ var HttpTransport = class {
|
|
|
91
127
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
92
128
|
} finally {
|
|
93
129
|
clearTimeout(timeoutId);
|
|
130
|
+
this.lastTransportLatencyMs = Date.now() - started;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
push(item) {
|
|
134
|
+
if (this.buffer.length >= MAX_BUFFER) {
|
|
135
|
+
this.buffer.shift();
|
|
136
|
+
this.dropped++;
|
|
94
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();
|
|
95
147
|
}
|
|
96
148
|
async flushBuffer() {
|
|
97
149
|
if (this.flushing || this.buffer.length === 0) return;
|
|
98
150
|
this.flushing = true;
|
|
151
|
+
const started = Date.now();
|
|
99
152
|
try {
|
|
100
153
|
const items = this.buffer.splice(0, this.buffer.length);
|
|
101
154
|
for (const item of items) {
|
|
155
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
156
|
+
this.push(item);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
102
159
|
try {
|
|
103
160
|
await this.doFetch(item.path, item.payload);
|
|
104
|
-
|
|
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);
|
|
105
168
|
}
|
|
106
169
|
}
|
|
107
170
|
} finally {
|
|
171
|
+
this.lastFlushDurationMs = Date.now() - started;
|
|
108
172
|
this.flushing = false;
|
|
173
|
+
if (this.buffer.length > 0) this.scheduleFlush();
|
|
109
174
|
}
|
|
110
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
|
+
}
|
|
111
183
|
getBufferSize() {
|
|
112
184
|
return this.buffer.length;
|
|
113
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
|
+
}
|
|
114
201
|
/**
|
|
115
202
|
* Wait for the in-flight retry-buffer to drain. Resolves `true` if the
|
|
116
203
|
* buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
|
|
@@ -127,6 +214,14 @@ var HttpTransport = class {
|
|
|
127
214
|
return true;
|
|
128
215
|
}
|
|
129
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
|
+
}
|
|
130
225
|
|
|
131
226
|
// src/stack.ts
|
|
132
227
|
var V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?((?:.+?):(\d+):(\d+))\)?\s*$/;
|
|
@@ -181,6 +276,24 @@ function isInApp(filename) {
|
|
|
181
276
|
return true;
|
|
182
277
|
}
|
|
183
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
|
+
|
|
184
297
|
// src/scope.ts
|
|
185
298
|
var Scope = class {
|
|
186
299
|
constructor() {
|
|
@@ -392,6 +505,7 @@ var TracingModule = class {
|
|
|
392
505
|
}
|
|
393
506
|
if (!this.flushTimer) {
|
|
394
507
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
|
|
508
|
+
this.flushTimer?.unref?.();
|
|
395
509
|
}
|
|
396
510
|
}
|
|
397
511
|
flush() {
|
|
@@ -437,10 +551,11 @@ var ReplaySurrogate = class {
|
|
|
437
551
|
if (Math.random() >= this.opts.sampleRate) return false;
|
|
438
552
|
this.active = true;
|
|
439
553
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS2);
|
|
554
|
+
this.flushTimer?.unref?.();
|
|
440
555
|
return true;
|
|
441
556
|
}
|
|
442
557
|
/** Record a screen view. Filters params through the safeParams allow-list. */
|
|
443
|
-
recordScreenView(routeName, params) {
|
|
558
|
+
recordScreenView(routeName, params, context) {
|
|
444
559
|
if (!this.active) return;
|
|
445
560
|
const safe = {};
|
|
446
561
|
if (params && this.opts.safeParams.length > 0) {
|
|
@@ -448,17 +563,22 @@ var ReplaySurrogate = class {
|
|
|
448
563
|
if (key in params) safe[key] = params[key];
|
|
449
564
|
}
|
|
450
565
|
}
|
|
451
|
-
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) } });
|
|
452
567
|
}
|
|
453
568
|
/** Record an AppState transition (foreground/background/inactive). */
|
|
454
|
-
recordAppState(next) {
|
|
569
|
+
recordAppState(next, context) {
|
|
455
570
|
if (!this.active) return;
|
|
456
|
-
this.push({ ts: Date.now(), k: "appstate", data: { state: next } });
|
|
571
|
+
this.push({ ts: Date.now(), k: "appstate", data: { state: next, ...compact(context) } });
|
|
457
572
|
}
|
|
458
573
|
/** Record a free-form, customer-validated checkpoint. */
|
|
459
|
-
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) {
|
|
460
580
|
if (!this.active) return;
|
|
461
|
-
this.push({ ts: Date.now(), k:
|
|
581
|
+
this.push({ ts: Date.now(), k: kind, data: { label, ...data ?? {}, ...compact(context) } });
|
|
462
582
|
}
|
|
463
583
|
destroy() {
|
|
464
584
|
this.destroyed = true;
|
|
@@ -492,6 +612,14 @@ var ReplaySurrogate = class {
|
|
|
492
612
|
});
|
|
493
613
|
}
|
|
494
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
|
+
}
|
|
495
623
|
|
|
496
624
|
// src/http-requests.ts
|
|
497
625
|
var INGEST_PATH = "/ingest/v1/http-requests";
|
|
@@ -503,6 +631,12 @@ function genTraceId() {
|
|
|
503
631
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
504
632
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
505
633
|
}
|
|
634
|
+
function genRequestId() {
|
|
635
|
+
return genTraceId();
|
|
636
|
+
}
|
|
637
|
+
function generateHttpId() {
|
|
638
|
+
return genTraceId();
|
|
639
|
+
}
|
|
506
640
|
function splitHostPath(url) {
|
|
507
641
|
try {
|
|
508
642
|
const u = new URL(url);
|
|
@@ -529,6 +663,7 @@ var HttpRequestModule = class {
|
|
|
529
663
|
const item = {
|
|
530
664
|
type: "http_request",
|
|
531
665
|
traceId: ev.traceId ?? genTraceId(),
|
|
666
|
+
requestId: ev.requestId ?? genRequestId(),
|
|
532
667
|
direction: "outbound",
|
|
533
668
|
method: (ev.method || "GET").toUpperCase(),
|
|
534
669
|
host,
|
|
@@ -543,6 +678,16 @@ var HttpRequestModule = class {
|
|
|
543
678
|
requestHeaders: ev.requestHeaders,
|
|
544
679
|
responseHeaders: ev.responseHeaders,
|
|
545
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",
|
|
546
691
|
environment: this.defaults.environment,
|
|
547
692
|
release: this.defaults.release,
|
|
548
693
|
dist: this.defaults.dist,
|
|
@@ -561,7 +706,10 @@ var HttpRequestModule = class {
|
|
|
561
706
|
this.flush();
|
|
562
707
|
return;
|
|
563
708
|
}
|
|
564
|
-
if (!this.flushTimer)
|
|
709
|
+
if (!this.flushTimer) {
|
|
710
|
+
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS3);
|
|
711
|
+
this.flushTimer?.unref?.();
|
|
712
|
+
}
|
|
565
713
|
}
|
|
566
714
|
/** Snapshot of the last failed requests for error-linking. Newest last. */
|
|
567
715
|
getRecentFailed() {
|
|
@@ -613,6 +761,24 @@ var ALWAYS_REDACT_QUERY = /* @__PURE__ */ new Set([
|
|
|
613
761
|
"jwt"
|
|
614
762
|
]);
|
|
615
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
|
+
];
|
|
616
782
|
function shouldCaptureUrl(url, opts) {
|
|
617
783
|
if (!url) return false;
|
|
618
784
|
const lower = url.toLowerCase();
|
|
@@ -680,25 +846,125 @@ function sanitizeHeaders(headers, opts) {
|
|
|
680
846
|
}
|
|
681
847
|
return out;
|
|
682
848
|
}
|
|
683
|
-
function
|
|
684
|
-
if (!enabled)
|
|
685
|
-
|
|
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
|
+
}
|
|
686
875
|
let str;
|
|
876
|
+
let redactedFields = [];
|
|
687
877
|
if (typeof body === "string") str = body;
|
|
688
878
|
else if (typeof body === "number" || typeof body === "boolean") str = String(body);
|
|
689
879
|
else if (typeof body === "object") {
|
|
690
880
|
const tag = Object.prototype.toString.call(body);
|
|
691
|
-
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;
|
|
692
892
|
try {
|
|
693
|
-
str = JSON.stringify(
|
|
893
|
+
str = JSON.stringify(redacted.value);
|
|
694
894
|
} catch {
|
|
695
|
-
return
|
|
895
|
+
return {
|
|
896
|
+
body: "<unserializable>",
|
|
897
|
+
status: "unsupported",
|
|
898
|
+
redactedFields,
|
|
899
|
+
truncated: false,
|
|
900
|
+
capturePolicy: "unserializable_body"
|
|
901
|
+
};
|
|
696
902
|
}
|
|
697
903
|
} else {
|
|
698
|
-
return
|
|
904
|
+
return {
|
|
905
|
+
body: "<binary>",
|
|
906
|
+
status: "unsupported",
|
|
907
|
+
redactedFields: [],
|
|
908
|
+
truncated: false,
|
|
909
|
+
capturePolicy: "unsupported_body_type"
|
|
910
|
+
};
|
|
699
911
|
}
|
|
700
|
-
if (
|
|
701
|
-
|
|
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;
|
|
702
968
|
}
|
|
703
969
|
|
|
704
970
|
// src/http-instrumentation.ts
|
|
@@ -708,12 +974,16 @@ var AXIOS_FLAG = /* @__PURE__ */ Symbol.for("allstak.http.axios.instrumented");
|
|
|
708
974
|
var DEFAULT_MAX_BODY = 4096;
|
|
709
975
|
var _currentModule = null;
|
|
710
976
|
var _currentOpts = null;
|
|
977
|
+
var _currentRuntime = null;
|
|
711
978
|
function currentModule() {
|
|
712
979
|
return _currentModule;
|
|
713
980
|
}
|
|
714
981
|
function currentOpts() {
|
|
715
982
|
return _currentOpts;
|
|
716
983
|
}
|
|
984
|
+
function currentRuntime() {
|
|
985
|
+
return _currentRuntime;
|
|
986
|
+
}
|
|
717
987
|
function safeCapture(ev) {
|
|
718
988
|
try {
|
|
719
989
|
currentModule()?.capture(ev);
|
|
@@ -730,6 +1000,8 @@ function bind(opts, ownIngestHost) {
|
|
|
730
1000
|
ignoredUrls: opts.ignoredUrls ?? [],
|
|
731
1001
|
allowedUrls: opts.allowedUrls ?? [],
|
|
732
1002
|
maxBodyBytes: opts.maxBodyBytes ?? DEFAULT_MAX_BODY,
|
|
1003
|
+
allowedContentTypes: opts.allowedContentTypes ?? ["application/json", "text/", "application/problem+json"],
|
|
1004
|
+
redactBodyFields: opts.redactBodyFields ?? [],
|
|
733
1005
|
ownIngestPrefix: ownIngestHost.replace(/\/$/, "")
|
|
734
1006
|
};
|
|
735
1007
|
}
|
|
@@ -776,6 +1048,77 @@ function headersToObject(h) {
|
|
|
776
1048
|
}
|
|
777
1049
|
return {};
|
|
778
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
|
+
}
|
|
779
1122
|
function patchFetch() {
|
|
780
1123
|
const g = globalThis;
|
|
781
1124
|
if (typeof g.fetch !== "function") return;
|
|
@@ -793,23 +1136,37 @@ function patchFetch() {
|
|
|
793
1136
|
return original.call(this, input, init);
|
|
794
1137
|
}
|
|
795
1138
|
const start = Date.now();
|
|
796
|
-
const
|
|
797
|
-
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"]);
|
|
798
1144
|
const reqSize = safeByteLength(typeof init?.body === "string" ? init.body : void 0);
|
|
799
1145
|
let response;
|
|
800
1146
|
try {
|
|
801
|
-
response = await original.call(this, input,
|
|
1147
|
+
response = await original.call(this, input, requestInit);
|
|
802
1148
|
} catch (err) {
|
|
1149
|
+
ctx?.span.finish("error");
|
|
1150
|
+
if (ctx) recordTimeline("exception", "request_failed", ctx, { method, url: sanitizedUrl, error: String(err?.message ?? err) });
|
|
803
1151
|
safeCapture({
|
|
804
1152
|
type: "http_request",
|
|
1153
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1154
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1155
|
+
spanId: ctx?.spanId,
|
|
1156
|
+
parentSpanId: ctx?.parentSpanId,
|
|
805
1157
|
method,
|
|
806
1158
|
url: sanitizedUrl,
|
|
807
1159
|
statusCode: 0,
|
|
808
1160
|
durationMs: Date.now() - start,
|
|
809
|
-
requestBody: reqBody,
|
|
1161
|
+
requestBody: reqBody.body,
|
|
810
1162
|
requestHeaders: reqHeaders,
|
|
811
1163
|
requestSize: reqSize,
|
|
812
|
-
|
|
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"
|
|
813
1170
|
});
|
|
814
1171
|
throw err;
|
|
815
1172
|
}
|
|
@@ -825,25 +1182,41 @@ function patchFetch() {
|
|
|
825
1182
|
try {
|
|
826
1183
|
const cloned = response.clone();
|
|
827
1184
|
const text = await cloned.text();
|
|
828
|
-
respBody =
|
|
1185
|
+
respBody = captureBodyResult(text, true, opts.maxBodyBytes, opts, respHeaders?.["content-type"]).body;
|
|
829
1186
|
if (respSize == null) respSize = safeByteLength(text);
|
|
830
1187
|
} catch {
|
|
831
1188
|
}
|
|
832
1189
|
}
|
|
833
1190
|
} catch {
|
|
834
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 });
|
|
835
1196
|
safeCapture({
|
|
836
1197
|
type: "http_request",
|
|
1198
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1199
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1200
|
+
spanId: ctx?.spanId,
|
|
1201
|
+
parentSpanId: ctx?.parentSpanId,
|
|
837
1202
|
method,
|
|
838
1203
|
url: sanitizedUrl,
|
|
839
1204
|
statusCode: response.status,
|
|
840
1205
|
durationMs,
|
|
841
|
-
requestBody: reqBody,
|
|
1206
|
+
requestBody: reqBody.body,
|
|
842
1207
|
requestHeaders: reqHeaders,
|
|
843
1208
|
requestSize: reqSize,
|
|
844
|
-
responseBody:
|
|
1209
|
+
responseBody: respBodyResult.body,
|
|
845
1210
|
responseHeaders: respHeaders,
|
|
846
|
-
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"
|
|
847
1220
|
});
|
|
848
1221
|
return response;
|
|
849
1222
|
};
|
|
@@ -881,7 +1254,17 @@ function patchXhr() {
|
|
|
881
1254
|
return origSend.call(this, body);
|
|
882
1255
|
}
|
|
883
1256
|
const reqHeaders = sanitizeHeaders(this.__allstak_headers__, opts);
|
|
884
|
-
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"]);
|
|
885
1268
|
const reqSize = safeByteLength(typeof body === "string" ? body : void 0);
|
|
886
1269
|
const finish = (statusCode, error) => {
|
|
887
1270
|
const durationMs = Date.now() - start;
|
|
@@ -899,28 +1282,43 @@ function patchXhr() {
|
|
|
899
1282
|
}
|
|
900
1283
|
respHeaders = sanitizeHeaders(dict, liveOpts);
|
|
901
1284
|
}
|
|
1285
|
+
let respBodyResult = captureBodyResult(void 0, false, liveOpts.maxBodyBytes, liveOpts);
|
|
902
1286
|
if (liveOpts.captureResponseBody) {
|
|
903
1287
|
const text = this.responseText;
|
|
904
1288
|
if (typeof text === "string") {
|
|
905
|
-
|
|
1289
|
+
respBodyResult = captureBodyResult(text, true, liveOpts.maxBodyBytes, liveOpts, respHeaders?.["content-type"]);
|
|
1290
|
+
respBody = respBodyResult.body;
|
|
906
1291
|
respSize = safeByteLength(text);
|
|
907
1292
|
}
|
|
908
1293
|
}
|
|
909
1294
|
} catch {
|
|
910
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 });
|
|
911
1299
|
safeCapture({
|
|
912
1300
|
type: "http_request",
|
|
1301
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1302
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1303
|
+
spanId: ctx?.spanId,
|
|
1304
|
+
parentSpanId: ctx?.parentSpanId,
|
|
913
1305
|
method,
|
|
914
1306
|
url: sanitizedUrl,
|
|
915
1307
|
statusCode,
|
|
916
1308
|
durationMs,
|
|
917
|
-
requestBody: reqBody,
|
|
1309
|
+
requestBody: reqBody.body,
|
|
918
1310
|
requestHeaders: reqHeaders,
|
|
919
1311
|
requestSize: reqSize,
|
|
920
1312
|
responseBody: respBody,
|
|
921
1313
|
responseHeaders: respHeaders,
|
|
922
1314
|
responseSize: respSize,
|
|
923
|
-
|
|
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"
|
|
924
1322
|
});
|
|
925
1323
|
};
|
|
926
1324
|
this.addEventListener?.("load", () => finish(this.status || 0));
|
|
@@ -939,10 +1337,17 @@ function instrumentAxiosInstance(axiosInstance, module2, opts) {
|
|
|
939
1337
|
axiosInstance.interceptors.request.use((config) => {
|
|
940
1338
|
try {
|
|
941
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
|
+
}
|
|
942
1346
|
reqStarts.set(config, {
|
|
943
1347
|
start: Date.now(),
|
|
944
|
-
method
|
|
945
|
-
rawUrl
|
|
1348
|
+
method,
|
|
1349
|
+
rawUrl,
|
|
1350
|
+
ctx
|
|
946
1351
|
});
|
|
947
1352
|
} catch {
|
|
948
1353
|
}
|
|
@@ -956,21 +1361,36 @@ function instrumentAxiosInstance(axiosInstance, module2, opts) {
|
|
|
956
1361
|
if (!shouldCaptureUrl(meta.rawUrl, opts)) return;
|
|
957
1362
|
const sanitizedUrl = redactUrl(meta.rawUrl, opts);
|
|
958
1363
|
const reqHeaders = sanitizeHeaders(headersToObject(cfg.headers), opts);
|
|
959
|
-
const reqBody =
|
|
1364
|
+
const reqBody = captureBodyResult(cfg.data, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
960
1365
|
const respHeaders = sanitizeHeaders(headersToObject(response?.headers), opts);
|
|
961
|
-
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 });
|
|
962
1370
|
try {
|
|
963
1371
|
module2.capture({
|
|
964
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,
|
|
965
1377
|
method: meta.method,
|
|
966
1378
|
url: sanitizedUrl,
|
|
967
1379
|
statusCode,
|
|
968
1380
|
durationMs: Date.now() - meta.start,
|
|
969
|
-
requestBody: reqBody,
|
|
1381
|
+
requestBody: reqBody.body,
|
|
970
1382
|
requestHeaders: reqHeaders,
|
|
971
|
-
responseBody: respBody,
|
|
1383
|
+
responseBody: respBody.body,
|
|
972
1384
|
responseHeaders: respHeaders,
|
|
973
|
-
|
|
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"
|
|
974
1394
|
});
|
|
975
1395
|
} catch {
|
|
976
1396
|
}
|
|
@@ -996,10 +1416,11 @@ function tryAutoInstrumentAxios(module2, opts) {
|
|
|
996
1416
|
} catch {
|
|
997
1417
|
}
|
|
998
1418
|
}
|
|
999
|
-
function installHttpInstrumentation(module2, options, ownIngestHost) {
|
|
1419
|
+
function installHttpInstrumentation(module2, options, ownIngestHost, runtime) {
|
|
1000
1420
|
const bound = bind(options, ownIngestHost);
|
|
1001
1421
|
_currentModule = module2;
|
|
1002
1422
|
_currentOpts = bound;
|
|
1423
|
+
_currentRuntime = runtime;
|
|
1003
1424
|
try {
|
|
1004
1425
|
patchFetch();
|
|
1005
1426
|
} catch {
|
|
@@ -1016,6 +1437,11 @@ function installHttpInstrumentation(module2, options, ownIngestHost) {
|
|
|
1016
1437
|
instrumentAxios: (axios) => instrumentAxiosInstance(axios, module2, bound)
|
|
1017
1438
|
};
|
|
1018
1439
|
}
|
|
1440
|
+
function unbindHttpInstrumentation() {
|
|
1441
|
+
_currentModule = null;
|
|
1442
|
+
_currentOpts = null;
|
|
1443
|
+
_currentRuntime = null;
|
|
1444
|
+
}
|
|
1019
1445
|
|
|
1020
1446
|
// src/client.ts
|
|
1021
1447
|
var INGEST_HOST = "https://api.allstak.sa";
|
|
@@ -1036,6 +1462,17 @@ function generateId() {
|
|
|
1036
1462
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
1037
1463
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
1038
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
|
+
}
|
|
1039
1476
|
var AllStakClient = class {
|
|
1040
1477
|
constructor(config) {
|
|
1041
1478
|
this.breadcrumbs = [];
|
|
@@ -1043,9 +1480,6 @@ var AllStakClient = class {
|
|
|
1043
1480
|
this.replay = null;
|
|
1044
1481
|
this.httpRequests = null;
|
|
1045
1482
|
this._instrumentAxios = null;
|
|
1046
|
-
if (!config.apiKey) {
|
|
1047
|
-
throw new Error("AllStak: config.apiKey is required");
|
|
1048
|
-
}
|
|
1049
1483
|
this.config = { ...config };
|
|
1050
1484
|
if (!this.config.environment) this.config.environment = "production";
|
|
1051
1485
|
if (!this.config.sdkName) this.config.sdkName = SDK_NAME;
|
|
@@ -1054,7 +1488,7 @@ var AllStakClient = class {
|
|
|
1054
1488
|
this.sessionId = generateId();
|
|
1055
1489
|
this.maxBreadcrumbs = config.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS;
|
|
1056
1490
|
const baseUrl = (config.host ?? INGEST_HOST).replace(/\/$/, "");
|
|
1057
|
-
this.transport = new HttpTransport(baseUrl, config.apiKey);
|
|
1491
|
+
this.transport = new HttpTransport(baseUrl, config.apiKey ?? "", Boolean(config.apiKey));
|
|
1058
1492
|
this.tracing = new TracingModule(this.transport, {
|
|
1059
1493
|
service: config.service ?? config.release ?? "",
|
|
1060
1494
|
environment: this.config.environment ?? "production",
|
|
@@ -1081,7 +1515,15 @@ var AllStakClient = class {
|
|
|
1081
1515
|
const { instrumentAxios } = installHttpInstrumentation(
|
|
1082
1516
|
this.httpRequests,
|
|
1083
1517
|
config.httpTracking ?? {},
|
|
1084
|
-
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
|
+
}
|
|
1085
1527
|
);
|
|
1086
1528
|
this._instrumentAxios = instrumentAxios;
|
|
1087
1529
|
} catch {
|
|
@@ -1105,33 +1547,67 @@ var AllStakClient = class {
|
|
|
1105
1547
|
if (!this.passesSampleRate()) return;
|
|
1106
1548
|
const frames = parseStack(error.stack).map((f) => ({
|
|
1107
1549
|
...f,
|
|
1108
|
-
platform: this.config.platform
|
|
1550
|
+
platform: this.config.platform,
|
|
1551
|
+
debugId: resolveDebugId(f.filename)
|
|
1109
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;
|
|
1110
1556
|
const stackTrace = frames.length > 0 ? frames.map(frameToString) : void 0;
|
|
1111
1557
|
const currentBreadcrumbs = this.breadcrumbs.length > 0 ? [...this.breadcrumbs] : void 0;
|
|
1112
1558
|
this.breadcrumbs = [];
|
|
1113
1559
|
const exceptionClass = (error.name && error.name !== "Error" ? error.name : void 0) || error.constructor?.name || "Error";
|
|
1114
1560
|
const eff = this.effective();
|
|
1115
1561
|
const traceContext = {};
|
|
1116
|
-
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();
|
|
1117
1574
|
if (traceId) traceContext.traceId = traceId;
|
|
1118
|
-
const spanId = this.tracing.getCurrentSpanId();
|
|
1575
|
+
const spanId = exceptionSpan?.spanId || this.tracing.getCurrentSpanId();
|
|
1119
1576
|
if (spanId) traceContext.spanId = spanId;
|
|
1120
|
-
const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
|
|
1121
1577
|
if (recentFailed.length > 0) {
|
|
1122
1578
|
traceContext["http.recentFailed"] = recentFailed.map((r) => ({
|
|
1123
1579
|
method: r.method,
|
|
1124
1580
|
url: r.url,
|
|
1125
1581
|
statusCode: r.statusCode,
|
|
1126
1582
|
durationMs: r.durationMs,
|
|
1127
|
-
error: r.error
|
|
1583
|
+
error: r.error,
|
|
1584
|
+
requestId: r.requestId,
|
|
1585
|
+
traceId: r.traceId,
|
|
1586
|
+
confidence: r.requestId === linkedRequest?.requestId ? "inferred" : "weak"
|
|
1128
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 {
|
|
1129
1604
|
}
|
|
1130
1605
|
const payload = {
|
|
1131
1606
|
exceptionClass,
|
|
1132
1607
|
message: error.message,
|
|
1133
1608
|
stackTrace,
|
|
1134
1609
|
frames: frames.length > 0 ? frames : void 0,
|
|
1610
|
+
debugMeta,
|
|
1135
1611
|
platform: this.config.platform,
|
|
1136
1612
|
sdkName: this.config.sdkName,
|
|
1137
1613
|
sdkVersion: this.config.sdkVersion,
|
|
@@ -1140,12 +1616,29 @@ var AllStakClient = class {
|
|
|
1140
1616
|
environment: this.config.environment,
|
|
1141
1617
|
release: this.config.release,
|
|
1142
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,
|
|
1143
1623
|
user: eff.user,
|
|
1144
1624
|
metadata: { ...this.buildMetadata(context), ...traceContext },
|
|
1145
1625
|
breadcrumbs: currentBreadcrumbs,
|
|
1146
1626
|
fingerprint: eff.fingerprint
|
|
1147
1627
|
};
|
|
1148
|
-
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
|
+
});
|
|
1149
1642
|
}
|
|
1150
1643
|
/** Start a new span. Auto-parented to any currently-active span. */
|
|
1151
1644
|
startSpan(operation, options) {
|
|
@@ -1186,6 +1679,9 @@ var AllStakClient = class {
|
|
|
1186
1679
|
environment: this.config.environment,
|
|
1187
1680
|
release: this.config.release,
|
|
1188
1681
|
sessionId: this.sessionId,
|
|
1682
|
+
traceId: this.tracing.getTraceId(),
|
|
1683
|
+
spanId: this.tracing.getCurrentSpanId() ?? void 0,
|
|
1684
|
+
service: this.config.service,
|
|
1189
1685
|
user: eff.user,
|
|
1190
1686
|
metadata: this.buildMetadata(),
|
|
1191
1687
|
fingerprint: eff.fingerprint
|
|
@@ -1269,6 +1765,9 @@ var AllStakClient = class {
|
|
|
1269
1765
|
getConfig() {
|
|
1270
1766
|
return this.config;
|
|
1271
1767
|
}
|
|
1768
|
+
getTransportStats() {
|
|
1769
|
+
return this.transport.getStats();
|
|
1770
|
+
}
|
|
1272
1771
|
destroy() {
|
|
1273
1772
|
this.tracing.destroy();
|
|
1274
1773
|
if (this.replay) {
|
|
@@ -1279,6 +1778,7 @@ var AllStakClient = class {
|
|
|
1279
1778
|
this.httpRequests.destroy();
|
|
1280
1779
|
this.httpRequests = null;
|
|
1281
1780
|
}
|
|
1781
|
+
unbindHttpInstrumentation();
|
|
1282
1782
|
this._instrumentAxios = null;
|
|
1283
1783
|
this.breadcrumbs = [];
|
|
1284
1784
|
}
|
|
@@ -1297,6 +1797,58 @@ var AllStakClient = class {
|
|
|
1297
1797
|
metadata: this.buildMetadata()
|
|
1298
1798
|
});
|
|
1299
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
|
+
}
|
|
1300
1852
|
passesSampleRate() {
|
|
1301
1853
|
const r = this.config.sampleRate;
|
|
1302
1854
|
if (typeof r !== "number" || r >= 1) return true;
|
|
@@ -1395,10 +1947,22 @@ var AllStakClient = class {
|
|
|
1395
1947
|
}
|
|
1396
1948
|
};
|
|
1397
1949
|
var instance = null;
|
|
1398
|
-
function
|
|
1399
|
-
if (!instance) throw new Error("AllStak.init() must be called before using the SDK");
|
|
1950
|
+
function maybeInit() {
|
|
1400
1951
|
return instance;
|
|
1401
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
|
+
}
|
|
1402
1966
|
function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
1403
1967
|
try {
|
|
1404
1968
|
instance?.addBreadcrumb(type, message, level, data);
|
|
@@ -1407,51 +1971,99 @@ function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
|
1407
1971
|
}
|
|
1408
1972
|
var AllStak = {
|
|
1409
1973
|
init(config) {
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
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
|
+
}
|
|
1413
1982
|
},
|
|
1414
1983
|
captureException(error, context) {
|
|
1415
|
-
|
|
1984
|
+
try {
|
|
1985
|
+
maybeInit()?.captureException(error, context);
|
|
1986
|
+
} catch {
|
|
1987
|
+
}
|
|
1416
1988
|
},
|
|
1417
1989
|
captureMessage(message, level = "info", options) {
|
|
1418
|
-
|
|
1990
|
+
try {
|
|
1991
|
+
maybeInit()?.captureMessage(message, level, options);
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1419
1994
|
},
|
|
1420
1995
|
addBreadcrumb(type, message, level, data) {
|
|
1421
|
-
|
|
1996
|
+
try {
|
|
1997
|
+
maybeInit()?.addBreadcrumb(type, message, level, data);
|
|
1998
|
+
} catch {
|
|
1999
|
+
}
|
|
1422
2000
|
},
|
|
1423
2001
|
clearBreadcrumbs() {
|
|
1424
|
-
|
|
2002
|
+
try {
|
|
2003
|
+
maybeInit()?.clearBreadcrumbs();
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
1425
2006
|
},
|
|
1426
2007
|
setUser(user) {
|
|
1427
|
-
|
|
2008
|
+
try {
|
|
2009
|
+
maybeInit()?.setUser(user);
|
|
2010
|
+
} catch {
|
|
2011
|
+
}
|
|
1428
2012
|
},
|
|
1429
2013
|
setTag(key, value) {
|
|
1430
|
-
|
|
2014
|
+
try {
|
|
2015
|
+
maybeInit()?.setTag(key, value);
|
|
2016
|
+
} catch {
|
|
2017
|
+
}
|
|
1431
2018
|
},
|
|
1432
2019
|
setTags(tags) {
|
|
1433
|
-
|
|
2020
|
+
try {
|
|
2021
|
+
maybeInit()?.setTags(tags);
|
|
2022
|
+
} catch {
|
|
2023
|
+
}
|
|
1434
2024
|
},
|
|
1435
2025
|
setExtra(key, value) {
|
|
1436
|
-
|
|
2026
|
+
try {
|
|
2027
|
+
maybeInit()?.setExtra(key, value);
|
|
2028
|
+
} catch {
|
|
2029
|
+
}
|
|
1437
2030
|
},
|
|
1438
2031
|
setExtras(extras) {
|
|
1439
|
-
|
|
2032
|
+
try {
|
|
2033
|
+
maybeInit()?.setExtras(extras);
|
|
2034
|
+
} catch {
|
|
2035
|
+
}
|
|
1440
2036
|
},
|
|
1441
2037
|
setContext(name, ctx) {
|
|
1442
|
-
|
|
2038
|
+
try {
|
|
2039
|
+
maybeInit()?.setContext(name, ctx);
|
|
2040
|
+
} catch {
|
|
2041
|
+
}
|
|
1443
2042
|
},
|
|
1444
2043
|
setLevel(level) {
|
|
1445
|
-
|
|
2044
|
+
try {
|
|
2045
|
+
maybeInit()?.setLevel(level);
|
|
2046
|
+
} catch {
|
|
2047
|
+
}
|
|
1446
2048
|
},
|
|
1447
2049
|
setFingerprint(fingerprint) {
|
|
1448
|
-
|
|
2050
|
+
try {
|
|
2051
|
+
maybeInit()?.setFingerprint(fingerprint);
|
|
2052
|
+
} catch {
|
|
2053
|
+
}
|
|
1449
2054
|
},
|
|
1450
2055
|
flush(timeoutMs) {
|
|
1451
|
-
|
|
2056
|
+
try {
|
|
2057
|
+
return maybeInit()?.flush(timeoutMs) ?? Promise.resolve(true);
|
|
2058
|
+
} catch {
|
|
2059
|
+
return Promise.resolve(false);
|
|
2060
|
+
}
|
|
1452
2061
|
},
|
|
1453
2062
|
setIdentity(identity) {
|
|
1454
|
-
|
|
2063
|
+
try {
|
|
2064
|
+
maybeInit()?.setIdentity(identity);
|
|
2065
|
+
} catch {
|
|
2066
|
+
}
|
|
1455
2067
|
},
|
|
1456
2068
|
/**
|
|
1457
2069
|
* Run `callback` with a fresh scoped context. Any user/tag/extra/context/
|
|
@@ -1460,37 +2072,79 @@ var AllStak = {
|
|
|
1460
2072
|
* for async callbacks and thrown errors.
|
|
1461
2073
|
*/
|
|
1462
2074
|
withScope(callback) {
|
|
1463
|
-
|
|
2075
|
+
try {
|
|
2076
|
+
const client = maybeInit();
|
|
2077
|
+
return client ? client.withScope(callback) : callback(new Scope());
|
|
2078
|
+
} catch {
|
|
2079
|
+
return callback(new Scope());
|
|
2080
|
+
}
|
|
1464
2081
|
},
|
|
1465
2082
|
startSpan(operation, options) {
|
|
1466
|
-
|
|
2083
|
+
try {
|
|
2084
|
+
return maybeInit()?.startSpan(operation, options) ?? noopSpan(operation);
|
|
2085
|
+
} catch {
|
|
2086
|
+
return noopSpan(operation);
|
|
2087
|
+
}
|
|
1467
2088
|
},
|
|
1468
2089
|
getTraceId() {
|
|
1469
|
-
|
|
2090
|
+
try {
|
|
2091
|
+
return maybeInit()?.getTraceId() ?? "";
|
|
2092
|
+
} catch {
|
|
2093
|
+
return "";
|
|
2094
|
+
}
|
|
1470
2095
|
},
|
|
1471
2096
|
setTraceId(traceId) {
|
|
1472
|
-
|
|
2097
|
+
try {
|
|
2098
|
+
maybeInit()?.setTraceId(traceId);
|
|
2099
|
+
} catch {
|
|
2100
|
+
}
|
|
1473
2101
|
},
|
|
1474
2102
|
getCurrentSpanId() {
|
|
1475
|
-
|
|
2103
|
+
try {
|
|
2104
|
+
return maybeInit()?.getCurrentSpanId() ?? null;
|
|
2105
|
+
} catch {
|
|
2106
|
+
return null;
|
|
2107
|
+
}
|
|
1476
2108
|
},
|
|
1477
2109
|
resetTrace() {
|
|
1478
|
-
|
|
2110
|
+
try {
|
|
2111
|
+
maybeInit()?.resetTrace();
|
|
2112
|
+
} catch {
|
|
2113
|
+
}
|
|
1479
2114
|
},
|
|
1480
2115
|
/** Access the privacy-first replay surrogate (or null if disabled / sampled out). */
|
|
1481
2116
|
getReplay() {
|
|
1482
|
-
|
|
2117
|
+
try {
|
|
2118
|
+
return maybeInit()?.getReplay() ?? null;
|
|
2119
|
+
} catch {
|
|
2120
|
+
return null;
|
|
2121
|
+
}
|
|
1483
2122
|
},
|
|
1484
2123
|
/** Manually instrument an axios instance. No-op when HTTP tracking is off. */
|
|
1485
2124
|
instrumentAxios(axios) {
|
|
1486
|
-
|
|
2125
|
+
try {
|
|
2126
|
+
return maybeInit()?.instrumentAxios(axios) ?? axios;
|
|
2127
|
+
} catch {
|
|
2128
|
+
return axios;
|
|
2129
|
+
}
|
|
1487
2130
|
},
|
|
1488
2131
|
getSessionId() {
|
|
1489
|
-
|
|
2132
|
+
try {
|
|
2133
|
+
return maybeInit()?.getSessionId() ?? "";
|
|
2134
|
+
} catch {
|
|
2135
|
+
return "";
|
|
2136
|
+
}
|
|
1490
2137
|
},
|
|
1491
2138
|
getConfig() {
|
|
1492
2139
|
return instance?.getConfig() ?? null;
|
|
1493
2140
|
},
|
|
2141
|
+
getTransportStats() {
|
|
2142
|
+
try {
|
|
2143
|
+
return maybeInit()?.getTransportStats() ?? emptyStats();
|
|
2144
|
+
} catch {
|
|
2145
|
+
return emptyStats();
|
|
2146
|
+
}
|
|
2147
|
+
},
|
|
1494
2148
|
destroy() {
|
|
1495
2149
|
instance?.destroy();
|
|
1496
2150
|
instance = null;
|
|
@@ -1500,6 +2154,14 @@ var AllStak = {
|
|
|
1500
2154
|
return instance;
|
|
1501
2155
|
}
|
|
1502
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
|
+
}
|
|
1503
2165
|
|
|
1504
2166
|
// src/provider.tsx
|
|
1505
2167
|
var React = __toESM(require("react"));
|
|
@@ -1859,7 +2521,7 @@ function installReactNative(options = {}) {
|
|
|
1859
2521
|
}
|
|
1860
2522
|
AllStak.setIdentity({
|
|
1861
2523
|
sdkName: "allstak-react-native",
|
|
1862
|
-
sdkVersion:
|
|
2524
|
+
sdkVersion: SDK_VERSION,
|
|
1863
2525
|
platform: "react-native",
|
|
1864
2526
|
dist
|
|
1865
2527
|
});
|