@allstak/react-native 0.1.3 → 0.3.0

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/dist/index.mjs CHANGED
@@ -1,7 +1,1856 @@
1
+ import {
2
+ __require
3
+ } from "./chunk-BJTO5JO5.mjs";
4
+
5
+ // src/transport.ts
6
+ var REQUEST_TIMEOUT = 3e3;
7
+ var MAX_BUFFER = 100;
8
+ var HttpTransport = class {
9
+ constructor(baseUrl, apiKey) {
10
+ this.baseUrl = baseUrl;
11
+ this.apiKey = apiKey;
12
+ this.buffer = [];
13
+ this.flushing = false;
14
+ }
15
+ async send(path, payload) {
16
+ try {
17
+ await this.doFetch(path, payload);
18
+ await this.flushBuffer();
19
+ } catch {
20
+ if (this.buffer.length >= MAX_BUFFER) this.buffer.shift();
21
+ this.buffer.push({ path, payload });
22
+ }
23
+ }
24
+ async doFetch(path, payload) {
25
+ const url = `${this.baseUrl}${path}`;
26
+ const controller = new AbortController();
27
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
28
+ try {
29
+ const res = await fetch(url, {
30
+ method: "POST",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ "X-AllStak-Key": this.apiKey
34
+ },
35
+ body: JSON.stringify(payload),
36
+ signal: controller.signal
37
+ });
38
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
39
+ } finally {
40
+ clearTimeout(timeoutId);
41
+ }
42
+ }
43
+ async flushBuffer() {
44
+ if (this.flushing || this.buffer.length === 0) return;
45
+ this.flushing = true;
46
+ try {
47
+ const items = this.buffer.splice(0, this.buffer.length);
48
+ for (const item of items) {
49
+ try {
50
+ await this.doFetch(item.path, item.payload);
51
+ } catch {
52
+ }
53
+ }
54
+ } finally {
55
+ this.flushing = false;
56
+ }
57
+ }
58
+ getBufferSize() {
59
+ return this.buffer.length;
60
+ }
61
+ /**
62
+ * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
63
+ * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
64
+ * Useful before navigation away or during native crash drain.
65
+ */
66
+ async flush(timeoutMs = 2e3) {
67
+ const deadline = Date.now() + timeoutMs;
68
+ await this.flushBuffer();
69
+ while (this.buffer.length > 0 || this.flushing) {
70
+ if (Date.now() >= deadline) return false;
71
+ await new Promise((r) => setTimeout(r, 25));
72
+ await this.flushBuffer();
73
+ }
74
+ return true;
75
+ }
76
+ };
77
+
78
+ // src/stack.ts
79
+ var V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?((?:.+?):(\d+):(\d+))\)?\s*$/;
80
+ var GECKO_FRAME_RE = /^\s*(?:(.*?)@)?(.+?):(\d+):(\d+)\s*$/;
81
+ var NODE_INTERNAL_RE = /^(node:|internal\/|node_modules\/)/;
82
+ function parseStack(stack) {
83
+ if (!stack || typeof stack !== "string") return [];
84
+ const frames = [];
85
+ for (const raw of stack.split("\n")) {
86
+ const line = raw.trim();
87
+ if (!line) continue;
88
+ let m = V8_FRAME_RE.exec(line);
89
+ if (m) {
90
+ const filename = stripQueryHash(m[2].replace(/:\d+:\d+$/, ""));
91
+ frames.push({
92
+ filename,
93
+ absPath: filename,
94
+ function: m[1] ? m[1].trim() : void 0,
95
+ lineno: parseInt(m[3], 10),
96
+ colno: parseInt(m[4], 10),
97
+ inApp: isInApp(filename)
98
+ });
99
+ continue;
100
+ }
101
+ m = GECKO_FRAME_RE.exec(line);
102
+ if (m && m[2]) {
103
+ const filename = stripQueryHash(m[2]);
104
+ frames.push({
105
+ filename,
106
+ absPath: filename,
107
+ function: m[1] ? m[1].trim() : void 0,
108
+ lineno: parseInt(m[3], 10),
109
+ colno: parseInt(m[4], 10),
110
+ inApp: isInApp(filename)
111
+ });
112
+ }
113
+ }
114
+ return frames;
115
+ }
116
+ function stripQueryHash(url) {
117
+ const q = url.indexOf("?");
118
+ const h = url.indexOf("#");
119
+ let cut = url.length;
120
+ if (q >= 0) cut = Math.min(cut, q);
121
+ if (h >= 0) cut = Math.min(cut, h);
122
+ return url.slice(0, cut);
123
+ }
124
+ function isInApp(filename) {
125
+ if (!filename) return true;
126
+ if (NODE_INTERNAL_RE.test(filename)) return false;
127
+ if (filename.includes("/node_modules/")) return false;
128
+ return true;
129
+ }
130
+
131
+ // src/scope.ts
132
+ var Scope = class {
133
+ constructor() {
134
+ this.tags = {};
135
+ this.extras = {};
136
+ this.contexts = {};
137
+ }
138
+ setUser(user) {
139
+ this.user = user;
140
+ return this;
141
+ }
142
+ setTag(key, value) {
143
+ this.tags[key] = value;
144
+ return this;
145
+ }
146
+ setTags(tags) {
147
+ Object.assign(this.tags, tags);
148
+ return this;
149
+ }
150
+ setExtra(key, value) {
151
+ this.extras[key] = value;
152
+ return this;
153
+ }
154
+ setExtras(extras) {
155
+ Object.assign(this.extras, extras);
156
+ return this;
157
+ }
158
+ setContext(name, ctx) {
159
+ if (ctx === null) delete this.contexts[name];
160
+ else this.contexts[name] = ctx;
161
+ return this;
162
+ }
163
+ setLevel(level) {
164
+ this.level = level;
165
+ return this;
166
+ }
167
+ setFingerprint(fingerprint) {
168
+ this.fingerprint = fingerprint && fingerprint.length > 0 ? fingerprint : void 0;
169
+ return this;
170
+ }
171
+ clear() {
172
+ this.user = void 0;
173
+ this.tags = {};
174
+ this.extras = {};
175
+ this.contexts = {};
176
+ this.fingerprint = void 0;
177
+ this.level = void 0;
178
+ return this;
179
+ }
180
+ };
181
+ function mergeScopes(base, stack) {
182
+ const out = { ...base };
183
+ out.tags = { ...base.tags ?? {} };
184
+ out.extras = { ...base.extras ?? {} };
185
+ out.contexts = { ...base.contexts ?? {} };
186
+ for (const scope of stack) {
187
+ if (scope.user) out.user = scope.user;
188
+ Object.assign(out.tags, scope.tags);
189
+ Object.assign(out.extras, scope.extras);
190
+ Object.assign(out.contexts, scope.contexts);
191
+ if (scope.fingerprint) out.fingerprint = scope.fingerprint;
192
+ if (scope.level) out.level = scope.level;
193
+ }
194
+ return out;
195
+ }
196
+
197
+ // src/tracing.ts
198
+ var SPAN_INGEST_PATH = "/ingest/v1/spans";
199
+ var FLUSH_INTERVAL_MS = 5e3;
200
+ var BATCH_SIZE_THRESHOLD = 20;
201
+ function id() {
202
+ const hex = (n) => Math.floor(Math.random() * n).toString(16).padStart(1, "0");
203
+ const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
204
+ return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
205
+ }
206
+ var Span = class {
207
+ constructor(_traceId, _spanId, _parentSpanId, _operation, _description, _service, _environment, _tags, _onFinish) {
208
+ this._traceId = _traceId;
209
+ this._spanId = _spanId;
210
+ this._parentSpanId = _parentSpanId;
211
+ this._operation = _operation;
212
+ this._description = _description;
213
+ this._service = _service;
214
+ this._environment = _environment;
215
+ this._tags = _tags;
216
+ this._onFinish = _onFinish;
217
+ this._finished = false;
218
+ this._data = "";
219
+ this._startTimeMillis = Date.now();
220
+ }
221
+ setTag(key, value) {
222
+ this._tags[key] = value;
223
+ return this;
224
+ }
225
+ setData(data) {
226
+ this._data = data;
227
+ return this;
228
+ }
229
+ setDescription(description) {
230
+ this._description = description;
231
+ return this;
232
+ }
233
+ finish(status = "ok") {
234
+ if (this._finished) return;
235
+ this._finished = true;
236
+ const endTimeMillis = Date.now();
237
+ this._onFinish({
238
+ traceId: this._traceId,
239
+ spanId: this._spanId,
240
+ parentSpanId: this._parentSpanId,
241
+ operation: this._operation,
242
+ description: this._description,
243
+ status,
244
+ durationMs: endTimeMillis - this._startTimeMillis,
245
+ startTimeMillis: this._startTimeMillis,
246
+ endTimeMillis,
247
+ service: this._service,
248
+ environment: this._environment,
249
+ tags: this._tags,
250
+ data: this._data
251
+ });
252
+ }
253
+ get traceId() {
254
+ return this._traceId;
255
+ }
256
+ get spanId() {
257
+ return this._spanId;
258
+ }
259
+ get isFinished() {
260
+ return this._finished;
261
+ }
262
+ };
263
+ var NoopSpan = class extends Span {
264
+ constructor(traceId, spanId) {
265
+ super(traceId, spanId, "", "", "", "", "", {}, () => {
266
+ });
267
+ }
268
+ finish() {
269
+ }
270
+ };
271
+ var TracingModule = class {
272
+ constructor(transport, opts) {
273
+ this.transport = transport;
274
+ this.opts = opts;
275
+ this.spans = [];
276
+ this.flushTimer = null;
277
+ this.currentTraceId = null;
278
+ this.spanStack = [];
279
+ this.destroyed = false;
280
+ }
281
+ /** Get (and lazily create) the active trace ID. */
282
+ getTraceId() {
283
+ if (!this.currentTraceId) this.currentTraceId = id();
284
+ return this.currentTraceId;
285
+ }
286
+ /** Override the active trace ID, e.g. from an inbound request header. */
287
+ setTraceId(traceId) {
288
+ this.currentTraceId = traceId;
289
+ }
290
+ /** Get the active span's ID, or null if no span is active. */
291
+ getCurrentSpanId() {
292
+ return this.spanStack.length > 0 ? this.spanStack[this.spanStack.length - 1].spanId : null;
293
+ }
294
+ /** Reset both the trace ID and the in-flight span stack. */
295
+ resetTrace() {
296
+ this.currentTraceId = null;
297
+ this.spanStack = [];
298
+ }
299
+ /**
300
+ * Start a new span. The returned Span automatically inherits the active
301
+ * span as its parent. If `tracesSampleRate` drops this trace, returns a
302
+ * no-op Span so the call site doesn't have to null-check.
303
+ */
304
+ startSpan(operation, options = {}) {
305
+ const traceId = this.getTraceId();
306
+ const spanId = id();
307
+ const parentSpanId = this.getCurrentSpanId() ?? "";
308
+ if (!this.passesSampleRate()) {
309
+ return new NoopSpan(traceId, spanId);
310
+ }
311
+ const span = new Span(
312
+ traceId,
313
+ spanId,
314
+ parentSpanId,
315
+ operation,
316
+ options.description ?? "",
317
+ this.opts.service ?? "",
318
+ this.opts.environment ?? "",
319
+ { ...options.tags ?? {} },
320
+ (data) => this.enqueue(data, span)
321
+ );
322
+ this.spanStack.push(span);
323
+ return span;
324
+ }
325
+ passesSampleRate() {
326
+ const r = this.opts.tracesSampleRate;
327
+ if (typeof r !== "number" || r >= 1) return true;
328
+ if (r <= 0) return false;
329
+ return Math.random() < r;
330
+ }
331
+ enqueue(data, span) {
332
+ if (this.destroyed) return;
333
+ const idx = this.spanStack.lastIndexOf(span);
334
+ if (idx >= 0) this.spanStack.splice(idx, 1);
335
+ this.spans.push(data);
336
+ if (this.spans.length >= BATCH_SIZE_THRESHOLD) {
337
+ this.flush();
338
+ return;
339
+ }
340
+ if (!this.flushTimer) {
341
+ this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
342
+ }
343
+ }
344
+ flush() {
345
+ if (this.spans.length === 0) return;
346
+ const batch = this.spans;
347
+ this.spans = [];
348
+ this.transport.send(SPAN_INGEST_PATH, { spans: batch });
349
+ }
350
+ destroy() {
351
+ this.destroyed = true;
352
+ if (this.flushTimer) {
353
+ clearInterval(this.flushTimer);
354
+ this.flushTimer = null;
355
+ }
356
+ this.flush();
357
+ this.currentTraceId = null;
358
+ this.spanStack = [];
359
+ }
360
+ };
361
+
362
+ // src/replay-surrogate.ts
363
+ var REPLAY_INGEST_PATH = "/ingest/v1/replay";
364
+ var FLUSH_INTERVAL_MS2 = 1e4;
365
+ var ReplaySurrogate = class {
366
+ constructor(transport, sessionId, options = {}) {
367
+ this.transport = transport;
368
+ this.buffer = [];
369
+ this.flushTimer = null;
370
+ this.active = false;
371
+ this.destroyed = false;
372
+ this.sessionId = sessionId;
373
+ this.opts = {
374
+ enabled: options.enabled ?? true,
375
+ sampleRate: options.sampleRate ?? 0,
376
+ safeParams: options.safeParams ?? [],
377
+ maxBufferedEvents: options.maxBufferedEvents ?? 200
378
+ };
379
+ }
380
+ /** Enable recording for this session if sample-rate roll passes. */
381
+ start() {
382
+ if (!this.opts.enabled) return false;
383
+ if (this.active) return true;
384
+ if (Math.random() >= this.opts.sampleRate) return false;
385
+ this.active = true;
386
+ this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS2);
387
+ return true;
388
+ }
389
+ /** Record a screen view. Filters params through the safeParams allow-list. */
390
+ recordScreenView(routeName, params) {
391
+ if (!this.active) return;
392
+ const safe = {};
393
+ if (params && this.opts.safeParams.length > 0) {
394
+ for (const key of this.opts.safeParams) {
395
+ if (key in params) safe[key] = params[key];
396
+ }
397
+ }
398
+ this.push({ ts: Date.now(), k: "screen", data: { route: routeName, params: safe } });
399
+ }
400
+ /** Record an AppState transition (foreground/background/inactive). */
401
+ recordAppState(next) {
402
+ if (!this.active) return;
403
+ this.push({ ts: Date.now(), k: "appstate", data: { state: next } });
404
+ }
405
+ /** Record a free-form, customer-validated checkpoint. */
406
+ recordManual(label, data) {
407
+ if (!this.active) return;
408
+ this.push({ ts: Date.now(), k: "manual", data: { label, ...data ?? {} } });
409
+ }
410
+ destroy() {
411
+ this.destroyed = true;
412
+ this.active = false;
413
+ if (this.flushTimer) {
414
+ clearInterval(this.flushTimer);
415
+ this.flushTimer = null;
416
+ }
417
+ this.flush();
418
+ }
419
+ /** @internal — for tests. */
420
+ isActive() {
421
+ return this.active;
422
+ }
423
+ /** @internal — for tests. */
424
+ getBuffer() {
425
+ return this.buffer;
426
+ }
427
+ push(ev) {
428
+ if (this.destroyed) return;
429
+ this.buffer.push(ev);
430
+ if (this.buffer.length >= this.opts.maxBufferedEvents) this.flush();
431
+ }
432
+ flush() {
433
+ if (this.buffer.length === 0) return;
434
+ const events = this.buffer;
435
+ this.buffer = [];
436
+ this.transport.send(REPLAY_INGEST_PATH, {
437
+ sessionId: this.sessionId,
438
+ events
439
+ });
440
+ }
441
+ };
442
+
443
+ // src/http-requests.ts
444
+ var INGEST_PATH = "/ingest/v1/http-requests";
445
+ var FLUSH_INTERVAL_MS3 = 5e3;
446
+ var BATCH_SIZE_THRESHOLD2 = 20;
447
+ var RECENT_FAILED_BUFFER_SIZE = 10;
448
+ function genTraceId() {
449
+ const hex = (n) => Math.floor(Math.random() * n).toString(16).padStart(1, "0");
450
+ const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
451
+ return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
452
+ }
453
+ function splitHostPath(url) {
454
+ try {
455
+ const u = new URL(url);
456
+ return { host: u.host, path: u.pathname || "/" };
457
+ } catch {
458
+ return { host: "", path: url.split("?")[0] };
459
+ }
460
+ }
461
+ var HttpRequestModule = class {
462
+ constructor(transport) {
463
+ this.transport = transport;
464
+ this.queue = [];
465
+ this.recentFailed = [];
466
+ this.flushTimer = null;
467
+ this.destroyed = false;
468
+ this.defaults = {};
469
+ }
470
+ setDefaults(defaults) {
471
+ this.defaults = { ...this.defaults, ...defaults };
472
+ }
473
+ capture(ev) {
474
+ if (this.destroyed) return;
475
+ const { host, path } = splitHostPath(ev.url);
476
+ const item = {
477
+ type: "http_request",
478
+ traceId: ev.traceId ?? genTraceId(),
479
+ direction: "outbound",
480
+ method: (ev.method || "GET").toUpperCase(),
481
+ host,
482
+ path,
483
+ url: ev.url,
484
+ statusCode: ev.statusCode ?? 0,
485
+ durationMs: Math.max(0, Math.floor(ev.durationMs)),
486
+ requestSize: ev.requestSize,
487
+ responseSize: ev.responseSize,
488
+ requestBody: ev.requestBody,
489
+ responseBody: ev.responseBody,
490
+ requestHeaders: ev.requestHeaders,
491
+ responseHeaders: ev.responseHeaders,
492
+ error: ev.error,
493
+ environment: this.defaults.environment,
494
+ release: this.defaults.release,
495
+ dist: this.defaults.dist,
496
+ platform: this.defaults.platform,
497
+ "sdk.name": this.defaults.sdkName,
498
+ "sdk.version": this.defaults.sdkVersion,
499
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
500
+ };
501
+ this.queue.push(item);
502
+ const isFailed = item.statusCode >= 400 || !!item.error;
503
+ if (isFailed) {
504
+ this.recentFailed.push(item);
505
+ if (this.recentFailed.length > RECENT_FAILED_BUFFER_SIZE) this.recentFailed.shift();
506
+ }
507
+ if (this.queue.length >= BATCH_SIZE_THRESHOLD2) {
508
+ this.flush();
509
+ return;
510
+ }
511
+ if (!this.flushTimer) this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS3);
512
+ }
513
+ /** Snapshot of the last failed requests for error-linking. Newest last. */
514
+ getRecentFailed() {
515
+ return this.recentFailed;
516
+ }
517
+ flush() {
518
+ if (this.queue.length === 0) return;
519
+ const batch = this.queue;
520
+ this.queue = [];
521
+ const payload = { requests: batch };
522
+ this.transport.send(INGEST_PATH, payload);
523
+ }
524
+ destroy() {
525
+ this.destroyed = true;
526
+ if (this.flushTimer) {
527
+ clearInterval(this.flushTimer);
528
+ this.flushTimer = null;
529
+ }
530
+ this.flush();
531
+ this.recentFailed = [];
532
+ }
533
+ /** @internal — for tests. */
534
+ getQueueSize() {
535
+ return this.queue.length;
536
+ }
537
+ };
538
+
539
+ // src/http-redact.ts
540
+ var ALWAYS_REDACT_HEADERS = /* @__PURE__ */ new Set([
541
+ "authorization",
542
+ "cookie",
543
+ "set-cookie",
544
+ "x-api-key",
545
+ "x-auth-token",
546
+ "proxy-authorization"
547
+ ]);
548
+ var ALWAYS_REDACT_QUERY = /* @__PURE__ */ new Set([
549
+ "token",
550
+ "password",
551
+ "api_key",
552
+ "apikey",
553
+ "authorization",
554
+ "auth",
555
+ "secret",
556
+ "access_token",
557
+ "refresh_token",
558
+ "session",
559
+ "sessionid",
560
+ "jwt"
561
+ ]);
562
+ var REDACTED = "[REDACTED]";
563
+ function shouldCaptureUrl(url, opts) {
564
+ if (!url) return false;
565
+ const lower = url.toLowerCase();
566
+ if (opts.allowedUrls && opts.allowedUrls.length > 0) {
567
+ return opts.allowedUrls.some((p) => matches(p, url, lower));
568
+ }
569
+ if (opts.ignoredUrls && opts.ignoredUrls.length > 0) {
570
+ return !opts.ignoredUrls.some((p) => matches(p, url, lower));
571
+ }
572
+ return true;
573
+ }
574
+ function matches(pattern, url, lower) {
575
+ if (pattern instanceof RegExp) return pattern.test(url);
576
+ if (typeof pattern !== "string") return false;
577
+ return lower.includes(pattern.toLowerCase());
578
+ }
579
+ function redactUrl(url, opts) {
580
+ if (!url) return url;
581
+ const extra = (opts.redactQueryParams ?? []).map((s) => s.toLowerCase());
582
+ const redactSet = /* @__PURE__ */ new Set([...ALWAYS_REDACT_QUERY, ...extra]);
583
+ let parsed = null;
584
+ try {
585
+ parsed = new URL(url);
586
+ } catch {
587
+ }
588
+ if (parsed) {
589
+ const params = parsed.searchParams;
590
+ let mutated = false;
591
+ const keysToRedact = [];
592
+ params.forEach((_v, k) => {
593
+ if (redactSet.has(k.toLowerCase())) keysToRedact.push(k);
594
+ });
595
+ for (const k of keysToRedact) {
596
+ params.set(k, REDACTED);
597
+ mutated = true;
598
+ }
599
+ if (mutated) parsed.search = params.toString();
600
+ return parsed.toString();
601
+ }
602
+ const qIdx = url.indexOf("?");
603
+ if (qIdx < 0) return url;
604
+ const head = url.slice(0, qIdx);
605
+ const queryAndHash = url.slice(qIdx + 1);
606
+ const hashIdx = queryAndHash.indexOf("#");
607
+ const query = hashIdx < 0 ? queryAndHash : queryAndHash.slice(0, hashIdx);
608
+ const hash = hashIdx < 0 ? "" : queryAndHash.slice(hashIdx);
609
+ const parts = query.split("&").map((pair) => {
610
+ const eq = pair.indexOf("=");
611
+ if (eq < 0) return pair;
612
+ const key = pair.slice(0, eq);
613
+ return redactSet.has(key.toLowerCase()) ? `${key}=${REDACTED}` : pair;
614
+ });
615
+ return `${head}?${parts.join("&")}${hash ? "#" + hash : ""}`;
616
+ }
617
+ function sanitizeHeaders(headers, opts) {
618
+ if (!opts.captureHeaders) return void 0;
619
+ if (!headers) return {};
620
+ const extra = (opts.redactHeaders ?? []).map((s) => s.toLowerCase());
621
+ const redactSet = /* @__PURE__ */ new Set([...ALWAYS_REDACT_HEADERS, ...extra]);
622
+ const out = {};
623
+ for (const [k, v] of Object.entries(headers)) {
624
+ if (v == null) continue;
625
+ const lower = k.toLowerCase();
626
+ out[lower] = redactSet.has(lower) ? REDACTED : Array.isArray(v) ? v.join(", ") : String(v);
627
+ }
628
+ return out;
629
+ }
630
+ function captureBody(body, enabled, maxBodyBytes) {
631
+ if (!enabled) return void 0;
632
+ if (body == null) return void 0;
633
+ let str;
634
+ if (typeof body === "string") str = body;
635
+ else if (typeof body === "number" || typeof body === "boolean") str = String(body);
636
+ else if (typeof body === "object") {
637
+ const tag = Object.prototype.toString.call(body);
638
+ if (tag !== "[object Object]" && tag !== "[object Array]") return "<binary>";
639
+ try {
640
+ str = JSON.stringify(body);
641
+ } catch {
642
+ return "<unserializable>";
643
+ }
644
+ } else {
645
+ return "<binary>";
646
+ }
647
+ if (str.length > maxBodyBytes) return str.slice(0, maxBodyBytes) + "\u2026[truncated]";
648
+ return str;
649
+ }
650
+
651
+ // src/http-instrumentation.ts
652
+ var FETCH_FLAG = "__allstak_http_fetch_patched__";
653
+ var XHR_FLAG = "__allstak_http_xhr_patched__";
654
+ var AXIOS_FLAG = /* @__PURE__ */ Symbol.for("allstak.http.axios.instrumented");
655
+ var DEFAULT_MAX_BODY = 4096;
656
+ var _currentModule = null;
657
+ var _currentOpts = null;
658
+ function currentModule() {
659
+ return _currentModule;
660
+ }
661
+ function currentOpts() {
662
+ return _currentOpts;
663
+ }
664
+ function safeCapture(ev) {
665
+ try {
666
+ currentModule()?.capture(ev);
667
+ } catch {
668
+ }
669
+ }
670
+ function bind(opts, ownIngestHost) {
671
+ return {
672
+ captureRequestBody: opts.captureRequestBody ?? false,
673
+ captureResponseBody: opts.captureResponseBody ?? false,
674
+ captureHeaders: opts.captureHeaders ?? false,
675
+ redactHeaders: opts.redactHeaders ?? [],
676
+ redactQueryParams: opts.redactQueryParams ?? [],
677
+ ignoredUrls: opts.ignoredUrls ?? [],
678
+ allowedUrls: opts.allowedUrls ?? [],
679
+ maxBodyBytes: opts.maxBodyBytes ?? DEFAULT_MAX_BODY,
680
+ ownIngestPrefix: ownIngestHost.replace(/\/$/, "")
681
+ };
682
+ }
683
+ function isOwnIngest(url, prefix) {
684
+ return !!prefix && url.startsWith(prefix);
685
+ }
686
+ function urlString(input) {
687
+ if (typeof input === "string") return input;
688
+ if (input && typeof input.href === "string") return input.href;
689
+ if (input && typeof input.url === "string") return input.url;
690
+ return String(input);
691
+ }
692
+ function safeByteLength(s) {
693
+ if (s == null) return void 0;
694
+ if (typeof s === "string") {
695
+ let n = 0;
696
+ for (let i = 0; i < s.length; i++) {
697
+ const c = s.charCodeAt(i);
698
+ if (c < 128) n += 1;
699
+ else if (c < 2048) n += 2;
700
+ else if (c >= 55296 && c <= 56319) {
701
+ n += 4;
702
+ i += 1;
703
+ } else n += 3;
704
+ }
705
+ return n;
706
+ }
707
+ return void 0;
708
+ }
709
+ function headersToObject(h) {
710
+ if (!h) return {};
711
+ if (typeof h.entries === "function") {
712
+ const out = {};
713
+ for (const [k, v] of h.entries()) out[String(k).toLowerCase()] = String(v);
714
+ return out;
715
+ }
716
+ if (typeof h === "object") {
717
+ const out = {};
718
+ for (const [k, v] of Object.entries(h)) {
719
+ if (v == null) continue;
720
+ out[String(k).toLowerCase()] = Array.isArray(v) ? v.join(", ") : String(v);
721
+ }
722
+ return out;
723
+ }
724
+ return {};
725
+ }
726
+ function patchFetch() {
727
+ const g = globalThis;
728
+ if (typeof g.fetch !== "function") return;
729
+ if (g.fetch[FETCH_FLAG]) return;
730
+ const original = g.fetch;
731
+ const wrapped = async function(input, init) {
732
+ const opts = currentOpts();
733
+ if (!opts || !currentModule()) {
734
+ return original.call(this, input, init);
735
+ }
736
+ const rawUrl = urlString(input);
737
+ const sanitizedUrl = redactUrl(rawUrl, opts);
738
+ const method = (init?.method || input && typeof input === "object" && input.method || "GET").toUpperCase();
739
+ if (isOwnIngest(rawUrl, opts.ownIngestPrefix) || !shouldCaptureUrl(rawUrl, opts)) {
740
+ return original.call(this, input, init);
741
+ }
742
+ const start = Date.now();
743
+ const reqHeaders = sanitizeHeaders(headersToObject(init?.headers ?? (input && input.headers)), opts);
744
+ const reqBody = captureBody(init?.body, opts.captureRequestBody, opts.maxBodyBytes);
745
+ const reqSize = safeByteLength(typeof init?.body === "string" ? init.body : void 0);
746
+ let response;
747
+ try {
748
+ response = await original.call(this, input, init);
749
+ } catch (err) {
750
+ safeCapture({
751
+ type: "http_request",
752
+ method,
753
+ url: sanitizedUrl,
754
+ statusCode: 0,
755
+ durationMs: Date.now() - start,
756
+ requestBody: reqBody,
757
+ requestHeaders: reqHeaders,
758
+ requestSize: reqSize,
759
+ error: String(err?.message ?? err)
760
+ });
761
+ throw err;
762
+ }
763
+ const durationMs = Date.now() - start;
764
+ let respBody;
765
+ let respSize;
766
+ let respHeaders;
767
+ try {
768
+ respHeaders = sanitizeHeaders(headersToObject(response.headers), opts);
769
+ const lenHeader = typeof response.headers?.get === "function" ? response.headers.get("content-length") : null;
770
+ if (lenHeader) respSize = parseInt(lenHeader, 10) || void 0;
771
+ if (opts.captureResponseBody && typeof response.clone === "function") {
772
+ try {
773
+ const cloned = response.clone();
774
+ const text = await cloned.text();
775
+ respBody = captureBody(text, true, opts.maxBodyBytes);
776
+ if (respSize == null) respSize = safeByteLength(text);
777
+ } catch {
778
+ }
779
+ }
780
+ } catch {
781
+ }
782
+ safeCapture({
783
+ type: "http_request",
784
+ method,
785
+ url: sanitizedUrl,
786
+ statusCode: response.status,
787
+ durationMs,
788
+ requestBody: reqBody,
789
+ requestHeaders: reqHeaders,
790
+ requestSize: reqSize,
791
+ responseBody: respBody,
792
+ responseHeaders: respHeaders,
793
+ responseSize: respSize
794
+ });
795
+ return response;
796
+ };
797
+ wrapped[FETCH_FLAG] = true;
798
+ g.fetch = wrapped;
799
+ }
800
+ function patchXhr() {
801
+ const g = globalThis;
802
+ const X = g.XMLHttpRequest;
803
+ if (!X || X.prototype[XHR_FLAG]) return;
804
+ const origOpen = X.prototype.open;
805
+ const origSend = X.prototype.send;
806
+ const origSetRequestHeader = X.prototype.setRequestHeader;
807
+ X.prototype.open = function(method, url, ...rest) {
808
+ this.__allstak_method__ = method;
809
+ this.__allstak_url__ = url;
810
+ this.__allstak_headers__ = {};
811
+ return origOpen.call(this, method, url, ...rest);
812
+ };
813
+ X.prototype.setRequestHeader = function(name, value) {
814
+ try {
815
+ this.__allstak_headers__[String(name).toLowerCase()] = String(value);
816
+ } catch {
817
+ }
818
+ return origSetRequestHeader.call(this, name, value);
819
+ };
820
+ X.prototype.send = function(body) {
821
+ const opts = currentOpts();
822
+ if (!opts || !currentModule()) return origSend.call(this, body);
823
+ const start = Date.now();
824
+ const method = String(this.__allstak_method__ || "GET").toUpperCase();
825
+ const rawUrl = String(this.__allstak_url__ || "");
826
+ const sanitizedUrl = redactUrl(rawUrl, opts);
827
+ if (isOwnIngest(rawUrl, opts.ownIngestPrefix) || !shouldCaptureUrl(rawUrl, opts)) {
828
+ return origSend.call(this, body);
829
+ }
830
+ const reqHeaders = sanitizeHeaders(this.__allstak_headers__, opts);
831
+ const reqBody = captureBody(body, opts.captureRequestBody, opts.maxBodyBytes);
832
+ const reqSize = safeByteLength(typeof body === "string" ? body : void 0);
833
+ const finish = (statusCode, error) => {
834
+ const durationMs = Date.now() - start;
835
+ let respHeaders;
836
+ let respBody;
837
+ let respSize;
838
+ try {
839
+ const liveOpts = currentOpts() ?? opts;
840
+ if (liveOpts.captureHeaders && typeof this.getAllResponseHeaders === "function") {
841
+ const raw = this.getAllResponseHeaders() || "";
842
+ const dict = {};
843
+ for (const line of raw.split(/\r?\n/)) {
844
+ const idx = line.indexOf(":");
845
+ if (idx > 0) dict[line.slice(0, idx).trim().toLowerCase()] = line.slice(idx + 1).trim();
846
+ }
847
+ respHeaders = sanitizeHeaders(dict, liveOpts);
848
+ }
849
+ if (liveOpts.captureResponseBody) {
850
+ const text = this.responseText;
851
+ if (typeof text === "string") {
852
+ respBody = captureBody(text, true, liveOpts.maxBodyBytes);
853
+ respSize = safeByteLength(text);
854
+ }
855
+ }
856
+ } catch {
857
+ }
858
+ safeCapture({
859
+ type: "http_request",
860
+ method,
861
+ url: sanitizedUrl,
862
+ statusCode,
863
+ durationMs,
864
+ requestBody: reqBody,
865
+ requestHeaders: reqHeaders,
866
+ requestSize: reqSize,
867
+ responseBody: respBody,
868
+ responseHeaders: respHeaders,
869
+ responseSize: respSize,
870
+ error
871
+ });
872
+ };
873
+ this.addEventListener?.("load", () => finish(this.status || 0));
874
+ this.addEventListener?.("error", () => finish(0, "network"));
875
+ this.addEventListener?.("abort", () => finish(0, "abort"));
876
+ this.addEventListener?.("timeout", () => finish(0, "timeout"));
877
+ return origSend.call(this, body);
878
+ };
879
+ X.prototype[XHR_FLAG] = true;
880
+ }
881
+ function instrumentAxiosInstance(axiosInstance, module, opts) {
882
+ if (!axiosInstance || typeof axiosInstance.interceptors !== "object") return axiosInstance;
883
+ if (axiosInstance[AXIOS_FLAG]) return axiosInstance;
884
+ axiosInstance[AXIOS_FLAG] = true;
885
+ const reqStarts = /* @__PURE__ */ new WeakMap();
886
+ axiosInstance.interceptors.request.use((config) => {
887
+ try {
888
+ const rawUrl = (config.baseURL ? config.baseURL.replace(/\/$/, "") : "") + (config.url || "");
889
+ reqStarts.set(config, {
890
+ start: Date.now(),
891
+ method: String(config.method || "GET").toUpperCase(),
892
+ rawUrl
893
+ });
894
+ } catch {
895
+ }
896
+ return config;
897
+ });
898
+ const finalize = (cfg, statusCode, response, error) => {
899
+ const meta = reqStarts.get(cfg);
900
+ if (!meta) return;
901
+ reqStarts.delete(cfg);
902
+ if (isOwnIngest(meta.rawUrl, opts.ownIngestPrefix)) return;
903
+ if (!shouldCaptureUrl(meta.rawUrl, opts)) return;
904
+ const sanitizedUrl = redactUrl(meta.rawUrl, opts);
905
+ const reqHeaders = sanitizeHeaders(headersToObject(cfg.headers), opts);
906
+ const reqBody = captureBody(cfg.data, opts.captureRequestBody, opts.maxBodyBytes);
907
+ const respHeaders = sanitizeHeaders(headersToObject(response?.headers), opts);
908
+ const respBody = captureBody(response?.data, opts.captureResponseBody, opts.maxBodyBytes);
909
+ try {
910
+ module.capture({
911
+ type: "http_request",
912
+ method: meta.method,
913
+ url: sanitizedUrl,
914
+ statusCode,
915
+ durationMs: Date.now() - meta.start,
916
+ requestBody: reqBody,
917
+ requestHeaders: reqHeaders,
918
+ responseBody: respBody,
919
+ responseHeaders: respHeaders,
920
+ error
921
+ });
922
+ } catch {
923
+ }
924
+ };
925
+ axiosInstance.interceptors.response.use(
926
+ (response) => {
927
+ finalize(response.config, response.status);
928
+ return response;
929
+ },
930
+ (err) => {
931
+ const cfg = err?.config;
932
+ const status = err?.response?.status ?? 0;
933
+ finalize(cfg, status, err?.response, String(err?.message ?? err));
934
+ throw err;
935
+ }
936
+ );
937
+ return axiosInstance;
938
+ }
939
+ function tryAutoInstrumentAxios(module, opts) {
940
+ try {
941
+ const axios = globalThis.require?.("axios") ?? null;
942
+ if (axios) instrumentAxiosInstance(axios.default ?? axios, module, opts);
943
+ } catch {
944
+ }
945
+ }
946
+ function installHttpInstrumentation(module, options, ownIngestHost) {
947
+ const bound = bind(options, ownIngestHost);
948
+ _currentModule = module;
949
+ _currentOpts = bound;
950
+ try {
951
+ patchFetch();
952
+ } catch {
953
+ }
954
+ try {
955
+ patchXhr();
956
+ } catch {
957
+ }
958
+ try {
959
+ tryAutoInstrumentAxios(module, bound);
960
+ } catch {
961
+ }
962
+ return {
963
+ instrumentAxios: (axios) => instrumentAxiosInstance(axios, module, bound)
964
+ };
965
+ }
966
+
967
+ // src/client.ts
968
+ var INGEST_HOST = "https://api.allstak.sa";
969
+ var SDK_NAME = "allstak-react-native";
970
+ var SDK_VERSION = "0.3.0";
971
+ var ERRORS_PATH = "/ingest/v1/errors";
972
+ var LOGS_PATH = "/ingest/v1/logs";
973
+ var VALID_BREADCRUMB_TYPES = /* @__PURE__ */ new Set(["http", "log", "ui", "navigation", "query", "default"]);
974
+ var VALID_BREADCRUMB_LEVELS = /* @__PURE__ */ new Set(["info", "warn", "error", "debug"]);
975
+ var DEFAULT_MAX_BREADCRUMBS = 50;
976
+ function frameToString(f) {
977
+ const fn = f.function && f.function.length > 0 ? f.function : "<anonymous>";
978
+ const file = f.filename || f.absPath || "<anonymous>";
979
+ return ` at ${fn} (${file}:${f.lineno ?? 0}:${f.colno ?? 0})`;
980
+ }
981
+ function generateId() {
982
+ const hex = (n) => Math.floor(Math.random() * n).toString(16).padStart(1, "0");
983
+ const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
984
+ return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
985
+ }
986
+ var AllStakClient = class {
987
+ constructor(config) {
988
+ this.breadcrumbs = [];
989
+ this.scopeStack = [];
990
+ this.replay = null;
991
+ this.httpRequests = null;
992
+ this._instrumentAxios = null;
993
+ if (!config.apiKey) {
994
+ throw new Error("AllStak: config.apiKey is required");
995
+ }
996
+ this.config = { ...config };
997
+ if (!this.config.environment) this.config.environment = "production";
998
+ if (!this.config.sdkName) this.config.sdkName = SDK_NAME;
999
+ if (!this.config.sdkVersion) this.config.sdkVersion = SDK_VERSION;
1000
+ if (!this.config.platform) this.config.platform = "react-native";
1001
+ this.sessionId = generateId();
1002
+ this.maxBreadcrumbs = config.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS;
1003
+ const baseUrl = (config.host ?? INGEST_HOST).replace(/\/$/, "");
1004
+ this.transport = new HttpTransport(baseUrl, config.apiKey);
1005
+ this.tracing = new TracingModule(this.transport, {
1006
+ service: config.service ?? config.release ?? "",
1007
+ environment: this.config.environment ?? "production",
1008
+ tracesSampleRate: config.tracesSampleRate
1009
+ });
1010
+ if (config.replay && (config.replay.enabled ?? true)) {
1011
+ try {
1012
+ this.replay = new ReplaySurrogate(this.transport, this.sessionId, config.replay);
1013
+ this.replay.start();
1014
+ } catch {
1015
+ }
1016
+ }
1017
+ if (config.enableHttpTracking) {
1018
+ try {
1019
+ this.httpRequests = new HttpRequestModule(this.transport);
1020
+ this.httpRequests.setDefaults({
1021
+ environment: this.config.environment,
1022
+ release: this.config.release,
1023
+ dist: this.config.dist,
1024
+ platform: this.config.platform,
1025
+ sdkName: this.config.sdkName,
1026
+ sdkVersion: this.config.sdkVersion
1027
+ });
1028
+ const { instrumentAxios } = installHttpInstrumentation(
1029
+ this.httpRequests,
1030
+ config.httpTracking ?? {},
1031
+ baseUrl
1032
+ );
1033
+ this._instrumentAxios = instrumentAxios;
1034
+ } catch {
1035
+ }
1036
+ }
1037
+ }
1038
+ /** Access the replay surrogate (or null if not initialized / sampled out). */
1039
+ getReplay() {
1040
+ return this.replay;
1041
+ }
1042
+ /** Manually instrument an axios instance. No-op when HTTP tracking is off. */
1043
+ instrumentAxios(axios) {
1044
+ return this._instrumentAxios ? this._instrumentAxios(axios) : axios;
1045
+ }
1046
+ /** Snapshot of recent failed HTTP requests for error-linking. */
1047
+ getRecentFailedHttp() {
1048
+ return this.httpRequests?.getRecentFailed() ?? [];
1049
+ }
1050
+ // ── Public API ────────────────────────────────────────────────────
1051
+ captureException(error, context) {
1052
+ if (!this.passesSampleRate()) return;
1053
+ const frames = parseStack(error.stack).map((f) => ({
1054
+ ...f,
1055
+ platform: this.config.platform
1056
+ }));
1057
+ const stackTrace = frames.length > 0 ? frames.map(frameToString) : void 0;
1058
+ const currentBreadcrumbs = this.breadcrumbs.length > 0 ? [...this.breadcrumbs] : void 0;
1059
+ this.breadcrumbs = [];
1060
+ const exceptionClass = (error.name && error.name !== "Error" ? error.name : void 0) || error.constructor?.name || "Error";
1061
+ const eff = this.effective();
1062
+ const traceContext = {};
1063
+ const traceId = this.tracing.getTraceId();
1064
+ if (traceId) traceContext.traceId = traceId;
1065
+ const spanId = this.tracing.getCurrentSpanId();
1066
+ if (spanId) traceContext.spanId = spanId;
1067
+ const recentFailed = this.httpRequests?.getRecentFailed() ?? [];
1068
+ if (recentFailed.length > 0) {
1069
+ traceContext["http.recentFailed"] = recentFailed.map((r) => ({
1070
+ method: r.method,
1071
+ url: r.url,
1072
+ statusCode: r.statusCode,
1073
+ durationMs: r.durationMs,
1074
+ error: r.error
1075
+ }));
1076
+ }
1077
+ const payload = {
1078
+ exceptionClass,
1079
+ message: error.message,
1080
+ stackTrace,
1081
+ frames: frames.length > 0 ? frames : void 0,
1082
+ platform: this.config.platform,
1083
+ sdkName: this.config.sdkName,
1084
+ sdkVersion: this.config.sdkVersion,
1085
+ dist: this.config.dist,
1086
+ level: eff.level ?? "error",
1087
+ environment: this.config.environment,
1088
+ release: this.config.release,
1089
+ sessionId: this.sessionId,
1090
+ user: eff.user,
1091
+ metadata: { ...this.buildMetadata(context), ...traceContext },
1092
+ breadcrumbs: currentBreadcrumbs,
1093
+ fingerprint: eff.fingerprint
1094
+ };
1095
+ this.sendThroughBeforeSend(payload);
1096
+ }
1097
+ /** Start a new span. Auto-parented to any currently-active span. */
1098
+ startSpan(operation, options) {
1099
+ return this.tracing.startSpan(operation, options);
1100
+ }
1101
+ /** Get (and lazily create) the active trace ID. */
1102
+ getTraceId() {
1103
+ return this.tracing.getTraceId();
1104
+ }
1105
+ /** Override the active trace ID, e.g. from an inbound request header. */
1106
+ setTraceId(traceId) {
1107
+ this.tracing.setTraceId(traceId);
1108
+ }
1109
+ /** ID of the currently-active span, or null. */
1110
+ getCurrentSpanId() {
1111
+ return this.tracing.getCurrentSpanId();
1112
+ }
1113
+ /** Reset the trace ID and the active span stack. */
1114
+ resetTrace() {
1115
+ this.tracing.resetTrace();
1116
+ }
1117
+ captureMessage(message, level = "info", options = {}) {
1118
+ const as = options.as ?? (level === "fatal" || level === "error" ? "both" : "log");
1119
+ if (as === "log" || as === "both") {
1120
+ this.sendLog(level === "warning" ? "warn" : level, message);
1121
+ }
1122
+ if (as === "error" || as === "both") {
1123
+ if (!this.passesSampleRate()) return;
1124
+ const eff = this.effective();
1125
+ const payload = {
1126
+ exceptionClass: "Message",
1127
+ message,
1128
+ platform: this.config.platform,
1129
+ sdkName: this.config.sdkName,
1130
+ sdkVersion: this.config.sdkVersion,
1131
+ dist: this.config.dist,
1132
+ level,
1133
+ environment: this.config.environment,
1134
+ release: this.config.release,
1135
+ sessionId: this.sessionId,
1136
+ user: eff.user,
1137
+ metadata: this.buildMetadata(),
1138
+ fingerprint: eff.fingerprint
1139
+ };
1140
+ this.sendThroughBeforeSend(payload);
1141
+ }
1142
+ }
1143
+ addBreadcrumb(type, message, level, data) {
1144
+ const crumb = {
1145
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1146
+ type: VALID_BREADCRUMB_TYPES.has(type) ? type : "default",
1147
+ message,
1148
+ level: level && VALID_BREADCRUMB_LEVELS.has(level) ? level : "info",
1149
+ ...data ? { data } : {}
1150
+ };
1151
+ if (this.breadcrumbs.length >= this.maxBreadcrumbs) this.breadcrumbs.shift();
1152
+ this.breadcrumbs.push(crumb);
1153
+ }
1154
+ clearBreadcrumbs() {
1155
+ this.breadcrumbs = [];
1156
+ }
1157
+ setUser(user) {
1158
+ this.config.user = user;
1159
+ }
1160
+ setTag(key, value) {
1161
+ if (!this.config.tags) this.config.tags = {};
1162
+ this.config.tags[key] = value;
1163
+ }
1164
+ /** Bulk-set tags. Merges with existing tags. */
1165
+ setTags(tags) {
1166
+ if (!this.config.tags) this.config.tags = {};
1167
+ Object.assign(this.config.tags, tags);
1168
+ }
1169
+ /** Set a single extra value. */
1170
+ setExtra(key, value) {
1171
+ if (!this.config.extras) this.config.extras = {};
1172
+ this.config.extras[key] = value;
1173
+ }
1174
+ /** Bulk-set extras. Merges with existing extras. */
1175
+ setExtras(extras) {
1176
+ if (!this.config.extras) this.config.extras = {};
1177
+ Object.assign(this.config.extras, extras);
1178
+ }
1179
+ /**
1180
+ * Attach a named context bag (e.g. `app`, `device`, `runtime`) — appears
1181
+ * under `metadata['context.<name>']` on every subsequent event. Pass
1182
+ * `null` to remove a previously-set context.
1183
+ */
1184
+ setContext(name, ctx) {
1185
+ if (!this.config.contexts) this.config.contexts = {};
1186
+ if (ctx === null) delete this.config.contexts[name];
1187
+ else this.config.contexts[name] = ctx;
1188
+ }
1189
+ /**
1190
+ * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
1191
+ * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
1192
+ */
1193
+ flush(timeoutMs) {
1194
+ return this.transport.flush(timeoutMs);
1195
+ }
1196
+ /** Set the default severity level applied to subsequent captures. */
1197
+ setLevel(level) {
1198
+ this.config.level = level;
1199
+ }
1200
+ /**
1201
+ * Set a custom grouping fingerprint applied to subsequent events.
1202
+ * Pass `null` or an empty array to clear and revert to default grouping.
1203
+ */
1204
+ setFingerprint(fingerprint) {
1205
+ this.config.fingerprint = fingerprint && fingerprint.length > 0 ? fingerprint : void 0;
1206
+ }
1207
+ setIdentity(identity) {
1208
+ if (identity.sdkName) this.config.sdkName = identity.sdkName;
1209
+ if (identity.sdkVersion) this.config.sdkVersion = identity.sdkVersion;
1210
+ if (identity.platform) this.config.platform = identity.platform;
1211
+ if (identity.dist) this.config.dist = identity.dist;
1212
+ }
1213
+ getSessionId() {
1214
+ return this.sessionId;
1215
+ }
1216
+ getConfig() {
1217
+ return this.config;
1218
+ }
1219
+ destroy() {
1220
+ this.tracing.destroy();
1221
+ if (this.replay) {
1222
+ this.replay.destroy();
1223
+ this.replay = null;
1224
+ }
1225
+ if (this.httpRequests) {
1226
+ this.httpRequests.destroy();
1227
+ this.httpRequests = null;
1228
+ }
1229
+ this._instrumentAxios = null;
1230
+ this.breadcrumbs = [];
1231
+ }
1232
+ // ── Internal ──────────────────────────────────────────────────────
1233
+ sendLog(level, message) {
1234
+ this.transport.send(LOGS_PATH, {
1235
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1236
+ level,
1237
+ message,
1238
+ sessionId: this.sessionId,
1239
+ environment: this.config.environment,
1240
+ release: this.config.release,
1241
+ platform: this.config.platform,
1242
+ sdkName: this.config.sdkName,
1243
+ sdkVersion: this.config.sdkVersion,
1244
+ metadata: this.buildMetadata()
1245
+ });
1246
+ }
1247
+ passesSampleRate() {
1248
+ const r = this.config.sampleRate;
1249
+ if (typeof r !== "number" || r >= 1) return true;
1250
+ if (r <= 0) return false;
1251
+ return Math.random() < r;
1252
+ }
1253
+ /**
1254
+ * Returns the effective config layer = base config + every scope on the
1255
+ * stack. Inner code reads from this instead of `this.config` directly so
1256
+ * scope-only overrides (set inside `withScope`) flow into the wire
1257
+ * payload without leaking out of the callback.
1258
+ */
1259
+ effective() {
1260
+ return mergeScopes(this.config, this.scopeStack);
1261
+ }
1262
+ buildMetadata(perCallContext) {
1263
+ const eff = this.effective();
1264
+ const out = {
1265
+ ...this.releaseTags(),
1266
+ ...eff.tags,
1267
+ ...eff.extras ?? {},
1268
+ ...perCallContext ?? {}
1269
+ };
1270
+ if (eff.contexts) {
1271
+ for (const [name, ctx] of Object.entries(eff.contexts)) {
1272
+ out[`context.${name}`] = ctx;
1273
+ }
1274
+ }
1275
+ return out;
1276
+ }
1277
+ /**
1278
+ * Run `callback` with a fresh, temporary {@link Scope} that isolates
1279
+ * any user/tag/extra/context/fingerprint/level it sets. The scope is
1280
+ * popped automatically when the callback returns or throws — including
1281
+ * for `Promise`-returning callbacks (the pop runs in `.finally`).
1282
+ *
1283
+ * Use this on the server to attach per-request context without leaking
1284
+ * across concurrent requests.
1285
+ */
1286
+ withScope(callback) {
1287
+ const scope = new Scope();
1288
+ this.scopeStack.push(scope);
1289
+ let popped = false;
1290
+ const pop = () => {
1291
+ if (!popped) {
1292
+ popped = true;
1293
+ this.scopeStack.pop();
1294
+ }
1295
+ };
1296
+ try {
1297
+ const result = callback(scope);
1298
+ if (result && typeof result.then === "function") {
1299
+ return result.then(
1300
+ (v) => {
1301
+ pop();
1302
+ return v;
1303
+ },
1304
+ (e) => {
1305
+ pop();
1306
+ throw e;
1307
+ }
1308
+ );
1309
+ }
1310
+ pop();
1311
+ return result;
1312
+ } catch (err) {
1313
+ pop();
1314
+ throw err;
1315
+ }
1316
+ }
1317
+ /** Direct access to the topmost active scope, or null. @internal */
1318
+ getCurrentScope() {
1319
+ return this.scopeStack[this.scopeStack.length - 1] ?? null;
1320
+ }
1321
+ async sendThroughBeforeSend(payload) {
1322
+ let final = payload;
1323
+ if (this.config.beforeSend) {
1324
+ try {
1325
+ final = await this.config.beforeSend(payload);
1326
+ } catch {
1327
+ final = payload;
1328
+ }
1329
+ }
1330
+ if (!final) return;
1331
+ this.transport.send(ERRORS_PATH, final);
1332
+ }
1333
+ releaseTags() {
1334
+ const out = {};
1335
+ if (this.config.sdkName) out["sdk.name"] = this.config.sdkName;
1336
+ if (this.config.sdkVersion) out["sdk.version"] = this.config.sdkVersion;
1337
+ if (this.config.platform) out["platform"] = this.config.platform;
1338
+ if (this.config.dist) out["dist"] = this.config.dist;
1339
+ if (this.config.commitSha) out["commit.sha"] = this.config.commitSha;
1340
+ if (this.config.branch) out["commit.branch"] = this.config.branch;
1341
+ return out;
1342
+ }
1343
+ };
1344
+ var instance = null;
1345
+ function ensureInit() {
1346
+ if (!instance) throw new Error("AllStak.init() must be called before using the SDK");
1347
+ return instance;
1348
+ }
1349
+ function __safeAddBreadcrumbForInstrumentation(type, message, level, data) {
1350
+ try {
1351
+ instance?.addBreadcrumb(type, message, level, data);
1352
+ } catch {
1353
+ }
1354
+ }
1355
+ var AllStak = {
1356
+ init(config) {
1357
+ if (instance) instance.destroy();
1358
+ instance = new AllStakClient(config);
1359
+ return instance;
1360
+ },
1361
+ captureException(error, context) {
1362
+ ensureInit().captureException(error, context);
1363
+ },
1364
+ captureMessage(message, level = "info", options) {
1365
+ ensureInit().captureMessage(message, level, options);
1366
+ },
1367
+ addBreadcrumb(type, message, level, data) {
1368
+ ensureInit().addBreadcrumb(type, message, level, data);
1369
+ },
1370
+ clearBreadcrumbs() {
1371
+ ensureInit().clearBreadcrumbs();
1372
+ },
1373
+ setUser(user) {
1374
+ ensureInit().setUser(user);
1375
+ },
1376
+ setTag(key, value) {
1377
+ ensureInit().setTag(key, value);
1378
+ },
1379
+ setTags(tags) {
1380
+ ensureInit().setTags(tags);
1381
+ },
1382
+ setExtra(key, value) {
1383
+ ensureInit().setExtra(key, value);
1384
+ },
1385
+ setExtras(extras) {
1386
+ ensureInit().setExtras(extras);
1387
+ },
1388
+ setContext(name, ctx) {
1389
+ ensureInit().setContext(name, ctx);
1390
+ },
1391
+ setLevel(level) {
1392
+ ensureInit().setLevel(level);
1393
+ },
1394
+ setFingerprint(fingerprint) {
1395
+ ensureInit().setFingerprint(fingerprint);
1396
+ },
1397
+ flush(timeoutMs) {
1398
+ return ensureInit().flush(timeoutMs);
1399
+ },
1400
+ setIdentity(identity) {
1401
+ ensureInit().setIdentity(identity);
1402
+ },
1403
+ /**
1404
+ * Run `callback` with a fresh scoped context. Any user/tag/extra/context/
1405
+ * fingerprint/level set on the passed `Scope` is visible only inside the
1406
+ * callback (and any captures made within it). Pop is automatic, including
1407
+ * for async callbacks and thrown errors.
1408
+ */
1409
+ withScope(callback) {
1410
+ return ensureInit().withScope(callback);
1411
+ },
1412
+ startSpan(operation, options) {
1413
+ return ensureInit().startSpan(operation, options);
1414
+ },
1415
+ getTraceId() {
1416
+ return ensureInit().getTraceId();
1417
+ },
1418
+ setTraceId(traceId) {
1419
+ ensureInit().setTraceId(traceId);
1420
+ },
1421
+ getCurrentSpanId() {
1422
+ return ensureInit().getCurrentSpanId();
1423
+ },
1424
+ resetTrace() {
1425
+ ensureInit().resetTrace();
1426
+ },
1427
+ /** Access the privacy-first replay surrogate (or null if disabled / sampled out). */
1428
+ getReplay() {
1429
+ return ensureInit().getReplay();
1430
+ },
1431
+ /** Manually instrument an axios instance. No-op when HTTP tracking is off. */
1432
+ instrumentAxios(axios) {
1433
+ return ensureInit().instrumentAxios(axios);
1434
+ },
1435
+ getSessionId() {
1436
+ return ensureInit().getSessionId();
1437
+ },
1438
+ getConfig() {
1439
+ return instance?.getConfig() ?? null;
1440
+ },
1441
+ destroy() {
1442
+ instance?.destroy();
1443
+ instance = null;
1444
+ },
1445
+ /** @internal — exposed for testing */
1446
+ _getInstance() {
1447
+ return instance;
1448
+ }
1449
+ };
1450
+
1451
+ // src/auto-breadcrumbs.ts
1452
+ var FETCH_FLAG2 = "__allstak_fetch_patched__";
1453
+ var CONSOLE_FLAG = "__allstak_console_patched__";
1454
+ function instrumentFetch(addBreadcrumb, ownBaseUrl) {
1455
+ const g = globalThis;
1456
+ if (typeof g.fetch !== "function") return;
1457
+ if (g.fetch[FETCH_FLAG2]) return;
1458
+ const originalFetch = g.fetch;
1459
+ const wrapped = async function(input, init) {
1460
+ const method = (init?.method || input && typeof input === "object" && input.method || "GET").toUpperCase();
1461
+ let url;
1462
+ if (typeof input === "string") url = input;
1463
+ else if (input && typeof input.href === "string") url = input.href;
1464
+ else if (input && typeof input.url === "string") url = input.url;
1465
+ else url = String(input);
1466
+ const safePath = url.split("?")[0];
1467
+ const isOwnIngest2 = !!(ownBaseUrl && url.startsWith(ownBaseUrl));
1468
+ const start = Date.now();
1469
+ try {
1470
+ const response = await originalFetch.call(this, input, init);
1471
+ const durationMs = Date.now() - start;
1472
+ if (!isOwnIngest2) {
1473
+ addBreadcrumb(
1474
+ "http",
1475
+ `${method} ${safePath} -> ${response.status}`,
1476
+ response.status >= 400 ? "error" : "info",
1477
+ { method, url: safePath, statusCode: response.status, durationMs }
1478
+ );
1479
+ }
1480
+ return response;
1481
+ } catch (err) {
1482
+ const durationMs = Date.now() - start;
1483
+ if (!isOwnIngest2) {
1484
+ addBreadcrumb("http", `${method} ${safePath} -> failed`, "error", {
1485
+ method,
1486
+ url: safePath,
1487
+ error: String(err),
1488
+ durationMs
1489
+ });
1490
+ }
1491
+ throw err;
1492
+ }
1493
+ };
1494
+ wrapped[FETCH_FLAG2] = true;
1495
+ g.fetch = wrapped;
1496
+ }
1497
+ function instrumentConsole(addBreadcrumb) {
1498
+ if (typeof console === "undefined") return;
1499
+ if (console[CONSOLE_FLAG]) return;
1500
+ const origWarn = console.warn;
1501
+ const origError = console.error;
1502
+ console.warn = function(...args) {
1503
+ try {
1504
+ addBreadcrumb("log", args.map(safeString).join(" "), "warn");
1505
+ } catch {
1506
+ }
1507
+ return origWarn.apply(console, args);
1508
+ };
1509
+ console.error = function(...args) {
1510
+ try {
1511
+ addBreadcrumb("log", args.map(safeString).join(" "), "error");
1512
+ } catch {
1513
+ }
1514
+ return origError.apply(console, args);
1515
+ };
1516
+ console[CONSOLE_FLAG] = true;
1517
+ }
1518
+ function safeString(v) {
1519
+ if (v == null) return String(v);
1520
+ if (typeof v === "string") return v;
1521
+ if (v instanceof Error) return `${v.name}: ${v.message}`;
1522
+ try {
1523
+ return typeof v === "object" ? JSON.stringify(v) : String(v);
1524
+ } catch {
1525
+ return Object.prototype.toString.call(v);
1526
+ }
1527
+ }
1528
+
1529
+ // src/architecture.ts
1530
+ function detectArchitecture() {
1531
+ const g = globalThis;
1532
+ const newArchitecture = typeof g.__turboModuleProxy !== "undefined";
1533
+ const bridgeless = typeof g.RN$Bridgeless !== "undefined" && !!g.RN$Bridgeless;
1534
+ const hermes = typeof g.HermesInternal !== "undefined";
1535
+ let tag = "unknown";
1536
+ if (newArchitecture) tag = "new-arch";
1537
+ else if (typeof g.nativeFlushQueueImmediate === "function") tag = "old-arch";
1538
+ return { newArchitecture, bridgeless, hermes, tag };
1539
+ }
1540
+ function applyArchitectureTags(setTag) {
1541
+ const info = detectArchitecture();
1542
+ try {
1543
+ setTag("rn.architecture", info.tag);
1544
+ setTag("rn.bridgeless", String(info.bridgeless));
1545
+ setTag("rn.hermes", String(info.hermes));
1546
+ } catch {
1547
+ }
1548
+ return info;
1549
+ }
1550
+
1551
+ // src/navigation.ts
1552
+ var NAV_FLAG = /* @__PURE__ */ Symbol.for("allstak.nav.subscribed");
1553
+ var LINKING_FLAG = "__allstak_linking_patched__";
1554
+ function instrumentReactNavigation(navigationRef, options = {}) {
1555
+ if (!navigationRef || typeof navigationRef.addListener !== "function") {
1556
+ return () => {
1557
+ };
1558
+ }
1559
+ const ref = navigationRef;
1560
+ if (ref[NAV_FLAG]) return () => {
1561
+ };
1562
+ ref[NAV_FLAG] = true;
1563
+ const safeKeys = options.safeParams ?? [];
1564
+ const forwardToReplay = options.forwardToReplay !== false;
1565
+ const filterParams = (params) => {
1566
+ const out = {};
1567
+ if (!params) return out;
1568
+ for (const key of safeKeys) if (key in params) out[key] = params[key];
1569
+ return out;
1570
+ };
1571
+ let last = navigationRef.getCurrentRoute?.()?.name;
1572
+ const unsub = navigationRef.addListener("state", () => {
1573
+ const route = navigationRef.getCurrentRoute?.();
1574
+ const next = route?.name;
1575
+ if (!next || next === last) return;
1576
+ const safe = filterParams(route?.params);
1577
+ try {
1578
+ AllStak.addBreadcrumb(
1579
+ "navigation",
1580
+ `${last ?? "<start>"} -> ${next}`,
1581
+ "info",
1582
+ { from: last, to: next, params: safe }
1583
+ );
1584
+ } catch {
1585
+ }
1586
+ if (forwardToReplay) {
1587
+ try {
1588
+ const replay = AllStak.getReplay?.();
1589
+ replay?.recordScreenView?.(next, route?.params);
1590
+ } catch {
1591
+ }
1592
+ }
1593
+ last = next;
1594
+ });
1595
+ return () => {
1596
+ try {
1597
+ unsub?.();
1598
+ } catch {
1599
+ }
1600
+ ref[NAV_FLAG] = false;
1601
+ };
1602
+ }
1603
+ function instrumentNavigationFromLinking() {
1604
+ try {
1605
+ const rn = __require("react-native");
1606
+ const Linking = rn?.Linking;
1607
+ if (!Linking || typeof Linking.addEventListener !== "function") return;
1608
+ if (Linking[LINKING_FLAG]) return;
1609
+ Linking.addEventListener("url", (ev) => {
1610
+ const url = typeof ev?.url === "string" ? ev.url : "";
1611
+ if (!url) return;
1612
+ try {
1613
+ AllStak.addBreadcrumb("navigation", `deep-link: ${url.split("?")[0]}`, "info", { url });
1614
+ } catch {
1615
+ }
1616
+ });
1617
+ Linking[LINKING_FLAG] = true;
1618
+ } catch {
1619
+ }
1620
+ }
1621
+
1
1622
  // src/index.ts
