@pagepocket/lib 0.8.6 → 0.9.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/cheerio/types.d.ts +5 -0
- package/dist/cheerio/types.js +1 -0
- package/dist/core/completion.js +2 -1
- package/dist/core/content-store.js +2 -2
- package/dist/css-rewrite.d.ts +1 -1
- package/dist/css-rewrite.js +2 -2
- package/dist/hackers/replay-dom-rewrite/script-part-1.d.ts +1 -0
- package/dist/hackers/replay-dom-rewrite/script-part-1.js +202 -0
- package/dist/hackers/replay-dom-rewrite/script-part-2.d.ts +1 -0
- package/dist/hackers/replay-dom-rewrite/script-part-2.js +173 -0
- package/dist/hackers/replay-dom-rewrite.js +3 -373
- package/dist/hackers/replay-svg-image.js +32 -8
- package/dist/hackers/replay-xhr.js +3 -3
- package/dist/path-resolver.js +2 -2
- package/dist/replace-elements/actions.d.ts +3 -3
- package/dist/replace-elements/actions.js +36 -16
- package/dist/replace-elements/match.d.ts +2 -2
- package/dist/replace-elements/match.js +22 -11
- package/dist/replace-elements/normalize.d.ts +1 -1
- package/dist/replace-elements/normalize.js +4 -2
- package/dist/replay/match-api.js +29 -17
- package/dist/replay/templates/replay-script-template.js +16 -332
- package/dist/replay/templates/replay-script-template.part-1.d.ts +5 -0
- package/dist/replay/templates/replay-script-template.part-1.js +101 -0
- package/dist/replay/templates/replay-script-template.part-2.d.ts +3 -0
- package/dist/replay/templates/replay-script-template.part-2.js +222 -0
- package/dist/replay/templates/replay-script-template.part-3.d.ts +3 -0
- package/dist/replay/templates/replay-script-template.part-3.js +9 -0
- package/dist/resource-proxy/pathname-variants.js +8 -5
- package/dist/resource-proxy.js +10 -10
- package/dist/resources.d.ts +3 -2
- package/dist/resources.js +6 -3
- package/dist/rewrite-links/js-imports.d.ts +1 -1
- package/dist/rewrite-links/link-rel.d.ts +2 -2
- package/dist/rewrite-links/meta-refresh.d.ts +1 -1
- package/dist/rewrite-links/meta-refresh.js +6 -3
- package/dist/rewrite-links/srcset.d.ts +1 -1
- package/dist/rewrite-links/srcset.js +4 -2
- package/dist/rewrite-links/url-resolve.d.ts +2 -2
- package/dist/rewrite-links/url-resolve.js +2 -2
- package/dist/rewrite-links.d.ts +1 -1
- package/dist/rewrite-links.js +12 -6
- package/dist/snapshot-builder/build-snapshot.js +2 -3
- package/dist/snapshot-builder/capture-index/index-capture.js +2 -1
- package/dist/snapshot-builder/emit-document.d.ts +1 -1
- package/dist/snapshot-builder/emit-document.js +1 -1
- package/dist/snapshot-builder/grouping.js +2 -2
- package/dist/snapshot-builder/path-map.d.ts +1 -1
- package/dist/snapshot-builder/path-map.js +1 -1
- package/dist/snapshot-builder/resources-path.js +8 -4
- package/dist/snapshot-builder/rewrite-resource.d.ts +2 -2
- package/dist/snapshot-builder/rewrite-resource.js +2 -2
- package/dist/types.d.ts +3 -3
- package/dist/units/internal/async-queue.d.ts +9 -0
- package/dist/units/internal/async-queue.js +57 -0
- package/dist/units/internal/deferred-tracker.d.ts +5 -0
- package/dist/units/internal/deferred-tracker.js +13 -0
- package/dist/units/internal/runtime.d.ts +37 -0
- package/dist/units/internal/runtime.js +113 -0
- package/dist/units/runner.js +3 -184
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +6 -6
- package/package.json +5 -4
- package/README.md +0 -357
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/core/completion.js
CHANGED
|
@@ -17,7 +17,8 @@ export const networkIdle = (ms, checkInterval = 100) => ({
|
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
export const normalizeCompletion = (completion) => {
|
|
20
|
-
if (!completion)
|
|
20
|
+
if (!completion) {
|
|
21
21
|
return [];
|
|
22
|
+
}
|
|
22
23
|
return Array.isArray(completion) ? completion : [completion];
|
|
23
24
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
1
3
|
import { readBinary, remove, write } from "@pagepocket/uni-fs";
|
|
2
4
|
import { streamFromUint8Array } from "../utils/streams.js";
|
|
3
5
|
import { hashString, toUint8Array } from "../utils.js";
|
|
@@ -46,8 +48,6 @@ export class HybridContentStore {
|
|
|
46
48
|
if (!this.baseDir || this.baseDir === "/" || this.baseDir === ".") {
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
const { resolve, isAbsolute } = await import("node:path");
|
|
50
|
-
const { rm } = await import("node:fs/promises");
|
|
51
51
|
const target = isAbsolute(this.baseDir) ? this.baseDir : resolve(this.baseDir);
|
|
52
52
|
await rm(target, { recursive: true, force: true });
|
|
53
53
|
}
|
package/dist/css-rewrite.d.ts
CHANGED
package/dist/css-rewrite.js
CHANGED
|
@@ -26,7 +26,7 @@ export const rewriteCssText = async (input) => {
|
|
|
26
26
|
return new URL(rawUrl, cssUrl).toString();
|
|
27
27
|
}
|
|
28
28
|
catch {
|
|
29
|
-
return
|
|
29
|
+
return undefined;
|
|
30
30
|
}
|
|
31
31
|
})();
|
|
32
32
|
if (absolute) {
|
|
@@ -53,7 +53,7 @@ export const rewriteCssText = async (input) => {
|
|
|
53
53
|
return new URL(rawUrl, cssUrl).toString();
|
|
54
54
|
}
|
|
55
55
|
catch {
|
|
56
|
-
return
|
|
56
|
+
return undefined;
|
|
57
57
|
}
|
|
58
58
|
})();
|
|
59
59
|
if (absolute) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const replayDomRewriteScriptPart1 = "\n const transparentGif = \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==\";\n const emptyScript = \"data:text/javascript,/*pagepocket-missing*/\";\n const emptyStyle = \"data:text/css,/*pagepocket-missing*/\";\n\n let readyResolved = false;\n if (ready && typeof ready.then === \"function\") {\n ready.then(() => {\n readyResolved = true;\n });\n } else {\n readyResolved = true;\n }\n\n const onReady = (callback) => {\n if (readyResolved) {\n callback();\n return;\n }\n if (ready && typeof ready.then === \"function\") {\n ready.then(callback);\n } else {\n callback();\n }\n };\n\n const rewritten = new WeakMap();\n\n const shouldRewriteAttr = (element, attr) => {\n try {\n const tag = String((element && element.tagName) || \"\").toLowerCase();\n const name = String(attr || \"\").toLowerCase();\n\n if (!tag || !name) {\n return false;\n }\n\n if (tag === \"a\" && name === \"href\") {\n return false;\n }\n\n if (name === \"src\") {\n return (\n tag === \"img\" ||\n tag === \"source\" ||\n tag === \"video\" ||\n tag === \"audio\" ||\n tag === \"script\" ||\n tag === \"iframe\" ||\n tag === \"object\" ||\n tag === \"embed\" ||\n tag === \"track\"\n );\n }\n\n if (name === \"href\") {\n if (tag !== \"link\") {\n return false;\n }\n\n const rel = String((element.getAttribute && element.getAttribute(\"rel\")) || \"\").toLowerCase();\n if (rel.includes(\"stylesheet\") || rel.includes(\"icon\")) {\n return true;\n }\n\n if (rel.includes(\"preload\") || rel.includes(\"prefetch\") || rel.includes(\"modulepreload\")) {\n return true;\n }\n\n return false;\n }\n\n if (name === \"srcset\") {\n return tag === \"img\" || tag === \"source\";\n }\n\n return false;\n } catch {\n return false;\n }\n };\n\n const rewriteSrcset = (value) => {\n if (!value) return value;\n\n try {\n const trimmed = String(value || \"\").trim();\n const hasFetchTransform = trimmed.includes(\"/image/fetch/\");\n const hasEncodedUrlTail = trimmed.includes(\"https%3A%2F%2F\");\n const hasCommaTokens =\n trimmed.includes(\",w_\") ||\n trimmed.includes(\", w_\") ||\n trimmed.includes(\",h_\") ||\n trimmed.includes(\", h_\") ||\n trimmed.includes(\",c_\") ||\n trimmed.includes(\", c_\");\n\n if (hasFetchTransform && hasEncodedUrlTail && hasCommaTokens) {\n return \"\";\n }\n } catch {}\n\n return value\n .split(\",\")\n .map((part) => {\n const trimmed = part.trim();\n if (!trimmed) return trimmed;\n const pieces = trimmed.split(/\\s+/, 2);\n const url = pieces[0];\n const descriptor = pieces[1];\n if (isLocalResource(url)) return trimmed;\n const localPath = findLocalPath(url);\n if (localPath) {\n return descriptor ? localPath + \" \" + descriptor : localPath;\n }\n return trimmed;\n })\n .join(\",\");\n };\n\n const rewriteElement = (element) => {\n if (!element || !element.getAttribute) return;\n if (!readyResolved) {\n onReady(() => rewriteElement(element));\n return;\n }\n const prev = rewritten.get(element);\n const currentSrc = element.getAttribute(\"src\");\n const currentHref = element.getAttribute(\"href\");\n const currentSrcset = element.getAttribute(\"srcset\");\n if (\n prev &&\n prev.src === currentSrc &&\n prev.href === currentHref &&\n prev.srcset === currentSrcset\n ) {\n return;\n }\n const tag = (element.tagName || \"\").toLowerCase();\n if (\n tag === \"img\" ||\n tag === \"source\" ||\n tag === \"video\" ||\n tag === \"audio\" ||\n tag === \"script\" ||\n tag === \"iframe\" ||\n tag === \"object\" ||\n tag === \"embed\" ||\n tag === \"track\"\n ) {\n const src = currentSrc;\n if (src && !src.startsWith(\"data:\") && !src.startsWith(\"blob:\")) {\n const next = rewriteResourceUrl(src, { kind: \"attr\", tag, attr: \"src\" });\n if (next && next !== src) {\n element.setAttribute(\"src\", next);\n return;\n }\n }\n }\n\n if (tag === \"link\") {\n const href = currentHref;\n const rel = (element.getAttribute(\"rel\") || \"\").toLowerCase();\n if (href && !href.startsWith(\"data:\") && !href.startsWith(\"blob:\")) {\n if (\n rel.includes(\"stylesheet\") ||\n rel.includes(\"icon\") ||\n rel.includes(\"preload\") ||\n rel.includes(\"prefetch\") ||\n rel.includes(\"modulepreload\")\n ) {\n const as = (element.getAttribute(\"as\") || \"\").toLowerCase();\n const fallbackType =\n rel.includes(\"stylesheet\") || (rel.includes(\"preload\") && as === \"style\")\n ? \"text/css\"\n : undefined;\n const next = rewriteResourceUrl(href, {\n kind: \"attr\",\n tag,\n attr: \"href\",\n fallbackType\n });\n if (next && next !== href) {\n element.setAttribute(\"href\", next);\n return;\n }\n }\n }\n }\n\n const srcset = currentSrcset;\n if (srcset) {\n element.setAttribute(\"srcset\", rewriteSrcset(srcset));\n }\n\n rewritten.set(element, {\n src: element.getAttribute(\"src\"),\n href: element.getAttribute(\"href\"),\n srcset: element.getAttribute(\"srcset\")\n });\n };\n";
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
export const replayDomRewriteScriptPart1 = `
|
|
2
|
+
const transparentGif = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
|
|
3
|
+
const emptyScript = "data:text/javascript,/*pagepocket-missing*/";
|
|
4
|
+
const emptyStyle = "data:text/css,/*pagepocket-missing*/";
|
|
5
|
+
|
|
6
|
+
let readyResolved = false;
|
|
7
|
+
if (ready && typeof ready.then === "function") {
|
|
8
|
+
ready.then(() => {
|
|
9
|
+
readyResolved = true;
|
|
10
|
+
});
|
|
11
|
+
} else {
|
|
12
|
+
readyResolved = true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const onReady = (callback) => {
|
|
16
|
+
if (readyResolved) {
|
|
17
|
+
callback();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (ready && typeof ready.then === "function") {
|
|
21
|
+
ready.then(callback);
|
|
22
|
+
} else {
|
|
23
|
+
callback();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const rewritten = new WeakMap();
|
|
28
|
+
|
|
29
|
+
const shouldRewriteAttr = (element, attr) => {
|
|
30
|
+
try {
|
|
31
|
+
const tag = String((element && element.tagName) || "").toLowerCase();
|
|
32
|
+
const name = String(attr || "").toLowerCase();
|
|
33
|
+
|
|
34
|
+
if (!tag || !name) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (tag === "a" && name === "href") {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (name === "src") {
|
|
43
|
+
return (
|
|
44
|
+
tag === "img" ||
|
|
45
|
+
tag === "source" ||
|
|
46
|
+
tag === "video" ||
|
|
47
|
+
tag === "audio" ||
|
|
48
|
+
tag === "script" ||
|
|
49
|
+
tag === "iframe" ||
|
|
50
|
+
tag === "object" ||
|
|
51
|
+
tag === "embed" ||
|
|
52
|
+
tag === "track"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (name === "href") {
|
|
57
|
+
if (tag !== "link") {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const rel = String((element.getAttribute && element.getAttribute("rel")) || "").toLowerCase();
|
|
62
|
+
if (rel.includes("stylesheet") || rel.includes("icon")) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (rel.includes("preload") || rel.includes("prefetch") || rel.includes("modulepreload")) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (name === "srcset") {
|
|
74
|
+
return tag === "img" || tag === "source";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return false;
|
|
78
|
+
} catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const rewriteSrcset = (value) => {
|
|
84
|
+
if (!value) return value;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const trimmed = String(value || "").trim();
|
|
88
|
+
const hasFetchTransform = trimmed.includes("/image/fetch/");
|
|
89
|
+
const hasEncodedUrlTail = trimmed.includes("https%3A%2F%2F");
|
|
90
|
+
const hasCommaTokens =
|
|
91
|
+
trimmed.includes(",w_") ||
|
|
92
|
+
trimmed.includes(", w_") ||
|
|
93
|
+
trimmed.includes(",h_") ||
|
|
94
|
+
trimmed.includes(", h_") ||
|
|
95
|
+
trimmed.includes(",c_") ||
|
|
96
|
+
trimmed.includes(", c_");
|
|
97
|
+
|
|
98
|
+
if (hasFetchTransform && hasEncodedUrlTail && hasCommaTokens) {
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
} catch {}
|
|
102
|
+
|
|
103
|
+
return value
|
|
104
|
+
.split(",")
|
|
105
|
+
.map((part) => {
|
|
106
|
+
const trimmed = part.trim();
|
|
107
|
+
if (!trimmed) return trimmed;
|
|
108
|
+
const pieces = trimmed.split(/\\s+/, 2);
|
|
109
|
+
const url = pieces[0];
|
|
110
|
+
const descriptor = pieces[1];
|
|
111
|
+
if (isLocalResource(url)) return trimmed;
|
|
112
|
+
const localPath = findLocalPath(url);
|
|
113
|
+
if (localPath) {
|
|
114
|
+
return descriptor ? localPath + " " + descriptor : localPath;
|
|
115
|
+
}
|
|
116
|
+
return trimmed;
|
|
117
|
+
})
|
|
118
|
+
.join(",");
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const rewriteElement = (element) => {
|
|
122
|
+
if (!element || !element.getAttribute) return;
|
|
123
|
+
if (!readyResolved) {
|
|
124
|
+
onReady(() => rewriteElement(element));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const prev = rewritten.get(element);
|
|
128
|
+
const currentSrc = element.getAttribute("src");
|
|
129
|
+
const currentHref = element.getAttribute("href");
|
|
130
|
+
const currentSrcset = element.getAttribute("srcset");
|
|
131
|
+
if (
|
|
132
|
+
prev &&
|
|
133
|
+
prev.src === currentSrc &&
|
|
134
|
+
prev.href === currentHref &&
|
|
135
|
+
prev.srcset === currentSrcset
|
|
136
|
+
) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const tag = (element.tagName || "").toLowerCase();
|
|
140
|
+
if (
|
|
141
|
+
tag === "img" ||
|
|
142
|
+
tag === "source" ||
|
|
143
|
+
tag === "video" ||
|
|
144
|
+
tag === "audio" ||
|
|
145
|
+
tag === "script" ||
|
|
146
|
+
tag === "iframe" ||
|
|
147
|
+
tag === "object" ||
|
|
148
|
+
tag === "embed" ||
|
|
149
|
+
tag === "track"
|
|
150
|
+
) {
|
|
151
|
+
const src = currentSrc;
|
|
152
|
+
if (src && !src.startsWith("data:") && !src.startsWith("blob:")) {
|
|
153
|
+
const next = rewriteResourceUrl(src, { kind: "attr", tag, attr: "src" });
|
|
154
|
+
if (next && next !== src) {
|
|
155
|
+
element.setAttribute("src", next);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (tag === "link") {
|
|
162
|
+
const href = currentHref;
|
|
163
|
+
const rel = (element.getAttribute("rel") || "").toLowerCase();
|
|
164
|
+
if (href && !href.startsWith("data:") && !href.startsWith("blob:")) {
|
|
165
|
+
if (
|
|
166
|
+
rel.includes("stylesheet") ||
|
|
167
|
+
rel.includes("icon") ||
|
|
168
|
+
rel.includes("preload") ||
|
|
169
|
+
rel.includes("prefetch") ||
|
|
170
|
+
rel.includes("modulepreload")
|
|
171
|
+
) {
|
|
172
|
+
const as = (element.getAttribute("as") || "").toLowerCase();
|
|
173
|
+
const fallbackType =
|
|
174
|
+
rel.includes("stylesheet") || (rel.includes("preload") && as === "style")
|
|
175
|
+
? "text/css"
|
|
176
|
+
: undefined;
|
|
177
|
+
const next = rewriteResourceUrl(href, {
|
|
178
|
+
kind: "attr",
|
|
179
|
+
tag,
|
|
180
|
+
attr: "href",
|
|
181
|
+
fallbackType
|
|
182
|
+
});
|
|
183
|
+
if (next && next !== href) {
|
|
184
|
+
element.setAttribute("href", next);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const srcset = currentSrcset;
|
|
192
|
+
if (srcset) {
|
|
193
|
+
element.setAttribute("srcset", rewriteSrcset(srcset));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
rewritten.set(element, {
|
|
197
|
+
src: element.getAttribute("src"),
|
|
198
|
+
href: element.getAttribute("href"),
|
|
199
|
+
srcset: element.getAttribute("srcset")
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const replayDomRewriteScriptPart2 = "\n const originalSetAttribute = Element.prototype.setAttribute;\n Element.prototype.setAttribute = function(name, value) {\n const attr = String(name).toLowerCase();\n if (attr === \"src\" || attr === \"href\" || attr === \"srcset\") {\n if (!readyResolved) {\n const pendingValue = String(value);\n onReady(() => originalSetAttribute.call(this, name, pendingValue));\n return;\n }\n if (attr === \"srcset\") {\n const rewritten = rewriteSrcset(String(value));\n return originalSetAttribute.call(this, name, rewritten);\n }\n\n if (!shouldRewriteAttr(this, attr)) {\n return originalSetAttribute.call(this, name, value);\n }\n\n const tag = (this.tagName || \"\").toLowerCase();\n const rel = (this.getAttribute && this.getAttribute(\"rel\")) || \"\";\n const relLower = rel.toLowerCase();\n const as = String((this.getAttribute && this.getAttribute(\"as\")) || \"\").toLowerCase();\n const fallbackType =\n attr === \"href\" && (relLower.includes(\"stylesheet\") || (relLower.includes(\"preload\") && as === \"style\"))\n ? \"text/css\"\n : undefined;\n\n const next = rewriteResourceUrl(String(value), {\n kind: \"setAttribute\",\n tag,\n attr,\n fallbackType\n });\n\n return originalSetAttribute.call(this, name, next);\n }\n return originalSetAttribute.call(this, name, value);\n };\n\n const patchProperty = (proto, prop, handler) => {\n try {\n const desc = Object.getOwnPropertyDescriptor(proto, prop);\n if (!desc || !desc.set) return;\n Object.defineProperty(proto, prop, {\n configurable: true,\n get: desc.get,\n set: function(value) {\n return handler.call(this, value, desc.set);\n }\n });\n } catch {}\n };\n\n patchProperty(HTMLImageElement.prototype, \"src\", function(value, setter) {\n const rawValue = String(value);\n if (!readyResolved) {\n onReady(() => {\n const next = rewriteResourceUrl(rawValue, { kind: \"setter\", tag: \"img\", attr: \"src\" });\n setter.call(this, next);\n });\n return;\n }\n const next = rewriteResourceUrl(rawValue, { kind: \"setter\", tag: \"img\", attr: \"src\" });\n setter.call(this, next);\n });\n\n patchProperty(HTMLScriptElement.prototype, \"src\", function(value, setter) {\n const rawValue = String(value);\n if (!readyResolved) {\n onReady(() => {\n const next = rewriteResourceUrl(rawValue, { kind: \"setter\", tag: \"script\", attr: \"src\" });\n setter.call(this, next);\n });\n return;\n }\n const next = rewriteResourceUrl(rawValue, { kind: \"setter\", tag: \"script\", attr: \"src\" });\n setter.call(this, next);\n });\n\n patchProperty(HTMLLinkElement.prototype, \"href\", function(value, setter) {\n const rawValue = String(value);\n const rel = (this.getAttribute && this.getAttribute(\"rel\")) || \"\";\n const relLower = rel.toLowerCase();\n const as = String((this.getAttribute && this.getAttribute(\"as\")) || \"\").toLowerCase();\n if (!readyResolved) {\n onReady(() => {\n if (\n !relLower.includes(\"stylesheet\") &&\n !relLower.includes(\"icon\") &&\n !relLower.includes(\"preload\") &&\n !relLower.includes(\"prefetch\") &&\n !relLower.includes(\"modulepreload\")\n ) {\n setter.call(this, rawValue);\n return;\n }\n const fallbackType =\n relLower.includes(\"stylesheet\") || (relLower.includes(\"preload\") && as === \"style\")\n ? \"text/css\"\n : undefined;\n const next = rewriteResourceUrl(rawValue, {\n kind: \"setter\",\n tag: \"link\",\n attr: \"href\",\n fallbackType\n });\n setter.call(this, next);\n });\n return;\n }\n if (\n !relLower.includes(\"stylesheet\") &&\n !relLower.includes(\"icon\") &&\n !relLower.includes(\"preload\") &&\n !relLower.includes(\"prefetch\") &&\n !relLower.includes(\"modulepreload\")\n ) {\n setter.call(this, rawValue);\n return;\n }\n const fallbackType =\n relLower.includes(\"stylesheet\") || (relLower.includes(\"preload\") && as === \"style\")\n ? \"text/css\"\n : undefined;\n const next = rewriteResourceUrl(rawValue, {\n kind: \"setter\",\n tag: \"link\",\n attr: \"href\",\n fallbackType\n });\n setter.call(this, next);\n });\n\n patchProperty(HTMLImageElement.prototype, \"srcset\", function(value, setter) {\n const rawValue = String(value);\n if (!readyResolved) {\n onReady(() => {\n const next = rewriteSrcset(rawValue);\n setter.call(this, next);\n });\n return;\n }\n const next = rewriteSrcset(rawValue);\n setter.call(this, next);\n });\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === \"attributes\" && mutation.target) {\n rewriteElement(mutation.target);\n }\n if (mutation.type === \"childList\") {\n mutation.addedNodes.forEach((node) => {\n if (node && node.nodeType === 1) {\n rewriteElement(node);\n }\n });\n }\n }\n });\n\n observer.observe(document.documentElement, {\n attributes: true,\n childList: true,\n subtree: true,\n attributeFilter: [\"src\", \"href\", \"srcset\", \"rel\", \"as\"]\n });\n\n document\n .querySelectorAll(\"img,source,video,audio,script,link,iframe\")\n .forEach((el) => rewriteElement(el));\n";
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export const replayDomRewriteScriptPart2 = `
|
|
2
|
+
const originalSetAttribute = Element.prototype.setAttribute;
|
|
3
|
+
Element.prototype.setAttribute = function(name, value) {
|
|
4
|
+
const attr = String(name).toLowerCase();
|
|
5
|
+
if (attr === "src" || attr === "href" || attr === "srcset") {
|
|
6
|
+
if (!readyResolved) {
|
|
7
|
+
const pendingValue = String(value);
|
|
8
|
+
onReady(() => originalSetAttribute.call(this, name, pendingValue));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (attr === "srcset") {
|
|
12
|
+
const rewritten = rewriteSrcset(String(value));
|
|
13
|
+
return originalSetAttribute.call(this, name, rewritten);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!shouldRewriteAttr(this, attr)) {
|
|
17
|
+
return originalSetAttribute.call(this, name, value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const tag = (this.tagName || "").toLowerCase();
|
|
21
|
+
const rel = (this.getAttribute && this.getAttribute("rel")) || "";
|
|
22
|
+
const relLower = rel.toLowerCase();
|
|
23
|
+
const as = String((this.getAttribute && this.getAttribute("as")) || "").toLowerCase();
|
|
24
|
+
const fallbackType =
|
|
25
|
+
attr === "href" && (relLower.includes("stylesheet") || (relLower.includes("preload") && as === "style"))
|
|
26
|
+
? "text/css"
|
|
27
|
+
: undefined;
|
|
28
|
+
|
|
29
|
+
const next = rewriteResourceUrl(String(value), {
|
|
30
|
+
kind: "setAttribute",
|
|
31
|
+
tag,
|
|
32
|
+
attr,
|
|
33
|
+
fallbackType
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return originalSetAttribute.call(this, name, next);
|
|
37
|
+
}
|
|
38
|
+
return originalSetAttribute.call(this, name, value);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const patchProperty = (proto, prop, handler) => {
|
|
42
|
+
try {
|
|
43
|
+
const desc = Object.getOwnPropertyDescriptor(proto, prop);
|
|
44
|
+
if (!desc || !desc.set) return;
|
|
45
|
+
Object.defineProperty(proto, prop, {
|
|
46
|
+
configurable: true,
|
|
47
|
+
get: desc.get,
|
|
48
|
+
set: function(value) {
|
|
49
|
+
return handler.call(this, value, desc.set);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
} catch {}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
patchProperty(HTMLImageElement.prototype, "src", function(value, setter) {
|
|
56
|
+
const rawValue = String(value);
|
|
57
|
+
if (!readyResolved) {
|
|
58
|
+
onReady(() => {
|
|
59
|
+
const next = rewriteResourceUrl(rawValue, { kind: "setter", tag: "img", attr: "src" });
|
|
60
|
+
setter.call(this, next);
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const next = rewriteResourceUrl(rawValue, { kind: "setter", tag: "img", attr: "src" });
|
|
65
|
+
setter.call(this, next);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
patchProperty(HTMLScriptElement.prototype, "src", function(value, setter) {
|
|
69
|
+
const rawValue = String(value);
|
|
70
|
+
if (!readyResolved) {
|
|
71
|
+
onReady(() => {
|
|
72
|
+
const next = rewriteResourceUrl(rawValue, { kind: "setter", tag: "script", attr: "src" });
|
|
73
|
+
setter.call(this, next);
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const next = rewriteResourceUrl(rawValue, { kind: "setter", tag: "script", attr: "src" });
|
|
78
|
+
setter.call(this, next);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
patchProperty(HTMLLinkElement.prototype, "href", function(value, setter) {
|
|
82
|
+
const rawValue = String(value);
|
|
83
|
+
const rel = (this.getAttribute && this.getAttribute("rel")) || "";
|
|
84
|
+
const relLower = rel.toLowerCase();
|
|
85
|
+
const as = String((this.getAttribute && this.getAttribute("as")) || "").toLowerCase();
|
|
86
|
+
if (!readyResolved) {
|
|
87
|
+
onReady(() => {
|
|
88
|
+
if (
|
|
89
|
+
!relLower.includes("stylesheet") &&
|
|
90
|
+
!relLower.includes("icon") &&
|
|
91
|
+
!relLower.includes("preload") &&
|
|
92
|
+
!relLower.includes("prefetch") &&
|
|
93
|
+
!relLower.includes("modulepreload")
|
|
94
|
+
) {
|
|
95
|
+
setter.call(this, rawValue);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const fallbackType =
|
|
99
|
+
relLower.includes("stylesheet") || (relLower.includes("preload") && as === "style")
|
|
100
|
+
? "text/css"
|
|
101
|
+
: undefined;
|
|
102
|
+
const next = rewriteResourceUrl(rawValue, {
|
|
103
|
+
kind: "setter",
|
|
104
|
+
tag: "link",
|
|
105
|
+
attr: "href",
|
|
106
|
+
fallbackType
|
|
107
|
+
});
|
|
108
|
+
setter.call(this, next);
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (
|
|
113
|
+
!relLower.includes("stylesheet") &&
|
|
114
|
+
!relLower.includes("icon") &&
|
|
115
|
+
!relLower.includes("preload") &&
|
|
116
|
+
!relLower.includes("prefetch") &&
|
|
117
|
+
!relLower.includes("modulepreload")
|
|
118
|
+
) {
|
|
119
|
+
setter.call(this, rawValue);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const fallbackType =
|
|
123
|
+
relLower.includes("stylesheet") || (relLower.includes("preload") && as === "style")
|
|
124
|
+
? "text/css"
|
|
125
|
+
: undefined;
|
|
126
|
+
const next = rewriteResourceUrl(rawValue, {
|
|
127
|
+
kind: "setter",
|
|
128
|
+
tag: "link",
|
|
129
|
+
attr: "href",
|
|
130
|
+
fallbackType
|
|
131
|
+
});
|
|
132
|
+
setter.call(this, next);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
patchProperty(HTMLImageElement.prototype, "srcset", function(value, setter) {
|
|
136
|
+
const rawValue = String(value);
|
|
137
|
+
if (!readyResolved) {
|
|
138
|
+
onReady(() => {
|
|
139
|
+
const next = rewriteSrcset(rawValue);
|
|
140
|
+
setter.call(this, next);
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const next = rewriteSrcset(rawValue);
|
|
145
|
+
setter.call(this, next);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const observer = new MutationObserver((mutations) => {
|
|
149
|
+
for (const mutation of mutations) {
|
|
150
|
+
if (mutation.type === "attributes" && mutation.target) {
|
|
151
|
+
rewriteElement(mutation.target);
|
|
152
|
+
}
|
|
153
|
+
if (mutation.type === "childList") {
|
|
154
|
+
mutation.addedNodes.forEach((node) => {
|
|
155
|
+
if (node && node.nodeType === 1) {
|
|
156
|
+
rewriteElement(node);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
observer.observe(document.documentElement, {
|
|
164
|
+
attributes: true,
|
|
165
|
+
childList: true,
|
|
166
|
+
subtree: true,
|
|
167
|
+
attributeFilter: ["src", "href", "srcset", "rel", "as"]
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
document
|
|
171
|
+
.querySelectorAll("img,source,video,audio,script,link,iframe")
|
|
172
|
+
.forEach((el) => rewriteElement(el));
|
|
173
|
+
`;
|