@botim/mp-debug-sdk 0.3.0 → 0.4.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/dist/index.cjs +100 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -7
- package/dist/index.d.ts +16 -7
- package/dist/index.js +100 -154
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var rrwebSnapshot = require('rrweb-snapshot');
|
|
4
|
+
|
|
3
5
|
// src/types.ts
|
|
4
6
|
var SCHEMA_VERSION = 2;
|
|
5
7
|
|
|
@@ -107,8 +109,7 @@ var Transport = class {
|
|
|
107
109
|
Authorization: `Bearer ${this.opts.deviceToken}`
|
|
108
110
|
},
|
|
109
111
|
body: JSON.stringify(batch),
|
|
110
|
-
signal: this.inflightUpload.signal
|
|
111
|
-
keepalive: true
|
|
112
|
+
signal: this.inflightUpload.signal
|
|
112
113
|
});
|
|
113
114
|
if (!res.ok) {
|
|
114
115
|
throw new Error(`ingest http ${res.status}`);
|
|
@@ -200,6 +201,12 @@ var Transport = class {
|
|
|
200
201
|
}
|
|
201
202
|
if (this.opts.buffer.size() > 0) {
|
|
202
203
|
const events = this.opts.buffer.drain(this.opts.buffer.size());
|
|
204
|
+
const body = JSON.stringify({
|
|
205
|
+
sessionToken: this.opts.deviceToken,
|
|
206
|
+
events
|
|
207
|
+
});
|
|
208
|
+
const KEEPALIVE_BODY_LIMIT = 60 * 1024;
|
|
209
|
+
const useKeepalive = body.length <= KEEPALIVE_BODY_LIMIT;
|
|
203
210
|
try {
|
|
204
211
|
await this.internalFetch(this.opts.ingestUrl, {
|
|
205
212
|
method: "POST",
|
|
@@ -207,11 +214,8 @@ var Transport = class {
|
|
|
207
214
|
"Content-Type": "application/json",
|
|
208
215
|
Authorization: `Bearer ${this.opts.deviceToken}`
|
|
209
216
|
},
|
|
210
|
-
body
|
|
211
|
-
|
|
212
|
-
events
|
|
213
|
-
}),
|
|
214
|
-
keepalive: true
|
|
217
|
+
body,
|
|
218
|
+
...useKeepalive ? { keepalive: true } : {}
|
|
215
219
|
});
|
|
216
220
|
} catch (err) {
|
|
217
221
|
this.opts.onError?.(err);
|
|
@@ -751,8 +755,6 @@ var CommandRegistry = class {
|
|
|
751
755
|
}
|
|
752
756
|
}
|
|
753
757
|
};
|
|
754
|
-
|
|
755
|
-
// src/commands/builtins.ts
|
|
756
758
|
var MAX_DUMP_BYTES = 64 * 1024;
|
|
757
759
|
var MAX_SCREENSHOT_BYTES = 1024 * 1024;
|
|
758
760
|
async function defaultDomScreenshot() {
|
|
@@ -761,163 +763,107 @@ async function defaultDomScreenshot() {
|
|
|
761
763
|
"[@botim/debug-sdk] default screenshot requires a DOM. Provide builtins.screenshot for non-browser runtimes (e.g. native bridge)."
|
|
762
764
|
);
|
|
763
765
|
}
|
|
766
|
+
const injected = injectAdoptedStyleSheets();
|
|
767
|
+
let tree;
|
|
764
768
|
try {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
"link",
|
|
787
|
-
"meta",
|
|
788
|
-
"source",
|
|
789
|
-
"track",
|
|
790
|
-
"wbr"
|
|
791
|
-
]);
|
|
792
|
-
var SKIP_TAGS = /* @__PURE__ */ new Set(["script", "noscript", "template"]);
|
|
793
|
-
var DEVTOOL_OVERLAY_PREFIXES = ["vite-", "astro-dev-", "next-route-"];
|
|
794
|
-
function isDevtoolOverlay(tag) {
|
|
795
|
-
return DEVTOOL_OVERLAY_PREFIXES.some((p) => tag.startsWith(p));
|
|
796
|
-
}
|
|
797
|
-
function escapeText(s) {
|
|
798
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
799
|
-
}
|
|
800
|
-
function escapeAttr(s) {
|
|
801
|
-
return s.replace(/&/g, "&").replace(/"/g, """);
|
|
802
|
-
}
|
|
803
|
-
function serializeComposed(node, opts, depth) {
|
|
804
|
-
if (depth > 256) return "";
|
|
805
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
806
|
-
return escapeText(node.textContent ?? "");
|
|
807
|
-
}
|
|
808
|
-
if (node.nodeType === Node.COMMENT_NODE) return "";
|
|
809
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return "";
|
|
810
|
-
const el = node;
|
|
811
|
-
const tag = el.tagName.toLowerCase();
|
|
812
|
-
if (SKIP_TAGS.has(tag)) return "";
|
|
813
|
-
if (isDevtoolOverlay(tag)) return "";
|
|
814
|
-
if (tag === "slot") {
|
|
815
|
-
const slot = el;
|
|
816
|
-
let assigned = [];
|
|
817
|
-
try {
|
|
818
|
-
assigned = slot.assignedNodes({ flatten: true });
|
|
819
|
-
} catch {
|
|
769
|
+
tree = rrwebSnapshot.snapshot(document, {
|
|
770
|
+
inlineStylesheet: true,
|
|
771
|
+
inlineImages: true,
|
|
772
|
+
recordCanvas: true,
|
|
773
|
+
// Deliberately NOT slimming. SlimDOM drops <link rel="preload">,
|
|
774
|
+
// hidden form metadata, and other "noise" that's actually relevant
|
|
775
|
+
// when reproducing a layout bug.
|
|
776
|
+
slimDOM: false,
|
|
777
|
+
// Don't mask anything by default — debug-relay already runs a
|
|
778
|
+
// top-level redactor on console payloads, and on-screen text is the
|
|
779
|
+
// whole point of capturing a screenshot. Hosts that need PII masking
|
|
780
|
+
// can wire their own builtins.screenshot using rrweb-snapshot's
|
|
781
|
+
// `maskTextSelector` / `maskInputOptions`.
|
|
782
|
+
maskAllInputs: false
|
|
783
|
+
});
|
|
784
|
+
} finally {
|
|
785
|
+
for (const node of injected) {
|
|
786
|
+
try {
|
|
787
|
+
node.remove();
|
|
788
|
+
} catch {
|
|
789
|
+
}
|
|
820
790
|
}
|
|
821
|
-
const source = assigned.length > 0 ? assigned : Array.from(el.childNodes);
|
|
822
|
-
return source.map((c) => serializeComposed(c, opts, depth + 1)).join("");
|
|
823
791
|
}
|
|
824
|
-
if (
|
|
825
|
-
|
|
792
|
+
if (!tree) {
|
|
793
|
+
throw new Error("[@botim/debug-sdk] rrweb-snapshot returned null tree");
|
|
826
794
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
795
|
+
const payload = {
|
|
796
|
+
snapshot: tree,
|
|
797
|
+
viewport: {
|
|
798
|
+
w: window.innerWidth || document.documentElement.clientWidth || 0,
|
|
799
|
+
h: window.innerHeight || document.documentElement.clientHeight || 0
|
|
800
|
+
},
|
|
801
|
+
url: location.href,
|
|
802
|
+
capturedAt: Date.now()
|
|
803
|
+
};
|
|
804
|
+
return {
|
|
805
|
+
data: JSON.stringify(payload),
|
|
806
|
+
format: "rrweb-snapshot"
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function injectAdoptedStyleSheets() {
|
|
810
|
+
const injected = [];
|
|
811
|
+
const collect = (sheets) => {
|
|
812
|
+
if (!sheets || sheets.length === 0) return "";
|
|
813
|
+
const chunks = [];
|
|
814
|
+
for (const sheet of sheets) {
|
|
833
815
|
try {
|
|
834
|
-
const
|
|
835
|
-
|
|
816
|
+
const rules = sheet.cssRules;
|
|
817
|
+
for (const rule of Array.from(rules)) chunks.push(rule.cssText);
|
|
836
818
|
} catch {
|
|
837
|
-
return "";
|
|
838
819
|
}
|
|
839
820
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
for (const rule of Array.from(rules)) chunks.push(rule.cssText);
|
|
854
|
-
} catch {
|
|
821
|
+
return chunks.join("\n");
|
|
822
|
+
};
|
|
823
|
+
const inject = (parent, css) => {
|
|
824
|
+
if (!css) return;
|
|
825
|
+
const ownerDoc = parent instanceof Document ? parent : parent.ownerDocument;
|
|
826
|
+
if (!ownerDoc) return;
|
|
827
|
+
const style = ownerDoc.createElement("style");
|
|
828
|
+
style.setAttribute("data-botim-adopted", "1");
|
|
829
|
+
style.textContent = css;
|
|
830
|
+
const target = parent instanceof Document ? parent.head ?? parent.documentElement ?? parent.body : parent;
|
|
831
|
+
if (target) {
|
|
832
|
+
target.insertBefore(style, target.firstChild);
|
|
833
|
+
injected.push(style);
|
|
855
834
|
}
|
|
856
|
-
}
|
|
857
|
-
return chunks.join("\n");
|
|
858
|
-
}
|
|
859
|
-
async function captureViaSvgForeignObject() {
|
|
860
|
-
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
861
|
-
const w = Math.max(1, Math.min(window.innerWidth || document.documentElement.clientWidth || 1024, 2400));
|
|
862
|
-
const h = Math.max(1, Math.min(document.documentElement.scrollHeight, 4e3));
|
|
863
|
-
const inlinedCss = readInlineableStyles();
|
|
864
|
-
const bodyHtml = serializeComposed(document.body, { stripCrossOriginImages: true }, 0);
|
|
865
|
-
const htmlStr = `<html xmlns="http://www.w3.org/1999/xhtml"><body>${bodyHtml}</body></html>`;
|
|
866
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}"><foreignObject width="100%" height="100%">` + (inlinedCss ? `<style xmlns="http://www.w3.org/1999/xhtml">${escapeForXml(inlinedCss)}</style>` : "") + htmlStr + `</foreignObject></svg>`;
|
|
867
|
-
const blobUrl = URL.createObjectURL(
|
|
868
|
-
new Blob([svg], { type: "image/svg+xml;charset=utf-8" })
|
|
869
|
-
);
|
|
835
|
+
};
|
|
870
836
|
try {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
if (!ctx) throw new Error("canvas 2D context unavailable");
|
|
877
|
-
const pageBg = getComputedStyle(document.body).backgroundColor || "#ffffff";
|
|
878
|
-
ctx.fillStyle = pageBg.startsWith("rgba(0, 0, 0, 0)") ? "#ffffff" : pageBg;
|
|
879
|
-
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
880
|
-
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
881
|
-
const dataUrl = canvas.toDataURL("image/jpeg", 0.85);
|
|
882
|
-
return { data: dataUrl.split(",")[1], format: "jpeg-base64" };
|
|
883
|
-
} finally {
|
|
884
|
-
URL.revokeObjectURL(blobUrl);
|
|
837
|
+
inject(
|
|
838
|
+
document,
|
|
839
|
+
collect(document.adoptedStyleSheets)
|
|
840
|
+
);
|
|
841
|
+
} catch {
|
|
885
842
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
<head>
|
|
905
|
-
<meta charset="utf-8">
|
|
906
|
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
907
|
-
<base href="${escapeAttr(location.href)}">
|
|
908
|
-
` + (inlinedCss ? `<style data-botim-snapshot="1">${inlinedCss}</style>
|
|
909
|
-
` : "") + `</head>
|
|
910
|
-
<body>${bodyHtml}</body>
|
|
911
|
-
</html>`;
|
|
912
|
-
return {
|
|
913
|
-
data: JSON.stringify({
|
|
914
|
-
html,
|
|
915
|
-
viewport: { w: window.innerWidth, h: window.innerHeight },
|
|
916
|
-
url: location.href,
|
|
917
|
-
capturedAt: Date.now()
|
|
918
|
-
}),
|
|
919
|
-
format: "html-snapshot"
|
|
843
|
+
const walkRoot = (root) => {
|
|
844
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
845
|
+
let n = walker.currentNode;
|
|
846
|
+
while (n) {
|
|
847
|
+
const el = n;
|
|
848
|
+
const sr = el.shadowRoot;
|
|
849
|
+
if (sr) {
|
|
850
|
+
try {
|
|
851
|
+
inject(
|
|
852
|
+
sr,
|
|
853
|
+
collect(sr.adoptedStyleSheets)
|
|
854
|
+
);
|
|
855
|
+
} catch {
|
|
856
|
+
}
|
|
857
|
+
walkRoot(sr);
|
|
858
|
+
}
|
|
859
|
+
n = walker.nextNode();
|
|
860
|
+
}
|
|
920
861
|
};
|
|
862
|
+
try {
|
|
863
|
+
walkRoot(document);
|
|
864
|
+
} catch {
|
|
865
|
+
}
|
|
866
|
+
return injected;
|
|
921
867
|
}
|
|
922
868
|
function registerBuiltins(registry, hooks = {}) {
|
|
923
869
|
registry.register("ping", ping);
|