@botim/mp-debug-sdk 0.4.1 → 0.6.1
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/README.md +54 -3
- package/dist/index.cjs +239 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +239 -8
- 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 +7 -3
package/dist/index.d.cts
CHANGED
|
@@ -52,6 +52,36 @@ interface BuiltinHostHooks {
|
|
|
52
52
|
* The SDK enforces a 1 MB base64/JSON cap regardless.
|
|
53
53
|
*/
|
|
54
54
|
screenshot?: () => ScreenshotResult | Promise<ScreenshotResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Default-enabled remote-eval command (`exec`). Pass `false` to opt out
|
|
57
|
+
* of registration entirely; pass an object to inject extra locals into
|
|
58
|
+
* every snippet's scope.
|
|
59
|
+
*
|
|
60
|
+
* builtins: { exec: false }
|
|
61
|
+
* → exec NOT registered; agents calling exec see `unknown-command`.
|
|
62
|
+
*
|
|
63
|
+
* builtins: { exec: { globals: { app, store } } }
|
|
64
|
+
* → exec registered; snippets can reference `app` and `store` as
|
|
65
|
+
* bare identifiers. Default locals (`BOT`, `window`, `document`)
|
|
66
|
+
* are always present.
|
|
67
|
+
*
|
|
68
|
+
* builtins.exec is undefined / not set
|
|
69
|
+
* → default behaviour: exec registered with default locals only.
|
|
70
|
+
*
|
|
71
|
+
* See `openspec/changes/add-default-exec-builtin/design.md` for the
|
|
72
|
+
* security rationale (no prod-specific gating in MVP; relies on the
|
|
73
|
+
* existing `enableRemoteDebug` consent gate).
|
|
74
|
+
*/
|
|
75
|
+
exec?: false | ExecOptions;
|
|
76
|
+
}
|
|
77
|
+
interface ExecOptions {
|
|
78
|
+
/**
|
|
79
|
+
* Additional locals bound into every snippet's scope. Keys MUST be
|
|
80
|
+
* valid identifier names (the SDK does not validate this — passing a
|
|
81
|
+
* key like "1foo" or "a-b" will throw at AsyncFunction construction
|
|
82
|
+
* time and surface as a `command-rejected`).
|
|
83
|
+
*/
|
|
84
|
+
globals?: Record<string, unknown>;
|
|
55
85
|
}
|
|
56
86
|
type ScreenshotResult = string | {
|
|
57
87
|
data: string;
|
|
@@ -71,6 +101,7 @@ type ScreenshotResult = string | {
|
|
|
71
101
|
*/
|
|
72
102
|
| 'html-snapshot';
|
|
73
103
|
};
|
|
104
|
+
declare function getBOT(): unknown;
|
|
74
105
|
|
|
75
106
|
/**
|
|
76
107
|
* Per-signature sliding-window event deduper.
|
|
@@ -211,4 +242,4 @@ declare const DEFAULT_BUFFER_SIZE = 1000;
|
|
|
211
242
|
declare const DEFAULT_MAX_BATCH_SIZE = 50;
|
|
212
243
|
declare function enableRemoteDebug(options: RemoteDebugOptions): Promise<RemoteDebugHandle>;
|
|
213
244
|
|
|
214
|
-
export { type AppInfo, BotimConfig, BotimConfigError, BotimConsentError, type BuiltinHostHooks, CommandHandler, ConsentInput, ConsolePayload, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, type DedupOptions, DeviceInfo, ErrorPayload, EventLevel, EventType, NetworkPayload, type RedactionConfig, type RemoteDebugHandle, type RemoteDebugOptions, type SamplingConfig, type SuppressionSummary, enableRemoteDebug };
|
|
245
|
+
export { type AppInfo, BotimConfig, BotimConfigError, BotimConsentError, type BuiltinHostHooks, CommandHandler, ConsentInput, ConsolePayload, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, type DedupOptions, DeviceInfo, ErrorPayload, EventLevel, EventType, type ExecOptions, NetworkPayload, type RedactionConfig, type RemoteDebugHandle, type RemoteDebugOptions, type SamplingConfig, type SuppressionSummary, enableRemoteDebug, getBOT };
|
package/dist/index.d.ts
CHANGED
|
@@ -52,6 +52,36 @@ interface BuiltinHostHooks {
|
|
|
52
52
|
* The SDK enforces a 1 MB base64/JSON cap regardless.
|
|
53
53
|
*/
|
|
54
54
|
screenshot?: () => ScreenshotResult | Promise<ScreenshotResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Default-enabled remote-eval command (`exec`). Pass `false` to opt out
|
|
57
|
+
* of registration entirely; pass an object to inject extra locals into
|
|
58
|
+
* every snippet's scope.
|
|
59
|
+
*
|
|
60
|
+
* builtins: { exec: false }
|
|
61
|
+
* → exec NOT registered; agents calling exec see `unknown-command`.
|
|
62
|
+
*
|
|
63
|
+
* builtins: { exec: { globals: { app, store } } }
|
|
64
|
+
* → exec registered; snippets can reference `app` and `store` as
|
|
65
|
+
* bare identifiers. Default locals (`BOT`, `window`, `document`)
|
|
66
|
+
* are always present.
|
|
67
|
+
*
|
|
68
|
+
* builtins.exec is undefined / not set
|
|
69
|
+
* → default behaviour: exec registered with default locals only.
|
|
70
|
+
*
|
|
71
|
+
* See `openspec/changes/add-default-exec-builtin/design.md` for the
|
|
72
|
+
* security rationale (no prod-specific gating in MVP; relies on the
|
|
73
|
+
* existing `enableRemoteDebug` consent gate).
|
|
74
|
+
*/
|
|
75
|
+
exec?: false | ExecOptions;
|
|
76
|
+
}
|
|
77
|
+
interface ExecOptions {
|
|
78
|
+
/**
|
|
79
|
+
* Additional locals bound into every snippet's scope. Keys MUST be
|
|
80
|
+
* valid identifier names (the SDK does not validate this — passing a
|
|
81
|
+
* key like "1foo" or "a-b" will throw at AsyncFunction construction
|
|
82
|
+
* time and surface as a `command-rejected`).
|
|
83
|
+
*/
|
|
84
|
+
globals?: Record<string, unknown>;
|
|
55
85
|
}
|
|
56
86
|
type ScreenshotResult = string | {
|
|
57
87
|
data: string;
|
|
@@ -71,6 +101,7 @@ type ScreenshotResult = string | {
|
|
|
71
101
|
*/
|
|
72
102
|
| 'html-snapshot';
|
|
73
103
|
};
|
|
104
|
+
declare function getBOT(): unknown;
|
|
74
105
|
|
|
75
106
|
/**
|
|
76
107
|
* Per-signature sliding-window event deduper.
|
|
@@ -211,4 +242,4 @@ declare const DEFAULT_BUFFER_SIZE = 1000;
|
|
|
211
242
|
declare const DEFAULT_MAX_BATCH_SIZE = 50;
|
|
212
243
|
declare function enableRemoteDebug(options: RemoteDebugOptions): Promise<RemoteDebugHandle>;
|
|
213
244
|
|
|
214
|
-
export { type AppInfo, BotimConfig, BotimConfigError, BotimConsentError, type BuiltinHostHooks, CommandHandler, ConsentInput, ConsolePayload, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, type DedupOptions, DeviceInfo, ErrorPayload, EventLevel, EventType, NetworkPayload, type RedactionConfig, type RemoteDebugHandle, type RemoteDebugOptions, type SamplingConfig, type SuppressionSummary, enableRemoteDebug };
|
|
245
|
+
export { type AppInfo, BotimConfig, BotimConfigError, BotimConsentError, type BuiltinHostHooks, CommandHandler, ConsentInput, ConsolePayload, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, type DedupOptions, DeviceInfo, ErrorPayload, EventLevel, EventType, type ExecOptions, NetworkPayload, type RedactionConfig, type RemoteDebugHandle, type RemoteDebugOptions, type SamplingConfig, type SuppressionSummary, enableRemoteDebug, getBOT };
|
package/dist/index.js
CHANGED
|
@@ -270,7 +270,7 @@ function resolveAgainstEndpoint(url, base) {
|
|
|
270
270
|
function detectDeviceInfo(app, override) {
|
|
271
271
|
const ua = typeof navigator !== "undefined" ? navigator.userAgent : void 0;
|
|
272
272
|
return {
|
|
273
|
-
deviceId: override?.deviceId ??
|
|
273
|
+
deviceId: override?.deviceId ?? loadOrCreateDeviceId(),
|
|
274
274
|
platform: override?.platform ?? detectPlatform(ua),
|
|
275
275
|
osVersion: override?.osVersion,
|
|
276
276
|
appName: override?.appName ?? app.name,
|
|
@@ -286,6 +286,21 @@ function detectPlatform(ua) {
|
|
|
286
286
|
if (/Mozilla|Chrome|Safari|Firefox/i.test(ua)) return "web";
|
|
287
287
|
return "unknown";
|
|
288
288
|
}
|
|
289
|
+
var DEVICE_ID_STORAGE_KEY = "botim-debug-sdk:device-id";
|
|
290
|
+
function loadOrCreateDeviceId() {
|
|
291
|
+
try {
|
|
292
|
+
const ls = typeof localStorage !== "undefined" ? localStorage : null;
|
|
293
|
+
if (ls) {
|
|
294
|
+
const stored = ls.getItem(DEVICE_ID_STORAGE_KEY);
|
|
295
|
+
if (stored && stored.length > 0) return stored;
|
|
296
|
+
const fresh = generateDeviceId();
|
|
297
|
+
ls.setItem(DEVICE_ID_STORAGE_KEY, fresh);
|
|
298
|
+
return fresh;
|
|
299
|
+
}
|
|
300
|
+
} catch {
|
|
301
|
+
}
|
|
302
|
+
return generateDeviceId();
|
|
303
|
+
}
|
|
289
304
|
function generateDeviceId() {
|
|
290
305
|
const c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
291
306
|
if (c?.randomUUID) return c.randomUUID();
|
|
@@ -560,6 +575,11 @@ function wrapFetch(opts) {
|
|
|
560
575
|
method,
|
|
561
576
|
url,
|
|
562
577
|
status: res.status,
|
|
578
|
+
// statusText carries the human label ("OK", "Not Found"). Pre-HTTP/2
|
|
579
|
+
// responses always have it; HTTP/2+ defines it as empty by spec but
|
|
580
|
+
// most browsers synthesize one from the code, so this is reliable
|
|
581
|
+
// enough to display alongside the status code.
|
|
582
|
+
statusText: res.statusText || void 0,
|
|
563
583
|
durationMs: Date.now() - start,
|
|
564
584
|
resHeaders: headersFromResponse(res),
|
|
565
585
|
resBody
|
|
@@ -573,7 +593,14 @@ function wrapFetch(opts) {
|
|
|
573
593
|
url,
|
|
574
594
|
durationMs: Date.now() - start,
|
|
575
595
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
576
|
-
errorName: err instanceof Error ? err.name : void 0
|
|
596
|
+
errorName: err instanceof Error ? err.name : void 0,
|
|
597
|
+
// Stack from the rejected promise — points into fetch internals
|
|
598
|
+
// and (when present) the call site that issued the request.
|
|
599
|
+
errorStack: err instanceof Error ? err.stack : void 0,
|
|
600
|
+
// undici frequently wraps the real reason in `cause` (e.g.
|
|
601
|
+
// `TypeError: fetch failed` outside, `Error: ECONNREFUSED` inside).
|
|
602
|
+
// Flatten the chain so operators don't have to dig.
|
|
603
|
+
errorCause: collectCauseChain(err)
|
|
577
604
|
});
|
|
578
605
|
throw err;
|
|
579
606
|
}
|
|
@@ -582,6 +609,24 @@ function wrapFetch(opts) {
|
|
|
582
609
|
target.fetch = original;
|
|
583
610
|
};
|
|
584
611
|
}
|
|
612
|
+
function collectCauseChain(err) {
|
|
613
|
+
if (!err || typeof err !== "object") return void 0;
|
|
614
|
+
const lines = [];
|
|
615
|
+
let cur = err.cause;
|
|
616
|
+
const seen = /* @__PURE__ */ new Set();
|
|
617
|
+
while (cur && lines.length < 5) {
|
|
618
|
+
if (seen.has(cur)) break;
|
|
619
|
+
seen.add(cur);
|
|
620
|
+
if (cur instanceof Error) {
|
|
621
|
+
lines.push(`${cur.name}: ${cur.message}`);
|
|
622
|
+
cur = cur.cause;
|
|
623
|
+
} else {
|
|
624
|
+
lines.push(String(cur));
|
|
625
|
+
cur = cur?.cause;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return lines.length ? lines.join("\n") : void 0;
|
|
629
|
+
}
|
|
585
630
|
function wrapXHR(opts) {
|
|
586
631
|
if (typeof XMLHttpRequest === "undefined") return () => {
|
|
587
632
|
};
|
|
@@ -617,6 +662,7 @@ function wrapXHR(opts) {
|
|
|
617
662
|
}
|
|
618
663
|
s.start = Date.now();
|
|
619
664
|
s.reqBody = typeof body === "string" ? body : void 0;
|
|
665
|
+
const sendSiteStack = captureCallSiteStack();
|
|
620
666
|
opts.emit({
|
|
621
667
|
phase: "request",
|
|
622
668
|
reqId: s.reqId,
|
|
@@ -634,25 +680,32 @@ function wrapXHR(opts) {
|
|
|
634
680
|
method: s.method,
|
|
635
681
|
url: s.url,
|
|
636
682
|
status: this.status,
|
|
683
|
+
// XHR exposes statusText directly; same display purpose as fetch.
|
|
684
|
+
statusText: this.statusText || void 0,
|
|
637
685
|
durationMs: Date.now() - s.start,
|
|
638
686
|
resHeaders: headers,
|
|
639
687
|
resBody
|
|
640
688
|
});
|
|
641
689
|
};
|
|
642
|
-
const onError = () => {
|
|
690
|
+
const onError = (kind) => () => {
|
|
643
691
|
opts.emit({
|
|
644
692
|
phase: "error",
|
|
645
693
|
reqId: s.reqId,
|
|
646
694
|
method: s.method,
|
|
647
695
|
url: s.url,
|
|
648
696
|
durationMs: Date.now() - s.start,
|
|
649
|
-
|
|
697
|
+
// Distinguish error/timeout/abort in the message — the standard
|
|
698
|
+
// XHR `statusText` is empty for `error` and unhelpful for the
|
|
699
|
+
// others, so we synthesise a clear label.
|
|
700
|
+
errorMessage: this.statusText || `xhr ${kind}`,
|
|
701
|
+
errorName: `XHR${kind[0].toUpperCase()}${kind.slice(1)}`,
|
|
702
|
+
errorStack: sendSiteStack
|
|
650
703
|
});
|
|
651
704
|
};
|
|
652
705
|
this.addEventListener("load", onLoad);
|
|
653
|
-
this.addEventListener("error", onError);
|
|
654
|
-
this.addEventListener("timeout", onError);
|
|
655
|
-
this.addEventListener("abort", onError);
|
|
706
|
+
this.addEventListener("error", onError("error"));
|
|
707
|
+
this.addEventListener("timeout", onError("timeout"));
|
|
708
|
+
this.addEventListener("abort", onError("abort"));
|
|
656
709
|
return origSend.apply(this, [body]);
|
|
657
710
|
};
|
|
658
711
|
return () => {
|
|
@@ -661,6 +714,15 @@ function wrapXHR(opts) {
|
|
|
661
714
|
proto.setRequestHeader = origSetReqHeader;
|
|
662
715
|
};
|
|
663
716
|
}
|
|
717
|
+
function captureCallSiteStack() {
|
|
718
|
+
try {
|
|
719
|
+
throw new Error("xhr-callsite");
|
|
720
|
+
} catch (err) {
|
|
721
|
+
if (!(err instanceof Error) || !err.stack) return void 0;
|
|
722
|
+
const lines = err.stack.split("\n");
|
|
723
|
+
return lines.slice(2).join("\n") || void 0;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
664
726
|
function parseXhrHeaders(raw) {
|
|
665
727
|
const out = {};
|
|
666
728
|
if (!raw) return out;
|
|
@@ -755,6 +817,10 @@ var CommandRegistry = class {
|
|
|
755
817
|
};
|
|
756
818
|
var MAX_DUMP_BYTES = 64 * 1024;
|
|
757
819
|
var MAX_SCREENSHOT_BYTES = 1024 * 1024;
|
|
820
|
+
var MAX_EXEC_CODE_BYTES = 8 * 1024;
|
|
821
|
+
var DEFAULT_EXEC_TIMEOUT_MS = 5e3;
|
|
822
|
+
var MIN_EXEC_TIMEOUT_MS = 250;
|
|
823
|
+
var MAX_EXEC_TIMEOUT_MS = 3e4;
|
|
758
824
|
async function defaultDomScreenshot() {
|
|
759
825
|
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
760
826
|
throw new Error(
|
|
@@ -869,6 +935,9 @@ function registerBuiltins(registry, hooks = {}) {
|
|
|
869
935
|
registry.register("dump-state", makeDumpState(hooks.getState));
|
|
870
936
|
registry.register("set-feature-flag", makeSetFlag(hooks.setFeatureFlag));
|
|
871
937
|
registry.register("screenshot", makeScreenshot(hooks.screenshot));
|
|
938
|
+
if (hooks.exec !== false) {
|
|
939
|
+
registry.register("exec", makeExec(hooks.exec ?? {}));
|
|
940
|
+
}
|
|
872
941
|
}
|
|
873
942
|
var ping = () => ({ ok: true, ts: Date.now() });
|
|
874
943
|
function makeReload(reload) {
|
|
@@ -931,6 +1000,168 @@ function makeScreenshot(screenshot) {
|
|
|
931
1000
|
return { format, data, bytes: data.length };
|
|
932
1001
|
};
|
|
933
1002
|
}
|
|
1003
|
+
var cachedBOT = void 0;
|
|
1004
|
+
function getBOT() {
|
|
1005
|
+
if (cachedBOT !== void 0) return cachedBOT;
|
|
1006
|
+
if (typeof window === "undefined") {
|
|
1007
|
+
cachedBOT = null;
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
const w = window;
|
|
1012
|
+
if (w.BOT) {
|
|
1013
|
+
cachedBOT = w.BOT;
|
|
1014
|
+
return cachedBOT;
|
|
1015
|
+
}
|
|
1016
|
+
} catch {
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
const w = window;
|
|
1020
|
+
const ng = w.angular;
|
|
1021
|
+
if (ng?.element && typeof document !== "undefined") {
|
|
1022
|
+
const injector = ng.element(document).injector?.();
|
|
1023
|
+
const bot = injector?.get?.("BOT");
|
|
1024
|
+
if (bot != null) {
|
|
1025
|
+
cachedBOT = bot;
|
|
1026
|
+
return cachedBOT;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
} catch {
|
|
1030
|
+
}
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
function makeExec(opts) {
|
|
1034
|
+
const extraGlobalNames = Object.keys(opts.globals ?? {});
|
|
1035
|
+
const extraGlobalValues = extraGlobalNames.map((k) => opts.globals[k]);
|
|
1036
|
+
return async (args, ctx) => {
|
|
1037
|
+
if (typeof args.code !== "string" || args.code.length === 0) {
|
|
1038
|
+
throw new Error("args.code (non-empty string) is required");
|
|
1039
|
+
}
|
|
1040
|
+
if (args.code.length > MAX_EXEC_CODE_BYTES) {
|
|
1041
|
+
throw new Error(`args.code ${args.code.length} bytes exceeds limit ${MAX_EXEC_CODE_BYTES}`);
|
|
1042
|
+
}
|
|
1043
|
+
const timeoutMs = clamp(
|
|
1044
|
+
typeof args.timeoutMs === "number" ? args.timeoutMs : DEFAULT_EXEC_TIMEOUT_MS,
|
|
1045
|
+
MIN_EXEC_TIMEOUT_MS,
|
|
1046
|
+
MAX_EXEC_TIMEOUT_MS
|
|
1047
|
+
);
|
|
1048
|
+
const start = Date.now();
|
|
1049
|
+
const logs = [];
|
|
1050
|
+
const consoleMethods = ["log", "info", "warn", "error", "debug"];
|
|
1051
|
+
const originals = {};
|
|
1052
|
+
if (typeof console !== "undefined") {
|
|
1053
|
+
for (const m of consoleMethods) {
|
|
1054
|
+
const orig = console[m];
|
|
1055
|
+
if (typeof orig !== "function") continue;
|
|
1056
|
+
originals[m] = orig;
|
|
1057
|
+
const captured = (...callArgs) => {
|
|
1058
|
+
logs.push({ method: m, args: callArgs.map(execSafeClone), ts: Date.now() });
|
|
1059
|
+
try {
|
|
1060
|
+
orig.call(console, ...callArgs);
|
|
1061
|
+
} catch {
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
console[m] = captured;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
let value;
|
|
1068
|
+
let threw = void 0;
|
|
1069
|
+
try {
|
|
1070
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {
|
|
1071
|
+
}).constructor;
|
|
1072
|
+
const localNames = ["BOT", "window", "document", ...extraGlobalNames];
|
|
1073
|
+
const localValues = [
|
|
1074
|
+
getBOT(),
|
|
1075
|
+
typeof window !== "undefined" ? window : void 0,
|
|
1076
|
+
typeof document !== "undefined" ? document : void 0,
|
|
1077
|
+
...extraGlobalValues
|
|
1078
|
+
];
|
|
1079
|
+
let fnTry = null;
|
|
1080
|
+
try {
|
|
1081
|
+
fnTry = new AsyncFunction(...localNames, `return (${args.code});`);
|
|
1082
|
+
} catch (e) {
|
|
1083
|
+
if (!(e instanceof SyntaxError)) throw e;
|
|
1084
|
+
}
|
|
1085
|
+
const fn = fnTry ?? new AsyncFunction(...localNames, args.code);
|
|
1086
|
+
let timer = null;
|
|
1087
|
+
let abortReject = null;
|
|
1088
|
+
const onAbort = () => abortReject?.(new Error("exec cancelled"));
|
|
1089
|
+
ctx.signal?.addEventListener?.("abort", onAbort);
|
|
1090
|
+
try {
|
|
1091
|
+
value = await Promise.race([
|
|
1092
|
+
fn(...localValues),
|
|
1093
|
+
new Promise((_, reject) => {
|
|
1094
|
+
timer = setTimeout(
|
|
1095
|
+
() => reject(new Error(`exec exceeded ${timeoutMs}ms`)),
|
|
1096
|
+
timeoutMs
|
|
1097
|
+
);
|
|
1098
|
+
}),
|
|
1099
|
+
new Promise((_, reject) => {
|
|
1100
|
+
abortReject = reject;
|
|
1101
|
+
})
|
|
1102
|
+
]);
|
|
1103
|
+
} finally {
|
|
1104
|
+
if (timer) clearTimeout(timer);
|
|
1105
|
+
ctx.signal?.removeEventListener?.("abort", onAbort);
|
|
1106
|
+
}
|
|
1107
|
+
} catch (err) {
|
|
1108
|
+
threw = err;
|
|
1109
|
+
} finally {
|
|
1110
|
+
if (typeof console !== "undefined") {
|
|
1111
|
+
for (const m of consoleMethods) {
|
|
1112
|
+
if (originals[m]) {
|
|
1113
|
+
console[m] = originals[m];
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (threw !== void 0) {
|
|
1119
|
+
const e = threw instanceof Error ? threw : new Error(String(threw));
|
|
1120
|
+
const stackTruncated = typeof e.stack === "string" ? e.stack.split("\n").slice(0, 20).join("\n") : void 0;
|
|
1121
|
+
const detail = {
|
|
1122
|
+
name: e.name,
|
|
1123
|
+
message: e.message,
|
|
1124
|
+
stack: stackTruncated,
|
|
1125
|
+
logs,
|
|
1126
|
+
durationMs: Date.now() - start
|
|
1127
|
+
};
|
|
1128
|
+
const wrapped = new Error(JSON.stringify(detail));
|
|
1129
|
+
wrapped.detail = detail;
|
|
1130
|
+
throw wrapped;
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
ok: true,
|
|
1134
|
+
value: execSafeClone(value),
|
|
1135
|
+
logs,
|
|
1136
|
+
durationMs: Date.now() - start
|
|
1137
|
+
};
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
function clamp(n, lo, hi) {
|
|
1141
|
+
if (!Number.isFinite(n)) return lo;
|
|
1142
|
+
return Math.min(Math.max(n, lo), hi);
|
|
1143
|
+
}
|
|
1144
|
+
function execSafeClone(v) {
|
|
1145
|
+
try {
|
|
1146
|
+
return JSON.parse(JSON.stringify(v, (_k, val) => {
|
|
1147
|
+
if (typeof val === "function") {
|
|
1148
|
+
return `[Function: ${val.name || "anonymous"}]`;
|
|
1149
|
+
}
|
|
1150
|
+
if (val instanceof Error) {
|
|
1151
|
+
return { name: val.name, message: val.message, stack: val.stack };
|
|
1152
|
+
}
|
|
1153
|
+
if (typeof val === "bigint") return val.toString() + "n";
|
|
1154
|
+
if (typeof val === "undefined") return null;
|
|
1155
|
+
if (val && typeof val === "object" && val.nodeType === 1) {
|
|
1156
|
+
const el = val;
|
|
1157
|
+
return `[${el.tagName ?? "Element"}${el.id ? "#" + el.id : ""}]`;
|
|
1158
|
+
}
|
|
1159
|
+
return val;
|
|
1160
|
+
}));
|
|
1161
|
+
} catch {
|
|
1162
|
+
return { __unserializable: typeof v };
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
934
1165
|
function safeStringify(v) {
|
|
935
1166
|
try {
|
|
936
1167
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -1368,6 +1599,6 @@ async function enableRemoteDebug(options) {
|
|
|
1368
1599
|
};
|
|
1369
1600
|
}
|
|
1370
1601
|
|
|
1371
|
-
export { BotimConfigError, BotimConsentError, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, SCHEMA_VERSION, enableRemoteDebug };
|
|
1602
|
+
export { BotimConfigError, BotimConsentError, DEFAULT_BODY_PATTERNS, DEFAULT_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_REDACT_HEADERS, SCHEMA_VERSION, enableRemoteDebug, getBOT };
|
|
1372
1603
|
//# sourceMappingURL=index.js.map
|
|
1373
1604
|
//# sourceMappingURL=index.js.map
|