2
- import { installReactNative, AllStak } from "@allstak/js/react-native";
1623
+ function instrumentXmlHttpRequest() {
1624
+ const flag = "__allstak_xhr_patched__";
1625
+ const X = globalThis.XMLHttpRequest;
1626
+ if (!X || X.prototype[flag]) return;
1627
+ const ownHost = (() => {
1628
+ try {
1629
+ const cfg = AllStak.getConfig();
1630
+ return (cfg?.host ?? "https://api.allstak.sa").replace(/\/$/, "");
1631
+ } catch {
1632
+ return "";
1633
+ }
1634
+ })();
1635
+ const origOpen = X.prototype.open;
1636
+ const origSend = X.prototype.send;
1637
+ X.prototype.open = function(method, url, ...rest) {
1638
+ this.__allstak_method__ = method;
1639
+ this.__allstak_url__ = url;
1640
+ return origOpen.call(this, method, url, ...rest);
1641
+ };
1642
+ X.prototype.send = function(body) {
1643
+ const start = Date.now();
1644
+ const method = this.__allstak_method__ || "GET";
1645
+ const url = this.__allstak_url__ || "";
1646
+ const isOwnIngest2 = ownHost && url.startsWith(ownHost);
1647
+ let path = url;
1648
+ try {
1649
+ path = new URL(url).pathname;
1650
+ } catch {
1651
+ }
1652
+ const onDone = (status) => {
1653
+ const durationMs = Date.now() - start;
1654
+ try {
1655
+ AllStak.addBreadcrumb(
1656
+ "http",
1657
+ `${method} ${path} -> ${status}`,
1658
+ status >= 400 ? "error" : "info",
1659
+ { method, url: path, statusCode: status, durationMs }
1660
+ );
1661
+ } catch {
1662
+ }
1663
+ };
1664
+ if (!isOwnIngest2) {
1665
+ this.addEventListener?.("load", () => onDone(this.status || 0));
1666
+ this.addEventListener?.("error", () => onDone(0));
1667
+ this.addEventListener?.("abort", () => onDone(0));
1668
+ this.addEventListener?.("timeout", () => onDone(0));
1669
+ }
1670
+ return origSend.call(this, body);
1671
+ };
1672
+ X.prototype[flag] = true;
1673
+ }
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
+ function installReactNative(options = {}) {
1712
+ const autoError = options.autoErrorHandler !== false;
1713
+ const autoPromise = options.autoPromiseRejections !== false;
1714
+ const autoDevice = options.autoDeviceTags !== false;
1715
+ const autoAppState = options.autoAppStateBreadcrumbs !== false;
1716
+ const autoNetwork = options.autoNetworkCapture !== false;
1717
+ AllStak.setTag("platform", "react-native");
1718
+ try {
1719
+ applyArchitectureTags((k, v) => AllStak.setTag(k, v));
1720
+ } catch {
1721
+ }
1722
+ try {
1723
+ const hermes = typeof globalThis.HermesInternal !== "undefined";
1724
+ let dist;
1725
+ try {
1726
+ const rn = __require("react-native");
1727
+ const os = rn?.Platform?.OS;
1728
+ if (os === "ios" || os === "android") {
1729
+ dist = `${os}-${hermes ? "hermes" : "jsc"}`;
1730
+ }
1731
+ } catch {
1732
+ }
1733
+ AllStak.setIdentity({
1734
+ sdkName: "allstak-react-native",
1735
+ sdkVersion: "0.3.0",
1736
+ platform: "react-native",
1737
+ dist
1738
+ });
1739
+ } catch {
1740
+ }
1741
+ if (autoNetwork) {
1742
+ try {
1743
+ instrumentXmlHttpRequest();
1744
+ } catch {
1745
+ }
1746
+ }
1747
+ if (options.autoFetchBreadcrumbs !== false) {
1748
+ try {
1749
+ const cfg = AllStak.getConfig();
1750
+ const ownBaseUrl = (cfg?.host ?? "https://api.allstak.sa").replace(/\/$/, "");
1751
+ instrumentFetch(__safeAddBreadcrumbForInstrumentation, ownBaseUrl);
1752
+ } catch {
1753
+ }
1754
+ }
1755
+ if (options.autoConsoleBreadcrumbs !== false) {
1756
+ try {
1757
+ instrumentConsole(__safeAddBreadcrumbForInstrumentation);
1758
+ } catch {
1759
+ }
1760
+ }
1761
+ if (autoDevice) {
1762
+ try {
1763
+ const rn = __require("react-native");
1764
+ const Platform = rn?.Platform;
1765
+ if (Platform) {
1766
+ AllStak.setTag("device.os", String(Platform.OS ?? ""));
1767
+ AllStak.setTag("device.osVersion", String(Platform.Version ?? ""));
1768
+ if (Platform.constants?.Model) {
1769
+ AllStak.setTag("device.model", String(Platform.constants.Model));
1770
+ }
1771
+ }
1772
+ } catch {
1773
+ }
1774
+ }
1775
+ if (autoAppState) {
1776
+ try {
1777
+ const rn = __require("react-native");
1778
+ const AppState = rn?.AppState;
1779
+ if (AppState && typeof AppState.addEventListener === "function") {
1780
+ AppState.addEventListener("change", (next) => {
1781
+ try {
1782
+ AllStak.addBreadcrumb("navigation", `AppState \u2192 ${next}`, "info", { appState: next });
1783
+ } catch {
1784
+ }
1785
+ });
1786
+ }
1787
+ } catch {
1788
+ }
1789
+ }
1790
+ if (autoError) {
1791
+ const eu = globalThis.ErrorUtils;
1792
+ if (eu && typeof eu.setGlobalHandler === "function") {
1793
+ const prev = eu.getGlobalHandler();
1794
+ eu.setGlobalHandler((error, isFatal) => {
1795
+ try {
1796
+ AllStak.captureException(error, {
1797
+ source: "react-native-ErrorUtils",
1798
+ fatal: String(Boolean(isFatal))
1799
+ });
1800
+ } catch {
1801
+ }
1802
+ try {
1803
+ prev(error, isFatal);
1804
+ } catch {
1805
+ }
1806
+ });
1807
+ }
1808
+ }
1809
+ if (autoPromise) {
1810
+ try {
1811
+ const tracking = __require("promise/setimmediate/rejection-tracking");
1812
+ tracking.enable({
1813
+ 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
+ },
1821
+ onHandled: () => {
1822
+ }
1823
+ });
1824
+ } catch {
1825
+ const g = globalThis;
1826
+ if (typeof g.addEventListener === "function") {
1827
+ g.addEventListener("unhandledrejection", (ev) => {
1828
+ const reason = ev?.reason;
1829
+ const err = reason instanceof Error ? reason : new Error(String(reason));
1830
+ try {
1831
+ AllStak.captureException(err, { source: "unhandledRejection" });
1832
+ } catch {
1833
+ }
1834
+ });
1835
+ }
1836
+ }
1837
+ }
1838
+ }
3
1839
  export {
4
1840
  AllStak,
5
- installReactNative
1841
+ AllStakClient,
1842
+ HttpRequestModule,
1843
+ INGEST_HOST,
1844
+ ReplaySurrogate,
1845
+ SDK_NAME,
1846
+ SDK_VERSION,
1847
+ Scope,
1848
+ __setNativeModuleForTest,
1849
+ applyArchitectureTags,
1850
+ detectArchitecture,
1851
+ drainPendingNativeCrashes,
1852
+ installReactNative,
1853
+ instrumentNavigationFromLinking,
1854
+ instrumentReactNavigation
6
1855
  };
7
1856
  //# sourceMappingURL=index.mjs.map