@pagepocket/lib 0.4.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.
Files changed (47) hide show
  1. package/dist/content-type.d.ts +2 -0
  2. package/dist/content-type.js +36 -0
  3. package/dist/css-rewrite.d.ts +9 -0
  4. package/dist/css-rewrite.js +76 -0
  5. package/dist/download-resources.d.ts +25 -0
  6. package/dist/download-resources.js +163 -0
  7. package/dist/hack-html.d.ts +9 -0
  8. package/dist/hack-html.js +32 -0
  9. package/dist/hackers/index.d.ts +3 -0
  10. package/dist/hackers/index.js +22 -0
  11. package/dist/hackers/preload-fetch.d.ts +2 -0
  12. package/dist/hackers/preload-fetch.js +56 -0
  13. package/dist/hackers/preload-xhr.d.ts +2 -0
  14. package/dist/hackers/preload-xhr.js +59 -0
  15. package/dist/hackers/replay-beacon.d.ts +2 -0
  16. package/dist/hackers/replay-beacon.js +21 -0
  17. package/dist/hackers/replay-dom-rewrite.d.ts +2 -0
  18. package/dist/hackers/replay-dom-rewrite.js +295 -0
  19. package/dist/hackers/replay-eventsource.d.ts +2 -0
  20. package/dist/hackers/replay-eventsource.js +25 -0
  21. package/dist/hackers/replay-fetch.d.ts +2 -0
  22. package/dist/hackers/replay-fetch.js +33 -0
  23. package/dist/hackers/replay-svg-image.d.ts +2 -0
  24. package/dist/hackers/replay-svg-image.js +89 -0
  25. package/dist/hackers/replay-websocket.d.ts +2 -0
  26. package/dist/hackers/replay-websocket.js +26 -0
  27. package/dist/hackers/replay-xhr.d.ts +2 -0
  28. package/dist/hackers/replay-xhr.js +91 -0
  29. package/dist/hackers/types.d.ts +10 -0
  30. package/dist/hackers/types.js +2 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.js +13 -0
  33. package/dist/network-records.d.ts +4 -0
  34. package/dist/network-records.js +83 -0
  35. package/dist/pagepocket.d.ts +18 -0
  36. package/dist/pagepocket.js +73 -0
  37. package/dist/preload.d.ts +1 -0
  38. package/dist/preload.js +60 -0
  39. package/dist/replay-script.d.ts +1 -0
  40. package/dist/replay-script.js +347 -0
  41. package/dist/resources.d.ts +16 -0
  42. package/dist/resources.js +82 -0
  43. package/dist/rewrite-links.d.ts +15 -0
  44. package/dist/rewrite-links.js +263 -0
  45. package/dist/types.d.ts +54 -0
  46. package/dist/types.js +2 -0
  47. package/package.json +29 -0
