@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.mjs
CHANGED
|
@@ -3,28 +3,57 @@ import {
|
|
|
3
3
|
} from "./chunk-BJTO5JO5.mjs";
|
|
4
4
|
|
|
5
5
|
// src/transport.ts
|
|
6
|
-
var REQUEST_TIMEOUT =
|
|
6
|
+
var REQUEST_TIMEOUT = 2e3;
|
|
7
7
|
var MAX_BUFFER = 100;
|
|
8
|
+
var FAILURE_THRESHOLD = 3;
|
|
9
|
+
var BACKOFF_BASE_MS = 500;
|
|
10
|
+
var BACKOFF_MAX_MS = 3e4;
|
|
8
11
|
var HttpTransport = class {
|
|
9
|
-
constructor(baseUrl, apiKey) {
|
|
12
|
+
constructor(baseUrl, apiKey, enabled = true) {
|
|
10
13
|
this.baseUrl = baseUrl;
|
|
11
14
|
this.apiKey = apiKey;
|
|
15
|
+
this.enabled = enabled;
|
|
12
16
|
this.buffer = [];
|
|
13
17
|
this.flushing = false;
|
|
18
|
+
this.consecutiveFailures = 0;
|
|
19
|
+
this.circuitOpenUntil = 0;
|
|
20
|
+
this.sent = 0;
|
|
21
|
+
this.failed = 0;
|
|
22
|
+
this.dropped = 0;
|
|
23
|
+
}
|
|
24
|
+
send(path, payload) {
|
|
25
|
+
if (!this.enabled) {
|
|
26
|
+
this.noteDropped();
|
|
27
|
+
return Promise.resolve();
|
|
28
|
+
}
|
|
29
|
+
this.enqueueOrDispatch({ path, payload });
|
|
30
|
+
return Promise.resolve();
|
|
31
|
+
}
|
|
32
|
+
enqueueOrDispatch(item) {
|
|
33
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
34
|
+
this.push(item);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
void this.dispatch(item).catch(() => void 0);
|
|
14
38
|
}
|
|
15
|
-
async
|
|
39
|
+
async dispatch(item) {
|
|
16
40
|
try {
|
|
17
|
-
await this.doFetch(path, payload);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
41
|
+
await this.doFetch(item.path, item.payload);
|
|
42
|
+
this.sent++;
|
|
43
|
+
this.consecutiveFailures = 0;
|
|
44
|
+
this.circuitOpenUntil = 0;
|
|
45
|
+
this.scheduleFlush();
|
|
46
|
+
} catch (err) {
|
|
47
|
+
this.failed++;
|
|
48
|
+
this.recordFailure(err);
|
|
49
|
+
this.push(item);
|
|
22
50
|
}
|
|
23
51
|
}
|
|
24
52
|
async doFetch(path, payload) {
|
|
25
53
|
const url = `${this.baseUrl}${path}`;
|
|
26
54
|
const controller = new AbortController();
|
|
27
55
|
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
56
|
+
const started = Date.now();
|
|
28
57
|
try {
|
|
29
58
|
const res = await fetch(url, {
|
|
30
59
|
method: "POST",
|
|
@@ -38,26 +67,77 @@ var HttpTransport = class {
|
|
|
38
67
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
39
68
|
} finally {
|
|
40
69
|
clearTimeout(timeoutId);
|
|
70
|
+
this.lastTransportLatencyMs = Date.now() - started;
|
|
41
71
|
}
|
|
42
72
|
}
|
|
73
|
+
push(item) {
|
|
74
|
+
if (this.buffer.length >= MAX_BUFFER) {
|
|
75
|
+
this.buffer.shift();
|
|
76
|
+
this.dropped++;
|
|
77
|
+
}
|
|
78
|
+
this.buffer.push(item);
|
|
79
|
+
}
|
|
80
|
+
scheduleFlush() {
|
|
81
|
+
if (this.flushing || this.buffer.length === 0) return;
|
|
82
|
+
const delay = Math.max(0, this.circuitOpenUntil - Date.now());
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
void this.flushBuffer().catch(() => void 0);
|
|
85
|
+
}, delay);
|
|
86
|
+
if (typeof timer === "object" && typeof timer.unref === "function") timer.unref();
|
|
87
|
+
}
|
|
43
88
|
async flushBuffer() {
|
|
44
89
|
if (this.flushing || this.buffer.length === 0) return;
|
|
45
90
|
this.flushing = true;
|
|
91
|
+
const started = Date.now();
|
|
46
92
|
try {
|
|
47
93
|
const items = this.buffer.splice(0, this.buffer.length);
|
|
48
94
|
for (const item of items) {
|
|
95
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
96
|
+
this.push(item);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
49
99
|
try {
|
|
50
100
|
await this.doFetch(item.path, item.payload);
|
|
51
|
-
|
|
101
|
+
this.sent++;
|
|
102
|
+
this.consecutiveFailures = 0;
|
|
103
|
+
this.circuitOpenUntil = 0;
|
|
104
|
+
} catch (err) {
|
|
105
|
+
this.failed++;
|
|
106
|
+
this.recordFailure(err);
|
|
107
|
+
this.push(item);
|
|
52
108
|
}
|
|
53
109
|
}
|
|
54
110
|
} finally {
|
|
111
|
+
this.lastFlushDurationMs = Date.now() - started;
|
|
55
112
|
this.flushing = false;
|
|
113
|
+
if (this.buffer.length > 0) this.scheduleFlush();
|
|
56
114
|
}
|
|
57
115
|
}
|
|
116
|
+
recordFailure(error) {
|
|
117
|
+
this.consecutiveFailures++;
|
|
118
|
+
if (this.consecutiveFailures < FAILURE_THRESHOLD) return;
|
|
119
|
+
const retryAfterMs = retryAfterFromError(error);
|
|
120
|
+
const backoff = retryAfterMs ?? jitteredBackoff(this.consecutiveFailures);
|
|
121
|
+
this.circuitOpenUntil = Date.now() + backoff;
|
|
122
|
+
}
|
|
58
123
|
getBufferSize() {
|
|
59
124
|
return this.buffer.length;
|
|
60
125
|
}
|
|
126
|
+
noteDropped(count = 1) {
|
|
127
|
+
this.dropped += Math.max(0, count);
|
|
128
|
+
}
|
|
129
|
+
getStats() {
|
|
130
|
+
return {
|
|
131
|
+
queued: this.buffer.length,
|
|
132
|
+
sent: this.sent,
|
|
133
|
+
failed: this.failed,
|
|
134
|
+
dropped: this.dropped,
|
|
135
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
136
|
+
circuitOpenUntil: this.circuitOpenUntil,
|
|
137
|
+
lastTransportLatencyMs: this.lastTransportLatencyMs,
|
|
138
|
+
lastFlushDurationMs: this.lastFlushDurationMs
|
|
139
|
+
};
|
|
140
|
+
}
|
|
61
141
|
/**
|
|
62
142
|
* Wait for the in-flight retry-buffer to drain. Resolves `true` if the
|
|
63
143
|
* buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
|
|
@@ -74,6 +154,14 @@ var HttpTransport = class {
|
|
|
74
154
|
return true;
|
|
75
155
|
}
|
|
76
156
|
};
|
|
157
|
+
function jitteredBackoff(failures) {
|
|
158
|
+
const exp = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** Math.min(8, failures - FAILURE_THRESHOLD));
|
|
159
|
+
return Math.floor(exp / 2 + Math.random() * (exp / 2));
|
|
160
|
+
}
|
|
161
|
+
function retryAfterFromError(error) {
|
|
162
|
+
const message = error instanceof Error ? error.message : "";
|
|
163
|
+
return /HTTP\s+(429|503)/.test(message) ? BACKOFF_MAX_MS : null;
|
|
164
|
+
}
|
|
77
165
|
|
|
78
166
|
// src/stack.ts
|
|
79
167
|
var V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?((?:.+?):(\d+):(\d+))\)?\s*$/;
|
|
@@ -128,6 +216,24 @@ function isInApp(filename) {
|
|
|
128
216
|
return true;
|
|
129
217
|
}
|
|
130
218
|
|
|
219
|
+
// src/utils/debug-id.ts
|
|
220
|
+
var REGISTRY_KEY = "_allstakDebugIds";
|
|
221
|
+
var cache = /* @__PURE__ */ new Map();
|
|
222
|
+
function resolveDebugId(filename) {
|
|
223
|
+
if (!filename) return void 0;
|
|
224
|
+
if (cache.has(filename)) return cache.get(filename) ?? void 0;
|
|
225
|
+
const registry = globalThis[REGISTRY_KEY];
|
|
226
|
+
if (registry && typeof registry === "object") {
|
|
227
|
+
const hit = registry[filename];
|
|
228
|
+
if (typeof hit === "string" && hit.length > 0) {
|
|
229
|
+
cache.set(filename, hit);
|
|
230
|
+
return hit;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
cache.set(filename, null);
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
|
|
131
237
|
// src/scope.ts
|
|
132
238
|
var Scope = class {
|
|
133
239
|
constructor() {
|
|
@@ -339,6 +445,7 @@ var TracingModule = class {
|
|
|
339
445
|
}
|
|
340
446
|
if (!this.flushTimer) {
|
|
341
447
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
|
|
448
|
+
this.flushTimer?.unref?.();
|
|
342
449
|
}
|
|
343
450
|
}
|
|
344
451
|
flush() {
|
|
@@ -384,10 +491,11 @@ var ReplaySurrogate = class {
|
|
|
384
491
|
if (Math.random() >= this.opts.sampleRate) return false;
|
|
385
492
|
this.active = true;
|
|
386
493
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS2);
|
|
494
|
+
this.flushTimer?.unref?.();
|
|
387
495
|
return true;
|
|
388
496
|
}
|
|
389
497
|
/** Record a screen view. Filters params through the safeParams allow-list. */
|
|
390
|
-
recordScreenView(routeName, params) {
|
|
498
|
+
recordScreenView(routeName, params, context) {
|
|
391
499
|
if (!this.active) return;
|
|
392
500
|
const safe = {};
|
|
393
501
|
if (params && this.opts.safeParams.length > 0) {
|
|
@@ -395,17 +503,22 @@ var ReplaySurrogate = class {
|
|
|
395
503
|
if (key in params) safe[key] = params[key];
|
|
396
504
|
}
|
|
397
505
|
}
|
|
398
|
-
this.push({ ts: Date.now(), k: "screen", data: { route: routeName, params: safe } });
|
|
506
|
+
this.push({ ts: Date.now(), k: "screen", data: { route: routeName, params: safe, ...compact(context) } });
|
|
399
507
|
}
|
|
400
508
|
/** Record an AppState transition (foreground/background/inactive). */
|
|
401
|
-
recordAppState(next) {
|
|
509
|
+
recordAppState(next, context) {
|
|
402
510
|
if (!this.active) return;
|
|
403
|
-
this.push({ ts: Date.now(), k: "appstate", data: { state: next } });
|
|
511
|
+
this.push({ ts: Date.now(), k: "appstate", data: { state: next, ...compact(context) } });
|
|
404
512
|
}
|
|
405
513
|
/** Record a free-form, customer-validated checkpoint. */
|
|
406
|
-
recordManual(label, data) {
|
|
514
|
+
recordManual(label, data, context) {
|
|
515
|
+
if (!this.active) return;
|
|
516
|
+
this.push({ ts: Date.now(), k: "manual", data: { label, ...data ?? {}, ...compact(context) } });
|
|
517
|
+
}
|
|
518
|
+
/** Record a forensic mobile session timeline marker. This is not replay. */
|
|
519
|
+
recordTimelineMarker(kind, label, data, context) {
|
|
407
520
|
if (!this.active) return;
|
|
408
|
-
this.push({ ts: Date.now(), k:
|
|
521
|
+
this.push({ ts: Date.now(), k: kind, data: { label, ...data ?? {}, ...compact(context) } });
|
|
409
522
|
}
|
|
410
523
|
destroy() {
|
|
411
524
|
this.destroyed = true;
|
|
@@ -439,6 +552,14 @@ var ReplaySurrogate = class {
|
|
|
439
552
|
});
|
|
440
553
|
}
|
|
441
554
|
};
|
|
555
|
+
function compact(context) {
|
|
556
|
+
if (!context) return {};
|
|
557
|
+
const out = {};
|
|
558
|
+
for (const [key, value] of Object.entries(context)) {
|
|
559
|
+
if (value !== void 0 && value !== null && value !== "") out[key] = value;
|
|
560
|
+
}
|
|
561
|
+
return out;
|
|
562
|
+
}
|
|
442
563
|
|
|
443
564
|
// src/http-requests.ts
|
|
444
565
|
var INGEST_PATH = "/ingest/v1/http-requests";
|
|
@@ -450,6 +571,12 @@ function genTraceId() {
|
|
|
450
571
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
451
572
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
452
573
|
}
|
|
574
|
+
function genRequestId() {
|
|
575
|
+
return genTraceId();
|
|
576
|
+
}
|
|
577
|
+
function generateHttpId() {
|
|
578
|
+
return genTraceId();
|
|
579
|
+
}
|
|
453
580
|
function splitHostPath(url) {
|
|
454
581
|
try {
|
|
455
582
|
const u = new URL(url);
|
|
@@ -476,6 +603,7 @@ var HttpRequestModule = class {
|
|
|
476
603
|
const item = {
|
|
477
604
|
type: "http_request",
|
|
478
605
|
traceId: ev.traceId ?? genTraceId(),
|
|
606
|
+
requestId: ev.requestId ?? genRequestId(),
|
|
479
607
|
direction: "outbound",
|
|
480
608
|
method: (ev.method || "GET").toUpperCase(),
|
|
481
609
|
host,
|
|
@@ -490,6 +618,16 @@ var HttpRequestModule = class {
|
|
|
490
618
|
requestHeaders: ev.requestHeaders,
|
|
491
619
|
responseHeaders: ev.responseHeaders,
|
|
492
620
|
error: ev.error,
|
|
621
|
+
spanId: ev.spanId,
|
|
622
|
+
parentSpanId: ev.parentSpanId,
|
|
623
|
+
requestBodyStatus: ev.requestBodyStatus,
|
|
624
|
+
responseBodyStatus: ev.responseBodyStatus,
|
|
625
|
+
requestBodyRedactedFields: ev.requestBodyRedactedFields,
|
|
626
|
+
responseBodyRedactedFields: ev.responseBodyRedactedFields,
|
|
627
|
+
requestBodyTruncated: ev.requestBodyTruncated,
|
|
628
|
+
responseBodyTruncated: ev.responseBodyTruncated,
|
|
629
|
+
capturePolicy: ev.capturePolicy,
|
|
630
|
+
linkConfidence: ev.linkConfidence ?? "exact",
|
|
493
631
|
environment: this.defaults.environment,
|
|
494
632
|
release: this.defaults.release,
|
|
495
633
|
dist: this.defaults.dist,
|
|
@@ -508,7 +646,10 @@ var HttpRequestModule = class {
|
|
|
508
646
|
this.flush();
|
|
509
647
|
return;
|
|
510
648
|
}
|
|
511
|
-
if (!this.flushTimer)
|
|
649
|
+
if (!this.flushTimer) {
|
|
650
|
+
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS3);
|
|
651
|
+
this.flushTimer?.unref?.();
|
|
652
|
+
}
|
|
512
653
|
}
|
|
513
654
|
/** Snapshot of the last failed requests for error-linking. Newest last. */
|
|
514
655
|
getRecentFailed() {
|
|
@@ -560,6 +701,24 @@ var ALWAYS_REDACT_QUERY = /* @__PURE__ */ new Set([
|
|
|
560
701
|
"jwt"
|
|
561
702
|
]);
|
|
562
703
|
var REDACTED = "[REDACTED]";
|
|
704
|
+
var DEFAULT_REDACT_BODY_FIELDS = [
|
|
705
|
+
"password",
|
|
706
|
+
"passcode",
|
|
707
|
+
"otp",
|
|
708
|
+
"token",
|
|
709
|
+
"authorization",
|
|
710
|
+
"cookie",
|
|
711
|
+
"session",
|
|
712
|
+
"refresh_token",
|
|
713
|
+
"access_token",
|
|
714
|
+
"jwt",
|
|
715
|
+
"card",
|
|
716
|
+
"credit_card",
|
|
717
|
+
"iban",
|
|
718
|
+
"national_id",
|
|
719
|
+
"secret",
|
|
720
|
+
"api_key"
|
|
721
|
+
];
|
|
563
722
|
function shouldCaptureUrl(url, opts) {
|
|
564
723
|
if (!url) return false;
|
|
565
724
|
const lower = url.toLowerCase();
|
|
@@ -627,25 +786,125 @@ function sanitizeHeaders(headers, opts) {
|
|
|
627
786
|
}
|
|
628
787
|
return out;
|
|
629
788
|
}
|
|
630
|
-
function
|
|
631
|
-
if (!enabled)
|
|
632
|
-
|
|
789
|
+
function captureBodyResult(body, enabled, maxBodyBytes, opts = {}, contentType) {
|
|
790
|
+
if (!enabled) {
|
|
791
|
+
return {
|
|
792
|
+
status: "disabled",
|
|
793
|
+
redactedFields: [],
|
|
794
|
+
truncated: false,
|
|
795
|
+
capturePolicy: "body_capture_disabled"
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
if (body == null) {
|
|
799
|
+
return {
|
|
800
|
+
status: "empty",
|
|
801
|
+
redactedFields: [],
|
|
802
|
+
truncated: false,
|
|
803
|
+
capturePolicy: "empty_body"
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const allowed = opts.allowedContentTypes ?? ["application/json", "text/", "application/problem+json"];
|
|
807
|
+
if (contentType && !allowed.some((needle) => contentType.toLowerCase().includes(needle.toLowerCase()))) {
|
|
808
|
+
return {
|
|
809
|
+
status: "unsupported",
|
|
810
|
+
redactedFields: [],
|
|
811
|
+
truncated: false,
|
|
812
|
+
capturePolicy: `unsupported_content_type:${contentType}`
|
|
813
|
+
};
|
|
814
|
+
}
|
|
633
815
|
let str;
|
|
816
|
+
let redactedFields = [];
|
|
634
817
|
if (typeof body === "string") str = body;
|
|
635
818
|
else if (typeof body === "number" || typeof body === "boolean") str = String(body);
|
|
636
819
|
else if (typeof body === "object") {
|
|
637
820
|
const tag = Object.prototype.toString.call(body);
|
|
638
|
-
if (tag !== "[object Object]" && tag !== "[object Array]")
|
|
821
|
+
if (tag !== "[object Object]" && tag !== "[object Array]") {
|
|
822
|
+
return {
|
|
823
|
+
body: "<binary>",
|
|
824
|
+
status: "unsupported",
|
|
825
|
+
redactedFields: [],
|
|
826
|
+
truncated: false,
|
|
827
|
+
capturePolicy: "unsupported_binary_body"
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
const redacted = redactJsonValue(body, opts);
|
|
831
|
+
redactedFields = redacted.redactedFields;
|
|
639
832
|
try {
|
|
640
|
-
str = JSON.stringify(
|
|
833
|
+
str = JSON.stringify(redacted.value);
|
|
641
834
|
} catch {
|
|
642
|
-
return
|
|
835
|
+
return {
|
|
836
|
+
body: "<unserializable>",
|
|
837
|
+
status: "unsupported",
|
|
838
|
+
redactedFields,
|
|
839
|
+
truncated: false,
|
|
840
|
+
capturePolicy: "unserializable_body"
|
|
841
|
+
};
|
|
643
842
|
}
|
|
644
843
|
} else {
|
|
645
|
-
return
|
|
844
|
+
return {
|
|
845
|
+
body: "<binary>",
|
|
846
|
+
status: "unsupported",
|
|
847
|
+
redactedFields: [],
|
|
848
|
+
truncated: false,
|
|
849
|
+
capturePolicy: "unsupported_body_type"
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
if (typeof body === "string" && looksJson(contentType, str)) {
|
|
853
|
+
try {
|
|
854
|
+
const redacted = redactJsonValue(JSON.parse(str), opts);
|
|
855
|
+
redactedFields = redacted.redactedFields;
|
|
856
|
+
str = JSON.stringify(redacted.value);
|
|
857
|
+
} catch {
|
|
858
|
+
str = redactSensitiveText(str, opts);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
let truncated = false;
|
|
862
|
+
if (str.length > maxBodyBytes) {
|
|
863
|
+
str = str.slice(0, maxBodyBytes) + "\u2026[truncated]";
|
|
864
|
+
truncated = true;
|
|
646
865
|
}
|
|
647
|
-
|
|
648
|
-
|
|
866
|
+
return {
|
|
867
|
+
body: str,
|
|
868
|
+
status: truncated ? "truncated" : redactedFields.length > 0 ? "redacted" : "captured",
|
|
869
|
+
redactedFields: Array.from(new Set(redactedFields)).sort(),
|
|
870
|
+
truncated,
|
|
871
|
+
capturePolicy: "opt_in_body_capture"
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
function looksJson(contentType, body) {
|
|
875
|
+
if (contentType && contentType.toLowerCase().includes("json")) return true;
|
|
876
|
+
const trimmed = body.trim();
|
|
877
|
+
return trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
878
|
+
}
|
|
879
|
+
function redactJsonValue(value, opts, path = "") {
|
|
880
|
+
const fieldSet = new Set([...DEFAULT_REDACT_BODY_FIELDS, ...opts.redactBodyFields ?? []].map((v) => v.toLowerCase()));
|
|
881
|
+
const redactedFields = [];
|
|
882
|
+
const walk = (input, currentPath) => {
|
|
883
|
+
if (Array.isArray(input)) return input.map((item, index) => walk(item, `${currentPath}[${index}]`));
|
|
884
|
+
if (!input || typeof input !== "object") return input;
|
|
885
|
+
const out = {};
|
|
886
|
+
for (const [key, raw] of Object.entries(input)) {
|
|
887
|
+
const keyLower = key.toLowerCase();
|
|
888
|
+
const nextPath = currentPath ? `${currentPath}.${key}` : key;
|
|
889
|
+
if (fieldSet.has(keyLower) || keyLower.includes("token") || keyLower.includes("password")) {
|
|
890
|
+
out[key] = REDACTED;
|
|
891
|
+
redactedFields.push(nextPath);
|
|
892
|
+
} else {
|
|
893
|
+
out[key] = walk(raw, nextPath);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return out;
|
|
897
|
+
};
|
|
898
|
+
return { value: walk(value, path), redactedFields };
|
|
899
|
+
}
|
|
900
|
+
function redactSensitiveText(input, opts) {
|
|
901
|
+
const fields = [...DEFAULT_REDACT_BODY_FIELDS, ...opts.redactBodyFields ?? []];
|
|
902
|
+
let out = input;
|
|
903
|
+
for (const key of fields) {
|
|
904
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
905
|
+
out = out.replace(new RegExp(`("${escaped}"\\s*:\\s*)"[^"]*"`, "gi"), `$1"${REDACTED}"`);
|
|
906
|
+
}
|
|
907
|
+
return out;
|
|
649
908
|
}
|
|
650
909
|
|
|
651
910
|
// src/http-instrumentation.ts
|
|
@@ -655,12 +914,16 @@ var AXIOS_FLAG = /* @__PURE__ */ Symbol.for("allstak.http.axios.instrumented");
|
|
|
655
914
|
var DEFAULT_MAX_BODY = 4096;
|
|
656
915
|
var _currentModule = null;
|
|
657
916
|
var _currentOpts = null;
|
|
917
|
+
var _currentRuntime = null;
|
|
658
918
|
function currentModule() {
|
|
659
919
|
return _currentModule;
|
|
660
920
|
}
|
|
661
921
|
function currentOpts() {
|
|
662
922
|
return _currentOpts;
|
|
663
923
|
}
|
|
924
|
+
function currentRuntime() {
|
|
925
|
+
return _currentRuntime;
|
|
926
|
+
}
|
|
664
927
|
function safeCapture(ev) {
|
|
665
928
|
try {
|
|
666
929
|
currentModule()?.capture(ev);
|
|
@@ -677,6 +940,8 @@ function bind(opts, ownIngestHost) {
|
|
|
677
940
|
ignoredUrls: opts.ignoredUrls ?? [],
|
|
678
941
|
allowedUrls: opts.allowedUrls ?? [],
|
|
679
942
|
maxBodyBytes: opts.maxBodyBytes ?? DEFAULT_MAX_BODY,
|
|
943
|
+
allowedContentTypes: opts.allowedContentTypes ?? ["application/json", "text/", "application/problem+json"],
|
|
944
|
+
redactBodyFields: opts.redactBodyFields ?? [],
|
|
680
945
|
ownIngestPrefix: ownIngestHost.replace(/\/$/, "")
|
|
681
946
|
};
|
|
682
947
|
}
|
|
@@ -723,6 +988,77 @@ function headersToObject(h) {
|
|
|
723
988
|
}
|
|
724
989
|
return {};
|
|
725
990
|
}
|
|
991
|
+
function normalizeTraceId(traceId) {
|
|
992
|
+
const hex = traceId.replace(/[^a-fA-F0-9]/g, "").toLowerCase();
|
|
993
|
+
return (hex + "00000000000000000000000000000000").slice(0, 32);
|
|
994
|
+
}
|
|
995
|
+
function normalizeSpanId(spanId) {
|
|
996
|
+
const hex = spanId.replace(/[^a-fA-F0-9]/g, "").toLowerCase();
|
|
997
|
+
return (hex + "0000000000000000").slice(0, 16);
|
|
998
|
+
}
|
|
999
|
+
function createRequestContext(method, url) {
|
|
1000
|
+
const runtime = currentRuntime();
|
|
1001
|
+
if (!runtime) return null;
|
|
1002
|
+
const requestId = generateHttpId();
|
|
1003
|
+
const parentSpanId = runtime.tracing.getCurrentSpanId() ?? "";
|
|
1004
|
+
const span = runtime.tracing.startSpan("mobile.http", {
|
|
1005
|
+
description: `${method.toUpperCase()} ${url}`,
|
|
1006
|
+
tags: { requestId, method: method.toUpperCase(), platform: runtime.platform ?? "react-native" }
|
|
1007
|
+
});
|
|
1008
|
+
const traceId = runtime.tracing.getTraceId();
|
|
1009
|
+
const spanId = span.spanId;
|
|
1010
|
+
return {
|
|
1011
|
+
traceId,
|
|
1012
|
+
requestId,
|
|
1013
|
+
spanId,
|
|
1014
|
+
parentSpanId,
|
|
1015
|
+
traceparent: `00-${normalizeTraceId(traceId)}-${normalizeSpanId(spanId)}-01`,
|
|
1016
|
+
span
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function propagationHeaders(ctx) {
|
|
1020
|
+
const headers = {
|
|
1021
|
+
traceparent: ctx.traceparent,
|
|
1022
|
+
"x-allstak-trace-id": ctx.traceId,
|
|
1023
|
+
"x-allstak-request-id": ctx.requestId
|
|
1024
|
+
};
|
|
1025
|
+
if (ctx.parentSpanId) headers["x-allstak-parent-span-id"] = ctx.parentSpanId;
|
|
1026
|
+
return headers;
|
|
1027
|
+
}
|
|
1028
|
+
function mergeHeaders(headers, propagation) {
|
|
1029
|
+
const entries = Object.entries(propagation);
|
|
1030
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
1031
|
+
const next2 = new Headers(headers);
|
|
1032
|
+
for (const [k, v] of entries) if (!next2.has(k)) next2.set(k, v);
|
|
1033
|
+
return next2;
|
|
1034
|
+
}
|
|
1035
|
+
if (Array.isArray(headers)) {
|
|
1036
|
+
const existing = new Set(headers.map(([k]) => String(k).toLowerCase()));
|
|
1037
|
+
const next2 = [...headers];
|
|
1038
|
+
for (const [k, v] of entries) if (!existing.has(k.toLowerCase())) next2.push([k, v]);
|
|
1039
|
+
return next2;
|
|
1040
|
+
}
|
|
1041
|
+
const next = { ...headers ?? {} };
|
|
1042
|
+
const lower = new Set(Object.keys(next).map((k) => k.toLowerCase()));
|
|
1043
|
+
for (const [k, v] of entries) if (!lower.has(k.toLowerCase())) next[k] = v;
|
|
1044
|
+
return next;
|
|
1045
|
+
}
|
|
1046
|
+
function injectFetchHeaders(input, init, ctx) {
|
|
1047
|
+
const headers = mergeHeaders(init?.headers ?? (input && typeof input === "object" ? input.headers : void 0), propagationHeaders(ctx));
|
|
1048
|
+
return { input, init: { ...init ?? {}, headers } };
|
|
1049
|
+
}
|
|
1050
|
+
function recordTimeline(kind, label, ctx, data) {
|
|
1051
|
+
try {
|
|
1052
|
+
currentRuntime()?.replay?.recordTimelineMarker?.(kind, label, data, {
|
|
1053
|
+
traceId: ctx.traceId,
|
|
1054
|
+
requestId: ctx.requestId,
|
|
1055
|
+
spanId: ctx.spanId,
|
|
1056
|
+
release: currentRuntime()?.release,
|
|
1057
|
+
dist: currentRuntime()?.dist
|
|
1058
|
+
});
|
|
1059
|
+
} catch {
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
726
1062
|
function patchFetch() {
|
|
727
1063
|
const g = globalThis;
|
|
728
1064
|
if (typeof g.fetch !== "function") return;
|
|
@@ -740,23 +1076,37 @@ function patchFetch() {
|
|
|
740
1076
|
return original.call(this, input, init);
|
|
741
1077
|
}
|
|
742
1078
|
const start = Date.now();
|
|
743
|
-
const
|
|
744
|
-
const
|
|
1079
|
+
const ctx = createRequestContext(method, sanitizedUrl);
|
|
1080
|
+
const requestInit = ctx ? injectFetchHeaders(input, init, ctx).init : init;
|
|
1081
|
+
if (ctx) recordTimeline("request", "request_started", ctx, { method, url: sanitizedUrl });
|
|
1082
|
+
const reqHeaders = sanitizeHeaders(headersToObject(requestInit?.headers ?? (input && input.headers)), opts);
|
|
1083
|
+
const reqBody = captureBodyResult(requestInit?.body, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
745
1084
|
const reqSize = safeByteLength(typeof init?.body === "string" ? init.body : void 0);
|
|
746
1085
|
let response;
|
|
747
1086
|
try {
|
|
748
|
-
response = await original.call(this, input,
|
|
1087
|
+
response = await original.call(this, input, requestInit);
|
|
749
1088
|
} catch (err) {
|
|
1089
|
+
ctx?.span.finish("error");
|
|
1090
|
+
if (ctx) recordTimeline("exception", "request_failed", ctx, { method, url: sanitizedUrl, error: String(err?.message ?? err) });
|
|
750
1091
|
safeCapture({
|
|
751
1092
|
type: "http_request",
|
|
1093
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1094
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1095
|
+
spanId: ctx?.spanId,
|
|
1096
|
+
parentSpanId: ctx?.parentSpanId,
|
|
752
1097
|
method,
|
|
753
1098
|
url: sanitizedUrl,
|
|
754
1099
|
statusCode: 0,
|
|
755
1100
|
durationMs: Date.now() - start,
|
|
756
|
-
requestBody: reqBody,
|
|
1101
|
+
requestBody: reqBody.body,
|
|
757
1102
|
requestHeaders: reqHeaders,
|
|
758
1103
|
requestSize: reqSize,
|
|
759
|
-
|
|
1104
|
+
requestBodyStatus: reqBody.status,
|
|
1105
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1106
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1107
|
+
capturePolicy: reqBody.capturePolicy,
|
|
1108
|
+
error: String(err?.message ?? err),
|
|
1109
|
+
linkConfidence: "exact"
|
|
760
1110
|
});
|
|
761
1111
|
throw err;
|
|
762
1112
|
}
|
|
@@ -772,25 +1122,41 @@ function patchFetch() {
|
|
|
772
1122
|
try {
|
|
773
1123
|
const cloned = response.clone();
|
|
774
1124
|
const text = await cloned.text();
|
|
775
|
-
respBody =
|
|
1125
|
+
respBody = captureBodyResult(text, true, opts.maxBodyBytes, opts, respHeaders?.["content-type"]).body;
|
|
776
1126
|
if (respSize == null) respSize = safeByteLength(text);
|
|
777
1127
|
} catch {
|
|
778
1128
|
}
|
|
779
1129
|
}
|
|
780
1130
|
} catch {
|
|
781
1131
|
}
|
|
1132
|
+
const respBodyResult = captureBodyResult(respBody, opts.captureResponseBody && respBody !== void 0, opts.maxBodyBytes, opts, respHeaders?.["content-type"]);
|
|
1133
|
+
const isError = response.status >= 400;
|
|
1134
|
+
ctx?.span.setTag("requestId", ctx.requestId).setTag("http.status_code", String(response.status)).finish(isError ? "error" : "ok");
|
|
1135
|
+
if (ctx) recordTimeline(isError ? "exception" : "response", isError ? "request_failed" : "response_received", ctx, { statusCode: response.status, durationMs });
|
|
782
1136
|
safeCapture({
|
|
783
1137
|
type: "http_request",
|
|
1138
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1139
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1140
|
+
spanId: ctx?.spanId,
|
|
1141
|
+
parentSpanId: ctx?.parentSpanId,
|
|
784
1142
|
method,
|
|
785
1143
|
url: sanitizedUrl,
|
|
786
1144
|
statusCode: response.status,
|
|
787
1145
|
durationMs,
|
|
788
|
-
requestBody: reqBody,
|
|
1146
|
+
requestBody: reqBody.body,
|
|
789
1147
|
requestHeaders: reqHeaders,
|
|
790
1148
|
requestSize: reqSize,
|
|
791
|
-
responseBody:
|
|
1149
|
+
responseBody: respBodyResult.body,
|
|
792
1150
|
responseHeaders: respHeaders,
|
|
793
|
-
responseSize: respSize
|
|
1151
|
+
responseSize: respSize,
|
|
1152
|
+
requestBodyStatus: reqBody.status,
|
|
1153
|
+
responseBodyStatus: respBodyResult.status,
|
|
1154
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1155
|
+
responseBodyRedactedFields: respBodyResult.redactedFields,
|
|
1156
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1157
|
+
responseBodyTruncated: respBodyResult.truncated,
|
|
1158
|
+
capturePolicy: `${reqBody.capturePolicy};${respBodyResult.capturePolicy}`,
|
|
1159
|
+
linkConfidence: "exact"
|
|
794
1160
|
});
|
|
795
1161
|
return response;
|
|
796
1162
|
};
|
|
@@ -828,7 +1194,17 @@ function patchXhr() {
|
|
|
828
1194
|
return origSend.call(this, body);
|
|
829
1195
|
}
|
|
830
1196
|
const reqHeaders = sanitizeHeaders(this.__allstak_headers__, opts);
|
|
831
|
-
const
|
|
1197
|
+
const ctx = createRequestContext(method, sanitizedUrl);
|
|
1198
|
+
if (ctx) {
|
|
1199
|
+
for (const [k, v] of Object.entries(propagationHeaders(ctx))) {
|
|
1200
|
+
try {
|
|
1201
|
+
origSetRequestHeader.call(this, k, v);
|
|
1202
|
+
} catch {
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
recordTimeline("request", "request_started", ctx, { method, url: sanitizedUrl });
|
|
1206
|
+
}
|
|
1207
|
+
const reqBody = captureBodyResult(body, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
832
1208
|
const reqSize = safeByteLength(typeof body === "string" ? body : void 0);
|
|
833
1209
|
const finish = (statusCode, error) => {
|
|
834
1210
|
const durationMs = Date.now() - start;
|
|
@@ -846,28 +1222,43 @@ function patchXhr() {
|
|
|
846
1222
|
}
|
|
847
1223
|
respHeaders = sanitizeHeaders(dict, liveOpts);
|
|
848
1224
|
}
|
|
1225
|
+
let respBodyResult = captureBodyResult(void 0, false, liveOpts.maxBodyBytes, liveOpts);
|
|
849
1226
|
if (liveOpts.captureResponseBody) {
|
|
850
1227
|
const text = this.responseText;
|
|
851
1228
|
if (typeof text === "string") {
|
|
852
|
-
|
|
1229
|
+
respBodyResult = captureBodyResult(text, true, liveOpts.maxBodyBytes, liveOpts, respHeaders?.["content-type"]);
|
|
1230
|
+
respBody = respBodyResult.body;
|
|
853
1231
|
respSize = safeByteLength(text);
|
|
854
1232
|
}
|
|
855
1233
|
}
|
|
856
1234
|
} catch {
|
|
857
1235
|
}
|
|
1236
|
+
const failed = !!error || statusCode >= 400;
|
|
1237
|
+
ctx?.span.setTag("requestId", ctx.requestId).setTag("http.status_code", String(statusCode)).finish(failed ? "error" : "ok");
|
|
1238
|
+
if (ctx) recordTimeline(failed ? "exception" : "response", failed ? "request_failed" : "response_received", ctx, { statusCode, durationMs, error });
|
|
858
1239
|
safeCapture({
|
|
859
1240
|
type: "http_request",
|
|
1241
|
+
traceId: ctx?.traceId ?? generateHttpId(),
|
|
1242
|
+
requestId: ctx?.requestId ?? generateHttpId(),
|
|
1243
|
+
spanId: ctx?.spanId,
|
|
1244
|
+
parentSpanId: ctx?.parentSpanId,
|
|
860
1245
|
method,
|
|
861
1246
|
url: sanitizedUrl,
|
|
862
1247
|
statusCode,
|
|
863
1248
|
durationMs,
|
|
864
|
-
requestBody: reqBody,
|
|
1249
|
+
requestBody: reqBody.body,
|
|
865
1250
|
requestHeaders: reqHeaders,
|
|
866
1251
|
requestSize: reqSize,
|
|
867
1252
|
responseBody: respBody,
|
|
868
1253
|
responseHeaders: respHeaders,
|
|
869
1254
|
responseSize: respSize,
|
|
870
|
-
|
|
1255
|
+
requestBodyStatus: reqBody.status,
|
|
1256
|
+
responseBodyStatus: respBody ? "captured" : opts.captureResponseBody ? "empty" : "disabled",
|
|
1257
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1258
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1259
|
+
capturePolicy: reqBody.capturePolicy,
|
|
1260
|
+
error,
|
|
1261
|
+
linkConfidence: "exact"
|
|
871
1262
|
});
|
|
872
1263
|
};
|
|
873
1264
|
this.addEventListener?.("load", () => finish(this.status || 0));
|
|
@@ -886,10 +1277,17 @@ function instrumentAxiosInstance(axiosInstance, module, opts) {
|
|
|
886
1277
|
axiosInstance.interceptors.request.use((config) => {
|
|
887
1278
|
try {
|
|
888
1279
|
const rawUrl = (config.baseURL ? config.baseURL.replace(/\/$/, "") : "") + (config.url || "");
|
|
1280
|
+
const method = String(config.method || "GET").toUpperCase();
|
|
1281
|
+
const ctx = createRequestContext(method, rawUrl);
|
|
1282
|
+
if (ctx) {
|
|
1283
|
+
config.headers = mergeHeaders(config.headers, propagationHeaders(ctx));
|
|
1284
|
+
recordTimeline("request", "request_started", ctx, { method, url: rawUrl });
|
|
1285
|
+
}
|
|
889
1286
|
reqStarts.set(config, {
|
|
890
1287
|
start: Date.now(),
|
|
891
|
-
method
|
|
892
|
-
rawUrl
|
|
1288
|
+
method,
|
|
1289
|
+
rawUrl,
|
|
1290
|
+
ctx
|
|
893
1291
|
});
|
|
894
1292
|
} catch {
|
|
895
1293
|
}
|
|
@@ -903,21 +1301,36 @@ function instrumentAxiosInstance(axiosInstance, module, opts) {
|
|
|
903
1301
|
if (!shouldCaptureUrl(meta.rawUrl, opts)) return;
|
|
904
1302
|
const sanitizedUrl = redactUrl(meta.rawUrl, opts);
|
|
905
1303
|
const reqHeaders = sanitizeHeaders(headersToObject(cfg.headers), opts);
|
|
906
|
-
const reqBody =
|
|
1304
|
+
const reqBody = captureBodyResult(cfg.data, opts.captureRequestBody, opts.maxBodyBytes, opts, reqHeaders?.["content-type"]);
|
|
907
1305
|
const respHeaders = sanitizeHeaders(headersToObject(response?.headers), opts);
|
|
908
|
-
const respBody =
|
|
1306
|
+
const respBody = captureBodyResult(response?.data, opts.captureResponseBody, opts.maxBodyBytes, opts, respHeaders?.["content-type"]);
|
|
1307
|
+
const failed = !!error || statusCode >= 400;
|
|
1308
|
+
meta.ctx?.span.setTag("requestId", meta.ctx.requestId).setTag("http.status_code", String(statusCode)).finish(failed ? "error" : "ok");
|
|
1309
|
+
if (meta.ctx) recordTimeline(failed ? "exception" : "response", failed ? "request_failed" : "response_received", meta.ctx, { statusCode, error });
|
|
909
1310
|
try {
|
|
910
1311
|
module.capture({
|
|
911
1312
|
type: "http_request",
|
|
1313
|
+
traceId: meta.ctx?.traceId ?? generateHttpId(),
|
|
1314
|
+
requestId: meta.ctx?.requestId ?? generateHttpId(),
|
|
1315
|
+
spanId: meta.ctx?.spanId,
|
|
1316
|
+
parentSpanId: meta.ctx?.parentSpanId,
|
|
912
1317
|
method: meta.method,
|
|
913
1318
|
url: sanitizedUrl,
|
|
914
1319
|
statusCode,
|
|
915
1320
|
durationMs: Date.now() - meta.start,
|
|
916
|
-
requestBody: reqBody,
|
|
1321
|
+
requestBody: reqBody.body,
|
|
917
1322
|
requestHeaders: reqHeaders,
|
|
918
|
-
responseBody: respBody,
|
|
1323
|
+
responseBody: respBody.body,
|
|
919
1324
|
responseHeaders: respHeaders,
|
|
920
|
-
|
|
1325
|
+
requestBodyStatus: reqBody.status,
|
|
1326
|
+
responseBodyStatus: respBody.status,
|
|
1327
|
+
requestBodyRedactedFields: reqBody.redactedFields,
|
|
1328
|
+
responseBodyRedactedFields: respBody.redactedFields,
|
|
1329
|
+
requestBodyTruncated: reqBody.truncated,
|
|
1330
|
+
responseBodyTruncated: respBody.truncated,
|
|
1331
|
+
capturePolicy: `${reqBody.capturePolicy};${respBody.capturePolicy}`,
|
|
1332
|
+
error,
|
|
1333
|
+
linkConfidence: "exact"
|
|
921
1334
|
});
|
|
922
1335
|
} catch {
|
|
923
1336
|
}
|
|
@@ -943,10 +1356,11 @@ function tryAutoInstrumentAxios(module, opts) {
|
|
|
943
1356
|
} catch {
|
|
944
1357
|
}
|
|
945
1358
|
}
|
|
946
|
-
function installHttpInstrumentation(module, options, ownIngestHost) {
|
|
1359
|
+
function installHttpInstrumentation(module, options, ownIngestHost, runtime) {
|
|
947
1360
|
const bound = bind(options, ownIngestHost);
|
|
948
1361
|
_currentModule = module;
|
|
949
1362
|
_currentOpts = bound;
|
|
1363
|
+
_currentRuntime = runtime;
|
|
950
1364
|
try {
|
|
951
1365
|
patchFetch();
|
|
952
1366
|
} catch {
|
|
@@ -963,11 +1377,16 @@ function installHttpInstrumentation(module, options, ownIngestHost) {
|
|
|
963
1377
|
instrumentAxios: (axios) => instrumentAxiosInstance(axios, module, bound)
|
|
964
1378
|
};
|
|
965
1379
|
}
|
|
1380
|
+
function unbindHttpInstrumentation() {
|
|
1381
|
+
_currentModule = null;
|
|
1382
|
+
_currentOpts = null;
|
|
1383
|
+
_currentRuntime = null;
|
|
1384
|
+
}
|
|
966
1385
|
|
|
967
1386
|
// src/client.ts
|
|
968
1387
|
var INGEST_HOST = "https://api.allstak.sa";
|
|
969
1388
|
var SDK_NAME = "allstak-react-native";
|
|
970
|
-
var SDK_VERSION = "0.3.
|
|
1389
|
+
var SDK_VERSION = "0.3.1";
|
|
971
1390
|
var ERRORS_PATH = "/ingest/v1/errors";
|
|
972
1391
|
var LOGS_PATH = "/ingest/v1/logs";
|
|
973
1392
|
var VALID_BREADCRUMB_TYPES = /* @__PURE__ */ new Set(["http", "log", "ui", "navigation", "query", "default"]);
|
|
@@ -983,6 +1402,17 @@ function generateId() {
|
|
|
983
1402
|
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
984
1403
|
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
985
1404
|
}
|
|
1405
|
+
function stringContextValue(context, key) {
|
|
1406
|
+
const value = context[key];
|
|
1407
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1408
|
+
}
|
|
1409
|
+
function firstRecentRequestId(recentFailed) {
|
|
1410
|
+
for (let i = recentFailed.length - 1; i >= 0; i--) {
|
|
1411
|
+
const requestId = recentFailed[i]?.requestId;
|
|
1412
|
+
if (requestId && requestId.trim().length > 0) return requestId;
|
|
1413
|
+
}
|
|
1414
|
+
return void 0;
|
|
1415
|
+
}
|
|
986
1416
|
var AllStakClient = class {
|
|
987
1417
|
constructor(config) {
|
|
988
1418
|
this.breadcrumbs = [];
|
|
@@ -990,9 +1420,6 @@ var AllStakClient = class {
|
|
|
990
1420
|
this.replay = null;
|
|
991
1421
|
this.httpRequests = null;
|
|
992
1422
|
this._instrumentAxios = null;
|
|
993
|
-
if (!config.apiKey) {
|
|
994
|
-
throw new Error("AllStak: config.apiKey is required");
|
|
995
|
-
}
|
|
996
1423
|
this.config = { ...config };
|
|
997
1424
|
if (!this.config.environment) this.config.environment = "production";
|
|
998
1425
|
if (!this.config.sdkName) this.config.sdkName = SDK_NAME;
|
|
@@ -1001,7 +1428,7 @@ var AllStakClient = class {
|
|
|
1001
1428
|
this.sessionId = generateId();
|
|
1002
1429
|
this.maxBreadcrumbs = config.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS;
|
|
1003
1430
|
const baseUrl = (config.host ?? INGEST_HOST).replace(/\/$/, "");
|
|
1004
|
-
this.transport = new HttpTransport(baseUrl, config.apiKey);
|
|
1431
|
+
this.transport = new HttpTransport(baseUrl, config.apiKey ?? "", Boolean(config.apiKey));
|
|
1005
1432
|
this.tracing = new TracingModule(this.transport, {
|
|
1006
1433
|
service: config.service ?? config.release ?? "",
|
|
1007
1434
|
environment: this.config.environment ?? "production",
|
|
@@ -1028,7 +1455,15 @@ var AllStakClient = class {
|
|
|
1028
1455
|
const { instrumentAxios } = installHttpInstrumentation(
|
|
1029
1456
|
this.httpRequests,
|
|
1030
1457
|
config.httpTracking ?? {},
|
|
1031
|
-
baseUrl
|
|
1458
|
+
baseUrl,
|
|
1459
|
+
{
|
|
1460
|
+
tracing: this.tracing,
|
|
1461
|
+
replay: this.replay,
|
|
1462
|
+
release: this.config.release,
|
|
1463
|
+
dist: this.config.dist,
|
|
1464
|
+
platform: this.config.platform,
|
|
1465
|
+
environment: this.config.environment
|
|
1466
|
+
}
|
|
1032
1467
|
);
|
|
1033
1468
|
this._instrumentAxios = instrumentAxios;
|
|
1034
1469
|
} catch {
|
|
@@ -1052,33 +1487,67 @@ var AllStakClient = class {
|
|
|
1052
1487
|
if (!this.passesSampleRate()) return;
|
|
1053
1488
|
const frames = parseStack(error.stack).map((f) => ({
|
|
1054
1489
|
...f,
|
|
1055
|
-
platform: this.config.platform
|
|
1490
|
+
platform: this.config.platform,
|
|
1491
|
+
debugId: resolveDebugId(f.filename)
|
|
1056
1492
|
}));
|
|
1493
|
+
const debugIdSet = /* @__PURE__ */ new Set();
|
|
1494
|
+
for (const f of frames) if (f.debugId) debugIdSet.add(f.debugId);
|
|
1495
|
+
const debugMeta = debugIdSet.size > 0 ? { images: Array.from(debugIdSet).map((id2) => ({ type: "sourcemap", debugId: id2 })) } : void 0;
|
|
1057
1496
|
const stackTrace = frames.length > 0 ? frames.map(frameToString) : void 0;
|
|
1058
1497
|
const currentBreadcrumbs = this.breadcrumbs.length > 0 ? [...this.breadcrumbs] : void 0;
|
|
1059
1498
|
this.breadcrumbs = [];
|
|
1060
1499
|
const exceptionClass = (error.name && error.name !== "Error" ? error.name : void 0) || error.constructor?.name || "Error";
|
|
1061
1500
|
const eff = this.effective();
|
|
1062
1501
|
const traceContext = {};
|
|
1063
|
-
const
|
|
1502
|
+
const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
|
|
1503
|
+
const linkedRequest = recentFailed.length > 0 ? recentFailed[recentFailed.length - 1] : void 0;
|
|
1504
|
+
if (linkedRequest?.traceId) this.tracing.setTraceId(linkedRequest.traceId);
|
|
1505
|
+
const exceptionSpan = linkedRequest ? this.tracing.startSpan("mobile.exception", {
|
|
1506
|
+
description: error.message,
|
|
1507
|
+
tags: {
|
|
1508
|
+
requestId: linkedRequest.requestId,
|
|
1509
|
+
exceptionClass
|
|
1510
|
+
}
|
|
1511
|
+
}) : null;
|
|
1512
|
+
exceptionSpan?.finish("error");
|
|
1513
|
+
const traceId = linkedRequest?.traceId ?? this.tracing.getTraceId();
|
|
1064
1514
|
if (traceId) traceContext.traceId = traceId;
|
|
1065
|
-
const spanId = this.tracing.getCurrentSpanId();
|
|
1515
|
+
const spanId = exceptionSpan?.spanId || this.tracing.getCurrentSpanId();
|
|
1066
1516
|
if (spanId) traceContext.spanId = spanId;
|
|
1067
|
-
const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
|
|
1068
1517
|
if (recentFailed.length > 0) {
|
|
1069
1518
|
traceContext["http.recentFailed"] = recentFailed.map((r) => ({
|
|
1070
1519
|
method: r.method,
|
|
1071
1520
|
url: r.url,
|
|
1072
1521
|
statusCode: r.statusCode,
|
|
1073
1522
|
durationMs: r.durationMs,
|
|
1074
|
-
error: r.error
|
|
1523
|
+
error: r.error,
|
|
1524
|
+
requestId: r.requestId,
|
|
1525
|
+
traceId: r.traceId,
|
|
1526
|
+
confidence: r.requestId === linkedRequest?.requestId ? "inferred" : "weak"
|
|
1075
1527
|
}));
|
|
1528
|
+
traceContext["http.linkConfidence"] = "inferred";
|
|
1529
|
+
}
|
|
1530
|
+
try {
|
|
1531
|
+
if (!linkedRequest) throw new Error("no linked request");
|
|
1532
|
+
this.replay?.recordTimelineMarker?.("exception", "exception_captured", {
|
|
1533
|
+
exceptionClass,
|
|
1534
|
+
message: error.message,
|
|
1535
|
+
requestLinkConfidence: linkedRequest ? "inferred" : "none"
|
|
1536
|
+
}, {
|
|
1537
|
+
traceId,
|
|
1538
|
+
requestId: linkedRequest?.requestId,
|
|
1539
|
+
spanId: spanId ?? void 0,
|
|
1540
|
+
release: this.config.release,
|
|
1541
|
+
dist: this.config.dist
|
|
1542
|
+
});
|
|
1543
|
+
} catch {
|
|
1076
1544
|
}
|
|
1077
1545
|
const payload = {
|
|
1078
1546
|
exceptionClass,
|
|
1079
1547
|
message: error.message,
|
|
1080
1548
|
stackTrace,
|
|
1081
1549
|
frames: frames.length > 0 ? frames : void 0,
|
|
1550
|
+
debugMeta,
|
|
1082
1551
|
platform: this.config.platform,
|
|
1083
1552
|
sdkName: this.config.sdkName,
|
|
1084
1553
|
sdkVersion: this.config.sdkVersion,
|
|
@@ -1087,12 +1556,29 @@ var AllStakClient = class {
|
|
|
1087
1556
|
environment: this.config.environment,
|
|
1088
1557
|
release: this.config.release,
|
|
1089
1558
|
sessionId: this.sessionId,
|
|
1559
|
+
traceId: stringContextValue(traceContext, "traceId"),
|
|
1560
|
+
spanId: stringContextValue(traceContext, "spanId"),
|
|
1561
|
+
requestId: linkedRequest?.requestId ?? firstRecentRequestId(recentFailed),
|
|
1562
|
+
service: this.config.service,
|
|
1090
1563
|
user: eff.user,
|
|
1091
1564
|
metadata: { ...this.buildMetadata(context), ...traceContext },
|
|
1092
1565
|
breadcrumbs: currentBreadcrumbs,
|
|
1093
1566
|
fingerprint: eff.fingerprint
|
|
1094
1567
|
};
|
|
1095
|
-
this.
|
|
1568
|
+
if (this.shouldCaptureScreenshot()) {
|
|
1569
|
+
void this.withScreenshotMetadata(error, payload).then((enriched) => this.sendThroughBeforeSend(enriched)).catch(() => this.sendThroughBeforeSend({
|
|
1570
|
+
...payload,
|
|
1571
|
+
metadata: { ...payload.metadata ?? {}, "screenshot.status": "failed" }
|
|
1572
|
+
}));
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
this.sendThroughBeforeSend({
|
|
1576
|
+
...payload,
|
|
1577
|
+
metadata: {
|
|
1578
|
+
...payload.metadata ?? {},
|
|
1579
|
+
"screenshot.status": this.config.screenshot?.enabled ? "unsupported" : "disabled"
|
|
1580
|
+
}
|
|
1581
|
+
});
|
|
1096
1582
|
}
|
|
1097
1583
|
/** Start a new span. Auto-parented to any currently-active span. */
|
|
1098
1584
|
startSpan(operation, options) {
|
|
@@ -1133,6 +1619,9 @@ var AllStakClient = class {
|
|
|
1133
1619
|
environment: this.config.environment,
|
|
1134
1620
|
release: this.config.release,
|
|
1135
1621
|
sessionId: this.sessionId,
|
|
1622
|
+
traceId: this.tracing.getTraceId(),
|
|
1623
|
+
spanId: this.tracing.getCurrentSpanId() ?? void 0,
|
|
1624
|
+
service: this.config.service,
|
|
1136
1625
|
user: eff.user,
|
|
1137
1626
|
metadata: this.buildMetadata(),
|
|
1138
1627
|
fingerprint: eff.fingerprint
|
|
@@ -1216,6 +1705,9 @@ var AllStakClient = class {
|
|
|
1216
1705
|
getConfig() {
|
|
1217
1706
|
return this.config;
|
|
1218
1707
|
}
|
|
1708
|
+
getTransportStats() {
|
|
1709
|
+
return this.transport.getStats();
|
|
1710
|
+
}
|
|
1219
1711
|
destroy() {
|
|
1220
1712
|
this.tracing.destroy();
|
|
1221
1713
|
if (this.replay) {
|
|
@@ -1226,6 +1718,7 @@ var AllStakClient = class {
|
|
|
1226
1718
|
this.httpRequests.destroy();
|
|
1227
1719
|
this.httpRequests = null;
|
|
1228
1720
|
}
|
|
1721
|
+
unbindHttpInstrumentation();
|
|
1229
1722
|
this._instrumentAxios = null;
|
|
1230
1723
|
this.breadcrumbs = [];
|
|
1231
1724
|
}
|
|
@@ -1244,6 +1737,58 @@ var AllStakClient = class {
|
|
|
1244
1737
|
metadata: this.buildMetadata()
|
|
1245
1738
|
});
|
|
1246
1739
|
}
|
|
1740
|
+
shouldCaptureScreenshot() {
|
|
1741
|
+
const screenshot = this.config.screenshot;
|
|
1742
|
+
if (!screenshot?.enabled || screenshot.captureOnError === false || !screenshot.provider) return false;
|
|
1743
|
+
const sampleRate = screenshot.sampleRate ?? 1;
|
|
1744
|
+
return !(sampleRate <= 0 || sampleRate < 1 && Math.random() >= sampleRate);
|
|
1745
|
+
}
|
|
1746
|
+
async withScreenshotMetadata(error, payload) {
|
|
1747
|
+
const screenshot = this.config.screenshot;
|
|
1748
|
+
if (!screenshot?.provider) {
|
|
1749
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "unsupported" } };
|
|
1750
|
+
}
|
|
1751
|
+
const timeoutMs = Math.max(100, Math.min(screenshot.timeoutMs ?? 1500, 5e3));
|
|
1752
|
+
const maxBytes = Math.max(1024, screenshot.maxBytes ?? 2e5);
|
|
1753
|
+
try {
|
|
1754
|
+
const artifact = await Promise.race([
|
|
1755
|
+
Promise.resolve(screenshot.provider({
|
|
1756
|
+
type: "error",
|
|
1757
|
+
error,
|
|
1758
|
+
traceId: payload.traceId,
|
|
1759
|
+
requestId: payload.requestId
|
|
1760
|
+
})),
|
|
1761
|
+
new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs))
|
|
1762
|
+
]);
|
|
1763
|
+
if (!artifact) {
|
|
1764
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "timeout_or_empty" } };
|
|
1765
|
+
}
|
|
1766
|
+
const size = artifact.sizeBytes ?? byteSize(artifact.data);
|
|
1767
|
+
if (size > maxBytes) {
|
|
1768
|
+
this.transport.noteDropped();
|
|
1769
|
+
return {
|
|
1770
|
+
...payload,
|
|
1771
|
+
metadata: { ...payload.metadata ?? {}, "screenshot.status": "dropped_too_large", "screenshot.sizeBytes": size }
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
return {
|
|
1775
|
+
...payload,
|
|
1776
|
+
metadata: {
|
|
1777
|
+
...payload.metadata ?? {},
|
|
1778
|
+
"screenshot.status": "captured",
|
|
1779
|
+
"screenshot.contentType": artifact.contentType,
|
|
1780
|
+
"screenshot.width": artifact.width,
|
|
1781
|
+
"screenshot.height": artifact.height,
|
|
1782
|
+
"screenshot.sizeBytes": size,
|
|
1783
|
+
"screenshot.redacted": artifact.redacted ?? false,
|
|
1784
|
+
"screenshot.redactionStrategy": artifact.redactionStrategy,
|
|
1785
|
+
...artifact.data ? { "screenshot.data": artifact.data } : {}
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
} catch {
|
|
1789
|
+
return { ...payload, metadata: { ...payload.metadata ?? {}, "screenshot.status": "failed" } };
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1247
1792
|
passesSampleRate() {
|
|
1248
1793
|
const r = this.config.sampleRate;
|
|
1249
1794
|
if (typeof r !== "number" || r >= 1) return true;
|
|
@@ -1342,10 +1887,22 @@ var AllStakClient = class {
|
|
|
1342
1887
|
}
|
|
1343
1888
|
};
|
|
1344
1889
|
var instance = null;
|
|
1345
|
-
function
|
|
1346
|
-
if (!instance) throw new Error("AllStak.init() must be called before using the SDK");
|
|
1890
|
+
function maybeInit() {
|
|
1347
1891
|
return instance;
|
|
1348
1892
|
}
|
|
1893
|
+
function noopSpan(operation = "") {
|
|
1894
|
+
return new Span("", "", "", operation, "", "", "", {}, () => void 0);
|
|
1895
|
+
}
|
|
1896
|
+
function emptyStats() {
|
|
1897
|
+
return {
|
|
1898
|
+
queued: 0,
|
|
1899
|
+
sent: 0,
|
|
1900
|
+
failed: 0,
|
|
1901
|
+
dropped: 0,
|
|
1902
|
+
consecutiveFailures: 0,
|
|
1903
|
+
circuitOpenUntil: 0
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1349
1906
|
function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
1350
1907
|
try {
|
|
1351
1908
|
instance?.addBreadcrumb(type, message, level, data);
|
|
@@ -1354,51 +1911,99 @@ function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
|
|
|
1354
1911
|
}
|
|
1355
1912
|
var AllStak = {
|
|
1356
1913
|
init(config) {
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1914
|
+
try {
|
|
1915
|
+
if (instance) instance.destroy();
|
|
1916
|
+
instance = new AllStakClient(config);
|
|
1917
|
+
return instance;
|
|
1918
|
+
} catch {
|
|
1919
|
+
instance = new AllStakClient({ ...config, apiKey: "" });
|
|
1920
|
+
return instance;
|
|
1921
|
+
}
|
|
1360
1922
|
},
|
|
1361
1923
|
captureException(error, context) {
|
|
1362
|
-
|
|
1924
|
+
try {
|
|
1925
|
+
maybeInit()?.captureException(error, context);
|
|
1926
|
+
} catch {
|
|
1927
|
+
}
|
|
1363
1928
|
},
|
|
1364
1929
|
captureMessage(message, level = "info", options) {
|
|
1365
|
-
|
|
1930
|
+
try {
|
|
1931
|
+
maybeInit()?.captureMessage(message, level, options);
|
|
1932
|
+
} catch {
|
|
1933
|
+
}
|
|
1366
1934
|
},
|
|
1367
1935
|
addBreadcrumb(type, message, level, data) {
|
|
1368
|
-
|
|
1936
|
+
try {
|
|
1937
|
+
maybeInit()?.addBreadcrumb(type, message, level, data);
|
|
1938
|
+
} catch {
|
|
1939
|
+
}
|
|
1369
1940
|
},
|
|
1370
1941
|
clearBreadcrumbs() {
|
|
1371
|
-
|
|
1942
|
+
try {
|
|
1943
|
+
maybeInit()?.clearBreadcrumbs();
|
|
1944
|
+
} catch {
|
|
1945
|
+
}
|
|
1372
1946
|
},
|
|
1373
1947
|
setUser(user) {
|
|
1374
|
-
|
|
1948
|
+
try {
|
|
1949
|
+
maybeInit()?.setUser(user);
|
|
1950
|
+
} catch {
|
|
1951
|
+
}
|
|
1375
1952
|
},
|
|
1376
1953
|
setTag(key, value) {
|
|
1377
|
-
|
|
1954
|
+
try {
|
|
1955
|
+
maybeInit()?.setTag(key, value);
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1378
1958
|
},
|
|
1379
1959
|
setTags(tags) {
|
|
1380
|
-
|
|
1960
|
+
try {
|
|
1961
|
+
maybeInit()?.setTags(tags);
|
|
1962
|
+
} catch {
|
|
1963
|
+
}
|
|
1381
1964
|
},
|
|
1382
1965
|
setExtra(key, value) {
|
|
1383
|
-
|
|
1966
|
+
try {
|
|
1967
|
+
maybeInit()?.setExtra(key, value);
|
|
1968
|
+
} catch {
|
|
1969
|
+
}
|
|
1384
1970
|
},
|
|
1385
1971
|
setExtras(extras) {
|
|
1386
|
-
|
|
1972
|
+
try {
|
|
1973
|
+
maybeInit()?.setExtras(extras);
|
|
1974
|
+
} catch {
|
|
1975
|
+
}
|
|
1387
1976
|
},
|
|
1388
1977
|
setContext(name, ctx) {
|
|
1389
|
-
|
|
1978
|
+
try {
|
|
1979
|
+
maybeInit()?.setContext(name, ctx);
|
|
1980
|
+
} catch {
|
|
1981
|
+
}
|
|
1390
1982
|
},
|
|
1391
1983
|
setLevel(level) {
|
|
1392
|
-
|
|
1984
|
+
try {
|
|
1985
|
+
maybeInit()?.setLevel(level);
|
|
1986
|
+
} catch {
|
|
1987
|
+
}
|
|
1393
1988
|
},
|
|
1394
1989
|
setFingerprint(fingerprint) {
|
|
1395
|
-
|
|
1990
|
+
try {
|
|
1991
|
+
maybeInit()?.setFingerprint(fingerprint);
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1396
1994
|
},
|
|
1397
1995
|
flush(timeoutMs) {
|
|
1398
|
-
|
|
1996
|
+
try {
|
|
1997
|
+
return maybeInit()?.flush(timeoutMs) ?? Promise.resolve(true);
|
|
1998
|
+
} catch {
|
|
1999
|
+
return Promise.resolve(false);
|
|
2000
|
+
}
|
|
1399
2001
|
},
|
|
1400
2002
|
setIdentity(identity) {
|
|
1401
|
-
|
|
2003
|
+
try {
|
|
2004
|
+
maybeInit()?.setIdentity(identity);
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
1402
2007
|
},
|
|
1403
2008
|
/**
|
|
1404
2009
|
* Run `callback` with a fresh scoped context. Any user/tag/extra/context/
|
|
@@ -1407,37 +2012,79 @@ var AllStak = {
|
|
|
1407
2012
|
* for async callbacks and thrown errors.
|
|
1408
2013
|
*/
|
|
1409
2014
|
withScope(callback) {
|
|
1410
|
-
|
|
2015
|
+
try {
|
|
2016
|
+
const client = maybeInit();
|
|
2017
|
+
return client ? client.withScope(callback) : callback(new Scope());
|
|
2018
|
+
} catch {
|
|
2019
|
+
return callback(new Scope());
|
|
2020
|
+
}
|
|
1411
2021
|
},
|
|
1412
2022
|
startSpan(operation, options) {
|
|
1413
|
-
|
|
2023
|
+
try {
|
|
2024
|
+
return maybeInit()?.startSpan(operation, options) ?? noopSpan(operation);
|
|
2025
|
+
} catch {
|
|
2026
|
+
return noopSpan(operation);
|
|
2027
|
+
}
|
|
1414
2028
|
},
|
|
1415
2029
|
getTraceId() {
|
|
1416
|
-
|
|
2030
|
+
try {
|
|
2031
|
+
return maybeInit()?.getTraceId() ?? "";
|
|
2032
|
+
} catch {
|
|
2033
|
+
return "";
|
|
2034
|
+
}
|
|
1417
2035
|
},
|
|
1418
2036
|
setTraceId(traceId) {
|
|
1419
|
-
|
|
2037
|
+
try {
|
|
2038
|
+
maybeInit()?.setTraceId(traceId);
|
|
2039
|
+
} catch {
|
|
2040
|
+
}
|
|
1420
2041
|
},
|
|
1421
2042
|
getCurrentSpanId() {
|
|
1422
|
-
|
|
2043
|
+
try {
|
|
2044
|
+
return maybeInit()?.getCurrentSpanId() ?? null;
|
|
2045
|
+
} catch {
|
|
2046
|
+
return null;
|
|
2047
|
+
}
|
|
1423
2048
|
},
|
|
1424
2049
|
resetTrace() {
|
|
1425
|
-
|
|
2050
|
+
try {
|
|
2051
|
+
maybeInit()?.resetTrace();
|
|
2052
|
+
} catch {
|
|
2053
|
+
}
|
|
1426
2054
|
},
|
|
1427
2055
|
/** Access the privacy-first replay surrogate (or null if disabled / sampled out). */
|
|
1428
2056
|
getReplay() {
|
|
1429
|
-
|
|
2057
|
+
try {
|
|
2058
|
+
return maybeInit()?.getReplay() ?? null;
|
|
2059
|
+
} catch {
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
1430
2062
|
},
|
|
1431
2063
|
/** Manually instrument an axios instance. No-op when HTTP tracking is off. */
|
|
1432
2064
|
instrumentAxios(axios) {
|
|
1433
|
-
|
|
2065
|
+
try {
|
|
2066
|
+
return maybeInit()?.instrumentAxios(axios) ?? axios;
|
|
2067
|
+
} catch {
|
|
2068
|
+
return axios;
|
|
2069
|
+
}
|
|
1434
2070
|
},
|
|
1435
2071
|
getSessionId() {
|
|
1436
|
-
|
|
2072
|
+
try {
|
|
2073
|
+
return maybeInit()?.getSessionId() ?? "";
|
|
2074
|
+
} catch {
|
|
2075
|
+
return "";
|
|
2076
|
+
}
|
|
1437
2077
|
},
|
|
1438
2078
|
getConfig() {
|
|
1439
2079
|
return instance?.getConfig() ?? null;
|
|
1440
2080
|
},
|
|
2081
|
+
getTransportStats() {
|
|
2082
|
+
try {
|
|
2083
|
+
return maybeInit()?.getTransportStats() ?? emptyStats();
|
|
2084
|
+
} catch {
|
|
2085
|
+
return emptyStats();
|
|
2086
|
+
}
|
|
2087
|
+
},
|
|
1441
2088
|
destroy() {
|
|
1442
2089
|
instance?.destroy();
|
|
1443
2090
|
instance = null;
|
|
@@ -1447,6 +2094,17 @@ var AllStak = {
|
|
|
1447
2094
|
return instance;
|
|
1448
2095
|
}
|
|
1449
2096
|
};
|
|
2097
|
+
function byteSize(value) {
|
|
2098
|
+
if (!value) return 0;
|
|
2099
|
+
try {
|
|
2100
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(value).length;
|
|
2101
|
+
} catch {
|
|
2102
|
+
}
|
|
2103
|
+
return value.length;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// src/provider.tsx
|
|
2107
|
+
import * as React from "react";
|
|
1450
2108
|
|
|
1451
2109
|
// src/auto-breadcrumbs.ts
|
|
1452
2110
|
var FETCH_FLAG2 = "__allstak_fetch_patched__";
|
|
@@ -1494,36 +2152,92 @@ function instrumentFetch(addBreadcrumb, ownBaseUrl) {
|
|
|
1494
2152
|
wrapped[FETCH_FLAG2] = true;
|
|
1495
2153
|
g.fetch = wrapped;
|
|
1496
2154
|
}
|
|
1497
|
-
|
|
2155
|
+
var CONSOLE_DEFAULTS = {
|
|
2156
|
+
log: false,
|
|
2157
|
+
info: false,
|
|
2158
|
+
warn: true,
|
|
2159
|
+
error: true
|
|
2160
|
+
};
|
|
2161
|
+
var CONSOLE_METHOD_TO_LEVEL = {
|
|
2162
|
+
log: "info",
|
|
2163
|
+
info: "info",
|
|
2164
|
+
warn: "warn",
|
|
2165
|
+
error: "error"
|
|
2166
|
+
};
|
|
2167
|
+
var MAX_ARG_BYTES = 5e3;
|
|
2168
|
+
function instrumentConsole(addBreadcrumb, options = {}) {
|
|
1498
2169
|
if (typeof console === "undefined") return;
|
|
1499
2170
|
if (console[CONSOLE_FLAG]) return;
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
} catch {
|
|
1506
|
-
}
|
|
1507
|
-
return origWarn.apply(console, args);
|
|
2171
|
+
const opts = {
|
|
2172
|
+
log: options.log ?? CONSOLE_DEFAULTS.log,
|
|
2173
|
+
info: options.info ?? CONSOLE_DEFAULTS.info,
|
|
2174
|
+
warn: options.warn ?? CONSOLE_DEFAULTS.warn,
|
|
2175
|
+
error: options.error ?? CONSOLE_DEFAULTS.error
|
|
1508
2176
|
};
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
2177
|
+
const wrap = (method) => {
|
|
2178
|
+
const orig = console[method];
|
|
2179
|
+
if (typeof orig !== "function") return;
|
|
2180
|
+
const level = CONSOLE_METHOD_TO_LEVEL[method];
|
|
2181
|
+
console[method] = function(...args) {
|
|
2182
|
+
if (opts[method]) {
|
|
2183
|
+
try {
|
|
2184
|
+
const serialized = args.map(safeStringifyArg);
|
|
2185
|
+
const message = truncate(serialized.join(" "));
|
|
2186
|
+
addBreadcrumb("log", message, level, {
|
|
2187
|
+
category: "console",
|
|
2188
|
+
method,
|
|
2189
|
+
args: serialized
|
|
2190
|
+
});
|
|
2191
|
+
} catch {
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return orig.apply(console, args);
|
|
2195
|
+
};
|
|
1515
2196
|
};
|
|
2197
|
+
if (opts.log) wrap("log");
|
|
2198
|
+
if (opts.info) wrap("info");
|
|
2199
|
+
if (opts.warn) wrap("warn");
|
|
2200
|
+
if (opts.error) wrap("error");
|
|
1516
2201
|
console[CONSOLE_FLAG] = true;
|
|
1517
2202
|
}
|
|
1518
|
-
function
|
|
1519
|
-
if (
|
|
2203
|
+
function __resetConsoleInstrumentationFlagForTest() {
|
|
2204
|
+
if (typeof console !== "undefined") {
|
|
2205
|
+
delete console[CONSOLE_FLAG];
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
function safeStringifyArg(v) {
|
|
2209
|
+
if (v === null || v === void 0) return String(v);
|
|
1520
2210
|
if (typeof v === "string") return v;
|
|
1521
|
-
if (v
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
return
|
|
2211
|
+
if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
|
|
2212
|
+
if (typeof v === "symbol") return v.toString();
|
|
2213
|
+
if (typeof v === "function") return `[Function${v.name ? ` ${v.name}` : ""}]`;
|
|
2214
|
+
if (v instanceof Error) {
|
|
2215
|
+
return `${v.name || "Error"}: ${v.message}${v.stack ? `
|
|
2216
|
+
${v.stack}` : ""}`;
|
|
2217
|
+
}
|
|
2218
|
+
if (typeof v === "object") {
|
|
2219
|
+
try {
|
|
2220
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2221
|
+
const out = JSON.stringify(v, (_key, val) => {
|
|
2222
|
+
if (typeof val === "object" && val !== null) {
|
|
2223
|
+
if (seen.has(val)) return "[Circular]";
|
|
2224
|
+
seen.add(val);
|
|
2225
|
+
}
|
|
2226
|
+
if (typeof val === "bigint") return val.toString();
|
|
2227
|
+
if (typeof val === "function") return `[Function${val.name ? ` ${val.name}` : ""}]`;
|
|
2228
|
+
if (typeof val === "symbol") return val.toString();
|
|
2229
|
+
return val;
|
|
2230
|
+
});
|
|
2231
|
+
return out ?? Object.prototype.toString.call(v);
|
|
2232
|
+
} catch {
|
|
2233
|
+
return Object.prototype.toString.call(v);
|
|
2234
|
+
}
|
|
1526
2235
|
}
|
|
2236
|
+
return String(v);
|
|
2237
|
+
}
|
|
2238
|
+
function truncate(s) {
|
|
2239
|
+
if (s.length <= MAX_ARG_BYTES) return s;
|
|
2240
|
+
return s.slice(0, MAX_ARG_BYTES) + "\u2026[truncated]";
|
|
1527
2241
|
}
|
|
1528
2242
|
|
|
1529
2243
|
// src/architecture.ts
|
|
@@ -1551,6 +2265,7 @@ function applyArchitectureTags(setTag) {
|
|
|
1551
2265
|
// src/navigation.ts
|
|
1552
2266
|
var NAV_FLAG = /* @__PURE__ */ Symbol.for("allstak.nav.subscribed");
|
|
1553
2267
|
var LINKING_FLAG = "__allstak_linking_patched__";
|
|
2268
|
+
var NAV_AUTO_PATCH_FLAG = /* @__PURE__ */ Symbol.for("allstak.nav.autoPatched");
|
|
1554
2269
|
function instrumentReactNavigation(navigationRef, options = {}) {
|
|
1555
2270
|
if (!navigationRef || typeof navigationRef.addListener !== "function") {
|
|
1556
2271
|
return () => {
|
|
@@ -1602,7 +2317,7 @@ function instrumentReactNavigation(navigationRef, options = {}) {
|
|
|
1602
2317
|
}
|
|
1603
2318
|
function instrumentNavigationFromLinking() {
|
|
1604
2319
|
try {
|
|
1605
|
-
const rn =
|
|
2320
|
+
const rn = require("react-native");
|
|
1606
2321
|
const Linking = rn?.Linking;
|
|
1607
2322
|
if (!Linking || typeof Linking.addEventListener !== "function") return;
|
|
1608
2323
|
if (Linking[LINKING_FLAG]) return;
|
|
@@ -1618,8 +2333,59 @@ function instrumentNavigationFromLinking() {
|
|
|
1618
2333
|
} catch {
|
|
1619
2334
|
}
|
|
1620
2335
|
}
|
|
2336
|
+
function tryAutoInstrumentNavigation() {
|
|
2337
|
+
const g = globalThis;
|
|
2338
|
+
const isMetro = typeof g.__METRO_GLOBAL_PREFIX__ !== "undefined" || typeof g.__r === "function" || typeof g.HermesInternal !== "undefined";
|
|
2339
|
+
if (isMetro) return false;
|
|
2340
|
+
try {
|
|
2341
|
+
const rnav = require("@react-navigation/native");
|
|
2342
|
+
if (!rnav || !rnav.NavigationContainer) return false;
|
|
2343
|
+
if (rnav[NAV_AUTO_PATCH_FLAG]) return true;
|
|
2344
|
+
const React2 = require("react");
|
|
2345
|
+
if (!React2 || typeof React2.forwardRef !== "function") return false;
|
|
2346
|
+
const OrigContainer = rnav.NavigationContainer;
|
|
2347
|
+
const Wrapped = React2.forwardRef(function AllStakNavigationContainer(props, userRef) {
|
|
2348
|
+
const internalRef = React2.useRef(null);
|
|
2349
|
+
const setRef = React2.useCallback((r) => {
|
|
2350
|
+
internalRef.current = r;
|
|
2351
|
+
if (typeof userRef === "function") userRef(r);
|
|
2352
|
+
else if (userRef) userRef.current = r;
|
|
2353
|
+
}, [userRef]);
|
|
2354
|
+
React2.useEffect(() => {
|
|
2355
|
+
if (internalRef.current) {
|
|
2356
|
+
try {
|
|
2357
|
+
instrumentReactNavigation(internalRef.current);
|
|
2358
|
+
} catch {
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
}, []);
|
|
2362
|
+
return React2.createElement(OrigContainer, { ...props, ref: setRef });
|
|
2363
|
+
});
|
|
2364
|
+
Wrapped.displayName = "AllStakNavigationContainer";
|
|
2365
|
+
try {
|
|
2366
|
+
Object.defineProperty(rnav, "NavigationContainer", {
|
|
2367
|
+
value: Wrapped,
|
|
2368
|
+
configurable: true,
|
|
2369
|
+
writable: true
|
|
2370
|
+
});
|
|
2371
|
+
rnav[NAV_AUTO_PATCH_FLAG] = true;
|
|
2372
|
+
return true;
|
|
2373
|
+
} catch {
|
|
2374
|
+
return false;
|
|
2375
|
+
}
|
|
2376
|
+
} catch {
|
|
2377
|
+
return false;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
function __resetAutoNavigationFlagForTest() {
|
|
2381
|
+
try {
|
|
2382
|
+
const rnav = require("@react-navigation/native");
|
|
2383
|
+
if (rnav) delete rnav[NAV_AUTO_PATCH_FLAG];
|
|
2384
|
+
} catch {
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
1621
2387
|
|
|
1622
|
-
// src/
|
|
2388
|
+
// src/install.ts
|
|
1623
2389
|
function instrumentXmlHttpRequest() {
|
|
1624
2390
|
const flag = "__allstak_xhr_patched__";
|
|
1625
2391
|
const X = globalThis.XMLHttpRequest;
|
|
@@ -1671,43 +2437,6 @@ function instrumentXmlHttpRequest() {
|
|
|
1671
2437
|
};
|
|
1672
2438
|
X.prototype[flag] = true;
|
|
1673
2439
|
}
|
|
1674
|
-
var __testNativeModule = null;
|
|
1675
|
-
function __setNativeModuleForTest(mod) {
|
|
1676
|
-
__testNativeModule = mod;
|
|
1677
|
-
}
|
|
1678
|
-
async function drainPendingNativeCrashes(release) {
|
|
1679
|
-
try {
|
|
1680
|
-
let native = __testNativeModule;
|
|
1681
|
-
if (!native) {
|
|
1682
|
-
const rn = __require("react-native");
|
|
1683
|
-
native = rn?.NativeModules?.AllStakNative;
|
|
1684
|
-
}
|
|
1685
|
-
if (!native) return;
|
|
1686
|
-
if (typeof native.install === "function") {
|
|
1687
|
-
try {
|
|
1688
|
-
await native.install(release ?? "");
|
|
1689
|
-
} catch {
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
if (typeof native.drainPendingCrash === "function") {
|
|
1693
|
-
const json = await native.drainPendingCrash();
|
|
1694
|
-
if (json && json !== "") {
|
|
1695
|
-
try {
|
|
1696
|
-
const payload = JSON.parse(json);
|
|
1697
|
-
const err = new Error(payload?.message ?? "Native crash");
|
|
1698
|
-
err.name = payload?.exceptionClass ?? "NativeCrash";
|
|
1699
|
-
err.stack = Array.isArray(payload?.stackTrace) ? payload.stackTrace.join("\n") : String(payload?.stackTrace ?? "");
|
|
1700
|
-
AllStak.captureException(err, {
|
|
1701
|
-
...payload?.metadata || {},
|
|
1702
|
-
"native.crash": "true"
|
|
1703
|
-
});
|
|
1704
|
-
} catch {
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
} catch {
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
2440
|
function installReactNative(options = {}) {
|
|
1712
2441
|
const autoError = options.autoErrorHandler !== false;
|
|
1713
2442
|
const autoPromise = options.autoPromiseRejections !== false;
|
|
@@ -1723,7 +2452,7 @@ function installReactNative(options = {}) {
|
|
|
1723
2452
|
const hermes = typeof globalThis.HermesInternal !== "undefined";
|
|
1724
2453
|
let dist;
|
|
1725
2454
|
try {
|
|
1726
|
-
const rn =
|
|
2455
|
+
const rn = require("react-native");
|
|
1727
2456
|
const os = rn?.Platform?.OS;
|
|
1728
2457
|
if (os === "ios" || os === "android") {
|
|
1729
2458
|
dist = `${os}-${hermes ? "hermes" : "jsc"}`;
|
|
@@ -1732,7 +2461,7 @@ function installReactNative(options = {}) {
|
|
|
1732
2461
|
}
|
|
1733
2462
|
AllStak.setIdentity({
|
|
1734
2463
|
sdkName: "allstak-react-native",
|
|
1735
|
-
sdkVersion:
|
|
2464
|
+
sdkVersion: SDK_VERSION,
|
|
1736
2465
|
platform: "react-native",
|
|
1737
2466
|
dist
|
|
1738
2467
|
});
|
|
@@ -1754,13 +2483,25 @@ function installReactNative(options = {}) {
|
|
|
1754
2483
|
}
|
|
1755
2484
|
if (options.autoConsoleBreadcrumbs !== false) {
|
|
1756
2485
|
try {
|
|
1757
|
-
|
|
2486
|
+
const cfg = AllStak.getConfig();
|
|
2487
|
+
instrumentConsole(__safeAddBreadcrumbForInstrumentation, cfg?.captureConsole);
|
|
1758
2488
|
} catch {
|
|
1759
2489
|
}
|
|
1760
2490
|
}
|
|
2491
|
+
if (options.autoNavigationBreadcrumbs !== false) {
|
|
2492
|
+
let navResult = false;
|
|
2493
|
+
try {
|
|
2494
|
+
navResult = tryAutoInstrumentNavigation();
|
|
2495
|
+
} catch {
|
|
2496
|
+
}
|
|
2497
|
+
if (options.debugLogs) {
|
|
2498
|
+
if (navResult) console.log("[AllStak] Navigation auto-instrumentation enabled");
|
|
2499
|
+
else console.log("[AllStak] Navigation auto-instrumentation not applied; use instrumentReactNavigation(ref) fallback");
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
1761
2502
|
if (autoDevice) {
|
|
1762
2503
|
try {
|
|
1763
|
-
const rn =
|
|
2504
|
+
const rn = require("react-native");
|
|
1764
2505
|
const Platform = rn?.Platform;
|
|
1765
2506
|
if (Platform) {
|
|
1766
2507
|
AllStak.setTag("device.os", String(Platform.OS ?? ""));
|
|
@@ -1774,7 +2515,7 @@ function installReactNative(options = {}) {
|
|
|
1774
2515
|
}
|
|
1775
2516
|
if (autoAppState) {
|
|
1776
2517
|
try {
|
|
1777
|
-
const rn =
|
|
2518
|
+
const rn = require("react-native");
|
|
1778
2519
|
const AppState = rn?.AppState;
|
|
1779
2520
|
if (AppState && typeof AppState.addEventListener === "function") {
|
|
1780
2521
|
AppState.addEventListener("change", (next) => {
|
|
@@ -1807,17 +2548,30 @@ function installReactNative(options = {}) {
|
|
|
1807
2548
|
}
|
|
1808
2549
|
}
|
|
1809
2550
|
if (autoPromise) {
|
|
2551
|
+
const wrapTrackerReason = (rejection) => rejection instanceof Error ? rejection : new Error(`Unhandled promise rejection: ${String(rejection)}`);
|
|
2552
|
+
const ship = (err) => {
|
|
2553
|
+
try {
|
|
2554
|
+
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
2555
|
+
} catch {
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
try {
|
|
2559
|
+
const hermesInternal = globalThis.HermesInternal;
|
|
2560
|
+
if (hermesInternal && typeof hermesInternal.enablePromiseRejectionTracker === "function") {
|
|
2561
|
+
hermesInternal.enablePromiseRejectionTracker({
|
|
2562
|
+
allRejections: true,
|
|
2563
|
+
onUnhandled: (_id, rejection) => ship(wrapTrackerReason(rejection)),
|
|
2564
|
+
onHandled: () => {
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
} catch {
|
|
2569
|
+
}
|
|
1810
2570
|
try {
|
|
1811
|
-
const tracking =
|
|
2571
|
+
const tracking = require("promise/setimmediate/rejection-tracking");
|
|
1812
2572
|
tracking.enable({
|
|
1813
2573
|
allRejections: true,
|
|
1814
|
-
onUnhandled: (_id, rejection) =>
|
|
1815
|
-
const err = rejection instanceof Error ? rejection : new Error(`Unhandled promise rejection: ${String(rejection)}`);
|
|
1816
|
-
try {
|
|
1817
|
-
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
1818
|
-
} catch {
|
|
1819
|
-
}
|
|
1820
|
-
},
|
|
2574
|
+
onUnhandled: (_id, rejection) => ship(wrapTrackerReason(rejection)),
|
|
1821
2575
|
onHandled: () => {
|
|
1822
2576
|
}
|
|
1823
2577
|
});
|
|
@@ -1827,30 +2581,237 @@ function installReactNative(options = {}) {
|
|
|
1827
2581
|
g.addEventListener("unhandledrejection", (ev) => {
|
|
1828
2582
|
const reason = ev?.reason;
|
|
1829
2583
|
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
1830
|
-
|
|
1831
|
-
AllStak.captureException(err, { source: "unhandledRejection" });
|
|
1832
|
-
} catch {
|
|
1833
|
-
}
|
|
2584
|
+
ship(err);
|
|
1834
2585
|
});
|
|
1835
2586
|
}
|
|
1836
2587
|
}
|
|
1837
2588
|
}
|
|
1838
2589
|
}
|
|
2590
|
+
|
|
2591
|
+
// src/provider.tsx
|
|
2592
|
+
var AllStakContext = React.createContext(null);
|
|
2593
|
+
var __providerOwnedInstance = null;
|
|
2594
|
+
var AllStakErrorBoundary = class extends React.Component {
|
|
2595
|
+
constructor() {
|
|
2596
|
+
super(...arguments);
|
|
2597
|
+
this.state = { error: null };
|
|
2598
|
+
this.resetError = () => this.setState({ error: null });
|
|
2599
|
+
}
|
|
2600
|
+
static getDerivedStateFromError(error) {
|
|
2601
|
+
return { error };
|
|
2602
|
+
}
|
|
2603
|
+
componentDidCatch(error, info) {
|
|
2604
|
+
try {
|
|
2605
|
+
AllStak.addBreadcrumb("ui", "React error boundary caught error", "error", {
|
|
2606
|
+
componentStack: info.componentStack ?? ""
|
|
2607
|
+
});
|
|
2608
|
+
AllStak.captureException(error, {
|
|
2609
|
+
componentStack: info.componentStack ?? "",
|
|
2610
|
+
source: "AllStakProvider.ErrorBoundary"
|
|
2611
|
+
});
|
|
2612
|
+
if (this.props.debug) {
|
|
2613
|
+
console.log(`[AllStak] Captured render error: ${error.message}`);
|
|
2614
|
+
}
|
|
2615
|
+
} catch {
|
|
2616
|
+
}
|
|
2617
|
+
try {
|
|
2618
|
+
this.props.onError?.(error, info.componentStack ?? void 0);
|
|
2619
|
+
} catch {
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
render() {
|
|
2623
|
+
if (this.state.error) {
|
|
2624
|
+
const { fallback } = this.props;
|
|
2625
|
+
if (typeof fallback === "function") {
|
|
2626
|
+
return fallback({ error: this.state.error, resetError: this.resetError });
|
|
2627
|
+
}
|
|
2628
|
+
if (fallback !== void 0) return fallback;
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
return this.props.children;
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
function AllStakProvider({
|
|
2635
|
+
children,
|
|
2636
|
+
apiKey,
|
|
2637
|
+
environment,
|
|
2638
|
+
release,
|
|
2639
|
+
host,
|
|
2640
|
+
user,
|
|
2641
|
+
tags,
|
|
2642
|
+
debug,
|
|
2643
|
+
enableHttpTracking,
|
|
2644
|
+
httpTracking,
|
|
2645
|
+
captureConsole,
|
|
2646
|
+
sampleRate,
|
|
2647
|
+
beforeSend,
|
|
2648
|
+
replay,
|
|
2649
|
+
tracesSampleRate,
|
|
2650
|
+
service,
|
|
2651
|
+
dist,
|
|
2652
|
+
destroyOnUnmount = false,
|
|
2653
|
+
fallback,
|
|
2654
|
+
onError,
|
|
2655
|
+
autoErrorHandler,
|
|
2656
|
+
autoPromiseRejections,
|
|
2657
|
+
autoDeviceTags,
|
|
2658
|
+
autoAppStateBreadcrumbs,
|
|
2659
|
+
autoNetworkCapture,
|
|
2660
|
+
autoFetchBreadcrumbs,
|
|
2661
|
+
autoConsoleBreadcrumbs,
|
|
2662
|
+
autoNavigationBreadcrumbs
|
|
2663
|
+
}) {
|
|
2664
|
+
const clientRef = React.useRef(null);
|
|
2665
|
+
if (!clientRef.current) {
|
|
2666
|
+
const existing = AllStak._getInstance();
|
|
2667
|
+
if (existing && __providerOwnedInstance === existing) {
|
|
2668
|
+
clientRef.current = existing;
|
|
2669
|
+
if (debug) {
|
|
2670
|
+
console.log(`[AllStak] Reusing session ${AllStak.getSessionId()}`);
|
|
2671
|
+
}
|
|
2672
|
+
} else {
|
|
2673
|
+
const config = {
|
|
2674
|
+
apiKey,
|
|
2675
|
+
environment,
|
|
2676
|
+
release,
|
|
2677
|
+
host,
|
|
2678
|
+
user,
|
|
2679
|
+
tags,
|
|
2680
|
+
enableHttpTracking,
|
|
2681
|
+
httpTracking,
|
|
2682
|
+
captureConsole,
|
|
2683
|
+
sampleRate,
|
|
2684
|
+
beforeSend,
|
|
2685
|
+
replay,
|
|
2686
|
+
tracesSampleRate,
|
|
2687
|
+
service,
|
|
2688
|
+
dist
|
|
2689
|
+
};
|
|
2690
|
+
clientRef.current = AllStak.init(config);
|
|
2691
|
+
__providerOwnedInstance = clientRef.current;
|
|
2692
|
+
installReactNative({
|
|
2693
|
+
autoErrorHandler,
|
|
2694
|
+
autoPromiseRejections,
|
|
2695
|
+
autoDeviceTags,
|
|
2696
|
+
autoAppStateBreadcrumbs,
|
|
2697
|
+
autoNetworkCapture,
|
|
2698
|
+
autoFetchBreadcrumbs,
|
|
2699
|
+
autoConsoleBreadcrumbs,
|
|
2700
|
+
autoNavigationBreadcrumbs,
|
|
2701
|
+
debugLogs: debug
|
|
2702
|
+
});
|
|
2703
|
+
if (debug) {
|
|
2704
|
+
console.log(`[AllStak] Initialized \u2014 session ${AllStak.getSessionId()}`);
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
React.useEffect(() => {
|
|
2709
|
+
return () => {
|
|
2710
|
+
if (destroyOnUnmount) {
|
|
2711
|
+
AllStak.destroy();
|
|
2712
|
+
__providerOwnedInstance = null;
|
|
2713
|
+
clientRef.current = null;
|
|
2714
|
+
if (debug) console.log("[AllStak] Destroyed on unmount");
|
|
2715
|
+
}
|
|
2716
|
+
};
|
|
2717
|
+
}, [destroyOnUnmount, debug]);
|
|
2718
|
+
return /* @__PURE__ */ React.createElement(AllStakContext.Provider, { value: clientRef.current }, /* @__PURE__ */ React.createElement(AllStakErrorBoundary, { fallback, onError, debug }, children));
|
|
2719
|
+
}
|
|
2720
|
+
function useAllStak() {
|
|
2721
|
+
return React.useMemo(
|
|
2722
|
+
() => ({
|
|
2723
|
+
captureException: (error, ctx) => AllStak.captureException(error, ctx),
|
|
2724
|
+
captureMessage: (msg, level = "info") => AllStak.captureMessage(msg, level),
|
|
2725
|
+
setUser: (user) => AllStak.setUser(user),
|
|
2726
|
+
setTag: (key, value) => AllStak.setTag(key, value),
|
|
2727
|
+
addBreadcrumb: (type, message, level, data) => AllStak.addBreadcrumb(type, message, level, data)
|
|
2728
|
+
}),
|
|
2729
|
+
[]
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
function __resetProviderInstanceForTest() {
|
|
2733
|
+
__providerOwnedInstance = null;
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
// src/index.ts
|
|
2737
|
+
var __testNativeModule = null;
|
|
2738
|
+
function __setNativeModuleForTest(mod) {
|
|
2739
|
+
__testNativeModule = mod;
|
|
2740
|
+
}
|
|
2741
|
+
async function __devTriggerNativeCrash() {
|
|
2742
|
+
try {
|
|
2743
|
+
let native = __testNativeModule;
|
|
2744
|
+
if (!native) {
|
|
2745
|
+
const rn = require("react-native");
|
|
2746
|
+
native = rn?.NativeModules?.AllStakNative;
|
|
2747
|
+
}
|
|
2748
|
+
if (!native || typeof native.__devTriggerCrash !== "function") return;
|
|
2749
|
+
await native.__devTriggerCrash();
|
|
2750
|
+
} catch {
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
async function drainPendingNativeCrashes(release) {
|
|
2754
|
+
try {
|
|
2755
|
+
let native = __testNativeModule;
|
|
2756
|
+
if (!native) {
|
|
2757
|
+
const rn = require("react-native");
|
|
2758
|
+
native = rn?.NativeModules?.AllStakNative;
|
|
2759
|
+
}
|
|
2760
|
+
if (!native) return;
|
|
2761
|
+
if (typeof native.install === "function") {
|
|
2762
|
+
try {
|
|
2763
|
+
await native.install(release ?? "");
|
|
2764
|
+
} catch {
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
if (typeof native.drainPendingCrash === "function") {
|
|
2768
|
+
const json = await native.drainPendingCrash();
|
|
2769
|
+
if (json && json !== "") {
|
|
2770
|
+
try {
|
|
2771
|
+
const payload = JSON.parse(json);
|
|
2772
|
+
const err = new Error(payload?.message ?? "Native crash");
|
|
2773
|
+
err.name = payload?.exceptionClass ?? "NativeCrash";
|
|
2774
|
+
err.stack = Array.isArray(payload?.stackTrace) ? payload.stackTrace.join("\n") : String(payload?.stackTrace ?? "");
|
|
2775
|
+
AllStak.captureException(err, {
|
|
2776
|
+
...payload?.metadata || {},
|
|
2777
|
+
"native.crash": "true"
|
|
2778
|
+
});
|
|
2779
|
+
} catch {
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
} catch {
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
1839
2786
|
export {
|
|
2787
|
+
ALWAYS_REDACT_HEADERS,
|
|
2788
|
+
ALWAYS_REDACT_QUERY,
|
|
1840
2789
|
AllStak,
|
|
1841
2790
|
AllStakClient,
|
|
2791
|
+
AllStakProvider,
|
|
2792
|
+
DEFAULT_REDACT_BODY_FIELDS,
|
|
1842
2793
|
HttpRequestModule,
|
|
1843
2794
|
INGEST_HOST,
|
|
2795
|
+
REDACTED,
|
|
1844
2796
|
ReplaySurrogate,
|
|
1845
2797
|
SDK_NAME,
|
|
1846
2798
|
SDK_VERSION,
|
|
1847
2799
|
Scope,
|
|
2800
|
+
__devTriggerNativeCrash,
|
|
2801
|
+
__resetAutoNavigationFlagForTest,
|
|
2802
|
+
__resetConsoleInstrumentationFlagForTest,
|
|
2803
|
+
__resetProviderInstanceForTest,
|
|
1848
2804
|
__setNativeModuleForTest,
|
|
1849
2805
|
applyArchitectureTags,
|
|
2806
|
+
captureBodyResult,
|
|
1850
2807
|
detectArchitecture,
|
|
1851
2808
|
drainPendingNativeCrashes,
|
|
1852
2809
|
installReactNative,
|
|
1853
2810
|
instrumentNavigationFromLinking,
|
|
1854
|
-
instrumentReactNavigation
|
|
2811
|
+
instrumentReactNavigation,
|
|
2812
|
+
redactUrl,
|
|
2813
|
+
sanitizeHeaders,
|
|
2814
|
+
tryAutoInstrumentNavigation,
|
|
2815
|
+
useAllStak
|
|
1855
2816
|
};
|
|
1856
2817
|
//# sourceMappingURL=index.mjs.map
|