@botim/mp-debug-sdk 0.4.1 → 0.5.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/dist/index.cjs +69 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -7
- package/dist/index.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +12 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -272,7 +272,7 @@ function resolveAgainstEndpoint(url, base) {
|
|
|
272
272
|
function detectDeviceInfo(app, override) {
|
|
273
273
|
const ua = typeof navigator !== "undefined" ? navigator.userAgent : void 0;
|
|
274
274
|
return {
|
|
275
|
-
deviceId: override?.deviceId ??
|
|
275
|
+
deviceId: override?.deviceId ?? loadOrCreateDeviceId(),
|
|
276
276
|
platform: override?.platform ?? detectPlatform(ua),
|
|
277
277
|
osVersion: override?.osVersion,
|
|
278
278
|
appName: override?.appName ?? app.name,
|
|
@@ -288,6 +288,21 @@ function detectPlatform(ua) {
|
|
|
288
288
|
if (/Mozilla|Chrome|Safari|Firefox/i.test(ua)) return "web";
|
|
289
289
|
return "unknown";
|
|
290
290
|
}
|
|
291
|
+
var DEVICE_ID_STORAGE_KEY = "botim-debug-sdk:device-id";
|
|
292
|
+
function loadOrCreateDeviceId() {
|
|
293
|
+
try {
|
|
294
|
+
const ls = typeof localStorage !== "undefined" ? localStorage : null;
|
|
295
|
+
if (ls) {
|
|
296
|
+
const stored = ls.getItem(DEVICE_ID_STORAGE_KEY);
|
|
297
|
+
if (stored && stored.length > 0) return stored;
|
|
298
|
+
const fresh = generateDeviceId();
|
|
299
|
+
ls.setItem(DEVICE_ID_STORAGE_KEY, fresh);
|
|
300
|
+
return fresh;
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
return generateDeviceId();
|
|
305
|
+
}
|
|
291
306
|
function generateDeviceId() {
|
|
292
307
|
const c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
293
308
|
if (c?.randomUUID) return c.randomUUID();
|
|
@@ -562,6 +577,11 @@ function wrapFetch(opts) {
|
|
|
562
577
|
method,
|
|
563
578
|
url,
|
|
564
579
|
status: res.status,
|
|
580
|
+
// statusText carries the human label ("OK", "Not Found"). Pre-HTTP/2
|
|
581
|
+
// responses always have it; HTTP/2+ defines it as empty by spec but
|
|
582
|
+
// most browsers synthesize one from the code, so this is reliable
|
|
583
|
+
// enough to display alongside the status code.
|
|
584
|
+
statusText: res.statusText || void 0,
|
|
565
585
|
durationMs: Date.now() - start,
|
|
566
586
|
resHeaders: headersFromResponse(res),
|
|
567
587
|
resBody
|
|
@@ -575,7 +595,14 @@ function wrapFetch(opts) {
|
|
|
575
595
|
url,
|
|
576
596
|
durationMs: Date.now() - start,
|
|
577
597
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
578
|
-
errorName: err instanceof Error ? err.name : void 0
|
|
598
|
+
errorName: err instanceof Error ? err.name : void 0,
|
|
599
|
+
// Stack from the rejected promise — points into fetch internals
|
|
600
|
+
// and (when present) the call site that issued the request.
|
|
601
|
+
errorStack: err instanceof Error ? err.stack : void 0,
|
|
602
|
+
// undici frequently wraps the real reason in `cause` (e.g.
|
|
603
|
+
// `TypeError: fetch failed` outside, `Error: ECONNREFUSED` inside).
|
|
604
|
+
// Flatten the chain so operators don't have to dig.
|
|
605
|
+
errorCause: collectCauseChain(err)
|
|
579
606
|
});
|
|
580
607
|
throw err;
|
|
581
608
|
}
|
|
@@ -584,6 +611,24 @@ function wrapFetch(opts) {
|
|
|
584
611
|
target.fetch = original;
|
|
585
612
|
};
|
|
586
613
|
}
|
|
614
|
+
function collectCauseChain(err) {
|
|
615
|
+
if (!err || typeof err !== "object") return void 0;
|
|
616
|
+
const lines = [];
|
|
617
|
+
let cur = err.cause;
|
|
618
|
+
const seen = /* @__PURE__ */ new Set();
|
|
619
|
+
while (cur && lines.length < 5) {
|
|
620
|
+
if (seen.has(cur)) break;
|
|
621
|
+
seen.add(cur);
|
|
622
|
+
if (cur instanceof Error) {
|
|
623
|
+
lines.push(`${cur.name}: ${cur.message}`);
|
|
624
|
+
cur = cur.cause;
|
|
625
|
+
} else {
|
|
626
|
+
lines.push(String(cur));
|
|
627
|
+
cur = cur?.cause;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return lines.length ? lines.join("\n") : void 0;
|
|
631
|
+
}
|
|
587
632
|
function wrapXHR(opts) {
|
|
588
633
|
if (typeof XMLHttpRequest === "undefined") return () => {
|
|
589
634
|
};
|
|
@@ -619,6 +664,7 @@ function wrapXHR(opts) {
|
|
|
619
664
|
}
|
|
620
665
|
s.start = Date.now();
|
|
621
666
|
s.reqBody = typeof body === "string" ? body : void 0;
|
|
667
|
+
const sendSiteStack = captureCallSiteStack();
|
|
622
668
|
opts.emit({
|
|
623
669
|
phase: "request",
|
|
624
670
|
reqId: s.reqId,
|
|
@@ -636,25 +682,32 @@ function wrapXHR(opts) {
|
|
|
636
682
|
method: s.method,
|
|
637
683
|
url: s.url,
|
|
638
684
|
status: this.status,
|
|
685
|
+
// XHR exposes statusText directly; same display purpose as fetch.
|
|
686
|
+
statusText: this.statusText || void 0,
|
|
639
687
|
durationMs: Date.now() - s.start,
|
|
640
688
|
resHeaders: headers,
|
|
641
689
|
resBody
|
|
642
690
|
});
|
|
643
691
|
};
|
|
644
|
-
const onError = () => {
|
|
692
|
+
const onError = (kind) => () => {
|
|
645
693
|
opts.emit({
|
|
646
694
|
phase: "error",
|
|
647
695
|
reqId: s.reqId,
|
|
648
696
|
method: s.method,
|
|
649
697
|
url: s.url,
|
|
650
698
|
durationMs: Date.now() - s.start,
|
|
651
|
-
|
|
699
|
+
// Distinguish error/timeout/abort in the message — the standard
|
|
700
|
+
// XHR `statusText` is empty for `error` and unhelpful for the
|
|
701
|
+
// others, so we synthesise a clear label.
|
|
702
|
+
errorMessage: this.statusText || `xhr ${kind}`,
|
|
703
|
+
errorName: `XHR${kind[0].toUpperCase()}${kind.slice(1)}`,
|
|
704
|
+
errorStack: sendSiteStack
|
|
652
705
|
});
|
|
653
706
|
};
|
|
654
707
|
this.addEventListener("load", onLoad);
|
|
655
|
-
this.addEventListener("error", onError);
|
|
656
|
-
this.addEventListener("timeout", onError);
|
|
657
|
-
this.addEventListener("abort", onError);
|
|
708
|
+
this.addEventListener("error", onError("error"));
|
|
709
|
+
this.addEventListener("timeout", onError("timeout"));
|
|
710
|
+
this.addEventListener("abort", onError("abort"));
|
|
658
711
|
return origSend.apply(this, [body]);
|
|
659
712
|
};
|
|
660
713
|
return () => {
|
|
@@ -663,6 +716,15 @@ function wrapXHR(opts) {
|
|
|
663
716
|
proto.setRequestHeader = origSetReqHeader;
|
|
664
717
|
};
|
|
665
718
|
}
|
|
719
|
+
function captureCallSiteStack() {
|
|
720
|
+
try {
|
|
721
|
+
throw new Error("xhr-callsite");
|
|
722
|
+
} catch (err) {
|
|
723
|
+
if (!(err instanceof Error) || !err.stack) return void 0;
|
|
724
|
+
const lines = err.stack.split("\n");
|
|
725
|
+
return lines.slice(2).join("\n") || void 0;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
666
728
|
function parseXhrHeaders(raw) {
|
|
667
729
|
const out = {};
|
|
668
730
|
if (!raw) return out;
|