@@ -0,0 +1,2 @@
1
+ export declare const extensionFromContentType: (contentType?: string | null) => "" | ".css" | ".js" | ".png" | ".jpg" | ".gif" | ".svg" | ".woff2" | ".woff";
2
+ export declare const isTextResponse: (contentType: string) => boolean;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isTextResponse = exports.extensionFromContentType = void 0;
4
+ const extensionFromContentType = (contentType) => {
5
+ if (!contentType) {
6
+ return "";
7
+ }
8
+ if (contentType.includes("text/css"))
9
+ return ".css";
10
+ if (contentType.includes("javascript"))
11
+ return ".js";
12
+ if (contentType.includes("image/png"))
13
+ return ".png";
14
+ if (contentType.includes("image/jpeg"))
15
+ return ".jpg";
16
+ if (contentType.includes("image/gif"))
17
+ return ".gif";
18
+ if (contentType.includes("image/svg"))
19
+ return ".svg";
20
+ if (contentType.includes("font/woff2"))
21
+ return ".woff2";
22
+ if (contentType.includes("font/woff"))
23
+ return ".woff";
24
+ return "";
25
+ };
26
+ exports.extensionFromContentType = extensionFromContentType;
27
+ const isTextResponse = (contentType) => {
28
+ const lowered = contentType.toLowerCase();
29
+ return (lowered.startsWith("text/") ||
30
+ lowered.includes("json") ||
31
+ lowered.includes("javascript") ||
32
+ lowered.includes("xml") ||
33
+ lowered.includes("svg") ||
34
+ lowered.includes("html"));
35
+ };
36
+ exports.isTextResponse = isTextResponse;
@@ -0,0 +1,9 @@
1
+ export type CssUrlResolver = (absoluteUrl: string) => Promise<string | null>;
2
+ type RewriteCssInput = {
3
+ filename: string;
4
+ extension: string;
5
+ cssUrl: string;
6
+ resolveUrl: CssUrlResolver;
7
+ };
8
+ export declare const rewriteCssUrls: (input: RewriteCssInput) => Promise<boolean>;
9
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.rewriteCssUrls = void 0;
37
+ const URL_PATTERN = /url\(\s*(['"]?)([^'")]+)\1\s*\)/g;
38
+ const rewriteCssUrls = async (input) => {
39
+ const { readText, write } = await Promise.resolve().then(() => __importStar(require("uni-fs")));
40
+ const original = await readText(input.filename, input.extension);
41
+ let updated = "";
42
+ let lastIndex = 0;
43
+ let changed = false;
44
+ for (const match of original.matchAll(URL_PATTERN)) {
45
+ const index = match.index ?? 0;
46
+ updated += original.slice(lastIndex, index);
47
+ const quote = match[1] || "";
48
+ const rawUrl = String(match[2] || "").trim();
49
+ let replacement = match[0];
50
+ if (rawUrl && !rawUrl.startsWith("data:") && !rawUrl.startsWith("blob:")) {
51
+ const absolute = (() => {
52
+ try {
53
+ return new URL(rawUrl, input.cssUrl).toString();
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ })();
59
+ if (absolute) {
60
+ const resolved = await input.resolveUrl(absolute);
61
+ if (resolved) {
62
+ replacement = `url(${quote}${resolved}${quote})`;
63
+ changed = true;
64
+ }
65
+ }
66
+ }
67
+ updated += replacement;
68
+ lastIndex = index + match[0].length;
69
+ }
70
+ updated += original.slice(lastIndex);
71
+ if (changed) {
72
+ await write(input.filename, input.extension, updated);
73
+ }
74
+ return changed;
75
+ };
76
+ exports.rewriteCssUrls = rewriteCssUrls;
@@ -0,0 +1,25 @@
1
+ import { type ResourceReference, type SrcsetReference } from "./resources";
2
+ import type { SnapshotData } from "./types";
3
+ export type DownloadedResource = {
4
+ url: string;
5
+ filename: string;
6
+ extension: string;
7
+ localPath: string;
8
+ contentType?: string | null;
9
+ size?: number;
10
+ };
11
+ type DownloadResourcesInput = {
12
+ baseUrl: string;
13
+ assetsDirName: string;
14
+ resourceUrls: ResourceReference[];
15
+ srcsetItems: SrcsetReference[];
16
+ referer?: string;
17
+ };
18
+ type DownloadResourcesResult = {
19
+ resourceMap: Map<string, DownloadedResource>;
20
+ resourceMeta: SnapshotData["resources"];
21
+ downloadedCount: number;
22
+ failedCount: number;
23
+ };
24
+ export declare const downloadResources: (input: DownloadResourcesInput) => Promise<DownloadResourcesResult>;
25
+ export {};
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.downloadResources = void 0;
37
+ const content_type_1 = require("./content-type");
38
+ const resources_1 = require("./resources");
39
+ const FNV_OFFSET = 0x811c9dc5;
40
+ const FNV_PRIME = 0x01000193;
41
+ const shouldSkipUrl = (value) => {
42
+ const trimmed = value.trim();
43
+ return (!trimmed ||
44
+ trimmed.startsWith("data:") ||
45
+ trimmed.startsWith("blob:") ||
46
+ trimmed.startsWith("mailto:") ||
47
+ trimmed.startsWith("tel:") ||
48
+ trimmed.startsWith("javascript:") ||
49
+ trimmed.startsWith("#"));
50
+ };
51
+ const hashUrl = (value) => {
52
+ let hash = FNV_OFFSET;
53
+ for (let i = 0; i < value.length; i += 1) {
54
+ hash ^= value.charCodeAt(i);
55
+ hash = (hash * FNV_PRIME) >>> 0;
56
+ }
57
+ return hash.toString(16).padStart(8, "0");
58
+ };
59
+ const extensionFromUrl = (url) => {
60
+ try {
61
+ const pathname = new URL(url).pathname;
62
+ const lastDot = pathname.lastIndexOf(".");
63
+ if (lastDot === -1) {
64
+ return "";
65
+ }
66
+ return pathname.slice(lastDot);
67
+ }
68
+ catch {
69
+ return "";
70
+ }
71
+ };
72
+ const normalizeExtension = (extension) => {
73
+ if (!extension) {
74
+ return "";
75
+ }
76
+ return extension.startsWith(".") ? extension.slice(1) : extension;
77
+ };
78
+ const buildLocalPath = (assetsDirName, filename, extension) => {
79
+ const normalizedExtension = normalizeExtension(extension);
80
+ if (!normalizedExtension) {
81
+ return `${assetsDirName}/${filename}`;
82
+ }
83
+ return `${assetsDirName}/${filename}.${normalizedExtension}`;
84
+ };
85
+ const collectSrcsetUrls = (items, baseUrl) => {
86
+ const urls = [];
87
+ for (const item of items) {
88
+ const parts = item.value.split(",").map((part) => part.trim());
89
+ for (const part of parts) {
90
+ const [rawUrl] = part.split(/\s+/, 2);
91
+ if (!rawUrl) {
92
+ continue;
93
+ }
94
+ const absolute = (0, resources_1.toAbsoluteUrl)(baseUrl, rawUrl);
95
+ urls.push(absolute);
96
+ }
97
+ }
98
+ return urls;
99
+ };
100
+ const downloadResources = async (input) => {
101
+ const { write, exists } = await Promise.resolve().then(() => __importStar(require("uni-fs")));
102
+ const resourceMap = new Map();
103
+ const resourceMeta = [];
104
+ let downloadedCount = 0;
105
+ let failedCount = 0;
106
+ const srcsetUrls = collectSrcsetUrls(input.srcsetItems, input.baseUrl);
107
+ const candidateUrls = [
108
+ ...input.resourceUrls.map((resource) => resource.url),
109
+ ...srcsetUrls
110
+ ];
111
+ for (const candidate of candidateUrls) {
112
+ if (shouldSkipUrl(candidate)) {
113
+ continue;
114
+ }
115
+ const url = (0, resources_1.toAbsoluteUrl)(input.baseUrl, candidate);
116
+ if (!url || resourceMap.has(url)) {
117
+ continue;
118
+ }
119
+ try {
120
+ const headers = {};
121
+ if (input.referer) {
122
+ headers.referer = input.referer;
123
+ }
124
+ const response = await fetch(url, { redirect: "follow", headers });
125
+ const contentType = response.headers.get("content-type");
126
+ const buffer = new Uint8Array(await response.arrayBuffer());
127
+ const extFromUrl = extensionFromUrl(url);
128
+ const extFromType = (0, content_type_1.extensionFromContentType)(contentType);
129
+ const extension = normalizeExtension(extFromUrl || extFromType);
130
+ const filename = hashUrl(url);
131
+ const localPath = buildLocalPath(input.assetsDirName, filename, extension);
132
+ if (!(await exists(input.assetsDirName + "/" + filename, extension))) {
133
+ await write(input.assetsDirName + "/" + filename, extension, buffer);
134
+ }
135
+ const entry = {
136
+ url,
137
+ filename,
138
+ extension,
139
+ localPath,
140
+ contentType,
141
+ size: buffer.byteLength
142
+ };
143
+ resourceMap.set(url, entry);
144
+ resourceMeta.push({
145
+ url,
146
+ localPath,
147
+ contentType,
148
+ size: buffer.byteLength
149
+ });
150
+ downloadedCount += 1;
151
+ }
152
+ catch {
153
+ failedCount += 1;
154
+ }
155
+ }
156
+ return {
157
+ resourceMap,
158
+ resourceMeta,
159
+ downloadedCount,
160
+ failedCount
161
+ };
162
+ };
163
+ exports.downloadResources = downloadResources;
@@ -0,0 +1,9 @@
1
+ import type { CheerioAPI } from "cheerio";
2
+ type HackHtmlInput = {
3
+ $: CheerioAPI;
4
+ baseUrl: string;
5
+ requestsPath: string;
6
+ faviconDataUrl?: string | null;
7
+ };
8
+ export declare const hackHtml: (input: HackHtmlInput) => void;
9
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hackHtml = void 0;
4
+ const preload_1 = require("./preload");
5
+ const replay_script_1 = require("./replay-script");
6
+ const hackHtml = (input) => {
7
+ const replayScript = (0, replay_script_1.buildReplayScript)(input.requestsPath, input.baseUrl);
8
+ const preloadScript = `<script>${(0, preload_1.buildPreloadScript)()}</script>`;
9
+ const head = input.$("head");
10
+ const root = input.$.root();
11
+ if (head.length) {
12
+ head.prepend(replayScript);
13
+ head.prepend(preloadScript);
14
+ }
15
+ else {
16
+ root.prepend(replayScript);
17
+ root.prepend(preloadScript);
18
+ }
19
+ if (input.faviconDataUrl) {
20
+ const existingIcon = input.$('link[rel="icon"]');
21
+ if (existingIcon.length) {
22
+ existingIcon.attr("href", input.faviconDataUrl);
23
+ }
24
+ else if (head.length) {
25
+ head.append(`<link rel="icon" href="${input.faviconDataUrl}" />`);
26
+ }
27
+ else {
28
+ root.append(`<link rel="icon" href="${input.faviconDataUrl}" />`);
29
+ }
30
+ }
31
+ };
32
+ exports.hackHtml = hackHtml;
@@ -0,0 +1,3 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const preloadHackers: ScriptHacker[];
3
+ export declare const replayHackers: ScriptHacker[];
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayHackers = exports.preloadHackers = void 0;
4
+ const preload_fetch_1 = require("./preload-fetch");
5
+ const preload_xhr_1 = require("./preload-xhr");
6
+ const replay_beacon_1 = require("./replay-beacon");
7
+ const replay_dom_rewrite_1 = require("./replay-dom-rewrite");
8
+ const replay_eventsource_1 = require("./replay-eventsource");
9
+ const replay_fetch_1 = require("./replay-fetch");
10
+ const replay_svg_image_1 = require("./replay-svg-image");
11
+ const replay_websocket_1 = require("./replay-websocket");
12
+ const replay_xhr_1 = require("./replay-xhr");
13
+ exports.preloadHackers = [preload_fetch_1.preloadFetchRecorder, preload_xhr_1.preloadXhrRecorder];
14
+ exports.replayHackers = [
15
+ replay_fetch_1.replayFetchResponder,
16
+ replay_xhr_1.replayXhrResponder,
17
+ replay_dom_rewrite_1.replayDomRewriter,
18
+ replay_svg_image_1.replaySvgImageRewriter,
19
+ replay_beacon_1.replayBeaconStub,
20
+ replay_websocket_1.replayWebSocketStub,
21
+ replay_eventsource_1.replayEventSourceStub
22
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const preloadFetchRecorder: ScriptHacker;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preloadFetchRecorder = void 0;
4
+ exports.preloadFetchRecorder = {
5
+ id: "preload-fetch-recorder",
6
+ stage: "preload",
7
+ build: () => `
8
+ // Record fetch calls and responses for replay.
9
+ const originalFetch = window.fetch.bind(window);
10
+ const recordFetch = async (input, init) => {
11
+ trackPendingStart();
12
+ const url = typeof input === "string" ? toAbsoluteUrl(input) : toAbsoluteUrl(input.url);
13
+ const method = init && init.method ? init.method : (typeof input === "string" ? "GET" : input.method || "GET");
14
+ const requestBody = normalizeBody(init && init.body ? init.body : (typeof input === "string" ? undefined : input.body));
15
+
16
+ try {
17
+ const response = await originalFetch(input, init);
18
+ const clone = response.clone();
19
+ const responseBody = await clone.text();
20
+ const headers = {};
21
+ response.headers.forEach((value, key) => {
22
+ headers[key] = value;
23
+ });
24
+ records.push({
25
+ kind: "fetch",
26
+ url,
27
+ method,
28
+ requestBody,
29
+ status: response.status,
30
+ statusText: response.statusText,
31
+ responseHeaders: headers,
32
+ responseBody,
33
+ timestamp: Date.now()
34
+ });
35
+ return response;
36
+ } catch (error) {
37
+ records.push({
38
+ kind: "fetch",
39
+ url,
40
+ method,
41
+ requestBody,
42
+ error: String(error),
43
+ timestamp: Date.now()
44
+ });
45
+ throw error;
46
+ } finally {
47
+ trackPendingEnd();
48
+ }
49
+ };
50
+
51
+ window.fetch = (input, init) => {
52
+ return recordFetch(input, init);
53
+ };
54
+ window.fetch.__pagepocketOriginal = originalFetch;
55
+ `
56
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const preloadXhrRecorder: ScriptHacker;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preloadXhrRecorder = void 0;
4
+ exports.preloadXhrRecorder = {
5
+ id: "preload-xhr-recorder",
6
+ stage: "preload",
7
+ build: () => `
8
+ // Record XHR calls and responses for replay.
9
+ const originalOpen = XMLHttpRequest.prototype.open;
10
+ const originalSend = XMLHttpRequest.prototype.send;
11
+
12
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
13
+ this.__pagepocketMethod = method;
14
+ this.__pagepocketUrl = toAbsoluteUrl(url);
15
+ return originalOpen.call(this, method, url, ...rest);
16
+ };
17
+
18
+ XMLHttpRequest.prototype.send = function(body) {
19
+ const xhr = this;
20
+ const requestBody = normalizeBody(body);
21
+
22
+ const onLoadEnd = () => {
23
+ const responseHeadersRaw = xhr.getAllResponseHeaders();
24
+ const headers = {};
25
+ responseHeadersRaw
26
+ .trim()
27
+ .split(/\\r?\\n/)
28
+ .filter(Boolean)
29
+ .forEach((line) => {
30
+ const index = line.indexOf(":");
31
+ if (index > -1) {
32
+ const key = line.slice(0, index).trim().toLowerCase();
33
+ const value = line.slice(index + 1).trim();
34
+ headers[key] = value;
35
+ }
36
+ });
37
+
38
+ records.push({
39
+ kind: "xhr",
40
+ url: xhr.__pagepocketUrl || "",
41
+ method: xhr.__pagepocketMethod || "GET",
42
+ requestBody,
43
+ status: xhr.status,
44
+ statusText: xhr.statusText,
45
+ responseHeaders: headers,
46
+ responseBody: xhr.responseText || "",
47
+ timestamp: Date.now()
48
+ });
49
+
50
+ xhr.removeEventListener("loadend", onLoadEnd);
51
+ trackPendingEnd();
52
+ };
53
+
54
+ trackPendingStart();
55
+ xhr.addEventListener("loadend", onLoadEnd);
56
+ return originalSend.call(xhr, body);
57
+ };
58
+ `
59
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayBeaconStub: ScriptHacker;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayBeaconStub = void 0;
4
+ exports.replayBeaconStub = {
5
+ id: "replay-beacon-stub",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Stub beacon calls so analytics doesn't leak outside the snapshot.
9
+ if (navigator.sendBeacon) {
10
+ const originalBeacon = navigator.sendBeacon.bind(navigator);
11
+ navigator.sendBeacon = (url, data) => {
12
+ const record = findRecord("POST", url, data);
13
+ if (record) {
14
+ return true;
15
+ }
16
+ return true;
17
+ };
18
+ navigator.sendBeacon.__pagepocketOriginal = originalBeacon;
19
+ }
20
+ `
21
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayDomRewriter: ScriptHacker;