@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,295 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayDomRewriter = void 0;
4
+ exports.replayDomRewriter = {
5
+ id: "replay-dom-rewriter",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Placeholder data URLs for missing resources.
9
+ const transparentGif = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
10
+ const emptyScript = "data:text/javascript,/*pagepocket-missing*/";
11
+ const emptyStyle = "data:text/css,/*pagepocket-missing*/";
12
+
13
+ let readyResolved = false;
14
+ if (ready && typeof ready.then === "function") {
15
+ ready.then(() => {
16
+ readyResolved = true;
17
+ });
18
+ } else {
19
+ readyResolved = true;
20
+ }
21
+
22
+ const onReady = (callback) => {
23
+ if (readyResolved) {
24
+ callback();
25
+ return;
26
+ }
27
+ if (ready && typeof ready.then === "function") {
28
+ ready.then(callback);
29
+ } else {
30
+ callback();
31
+ }
32
+ };
33
+
34
+ // Rewrite srcset values to local files only (avoid data: URLs in srcset).
35
+ const rewriteSrcset = (value) => {
36
+ if (!value) return value;
37
+ return value.split(",").map((part) => {
38
+ const trimmed = part.trim();
39
+ if (!trimmed) return trimmed;
40
+ const pieces = trimmed.split(/\\s+/, 2);
41
+ const url = pieces[0];
42
+ const descriptor = pieces[1];
43
+ if (isLocalResource(url)) return trimmed;
44
+ const localPath = findLocalPath(url);
45
+ if (localPath) {
46
+ return descriptor ? localPath + " " + descriptor : localPath;
47
+ }
48
+ return trimmed;
49
+ }).join(", ");
50
+ };
51
+
52
+ // Rewrite element attributes to local files or data URLs.
53
+ const rewriteElement = (element) => {
54
+ if (!element || !element.getAttribute) return;
55
+ if (!readyResolved) {
56
+ onReady(() => rewriteElement(element));
57
+ return;
58
+ }
59
+ const tag = (element.tagName || "").toLowerCase();
60
+ if (tag === "img" || tag === "source" || tag === "video" || tag === "audio" || tag === "script" || tag === "iframe") {
61
+ const src = element.getAttribute("src");
62
+ if (src && !isLocalResource(src) && !src.startsWith("data:") && !src.startsWith("blob:")) {
63
+ const localPath = findLocalPath(src);
64
+ if (localPath) {
65
+ element.setAttribute("src", localPath);
66
+ return;
67
+ }
68
+ const record = findByUrl(src);
69
+ const fallback = tag === "script" ? emptyScript : transparentGif;
70
+ element.setAttribute("src", record ? toDataUrl(record) : fallback);
71
+ }
72
+ }
73
+
74
+ if (tag === "link") {
75
+ const href = element.getAttribute("href");
76
+ const rel = (element.getAttribute("rel") || "").toLowerCase();
77
+ if (href && !isLocalResource(href) && !href.startsWith("data:") && !href.startsWith("blob:")) {
78
+ const localPath = findLocalPath(href);
79
+ if (localPath) {
80
+ element.setAttribute("href", localPath);
81
+ return;
82
+ }
83
+ const record = findByUrl(href);
84
+ const fallback = rel === "stylesheet" ? emptyStyle : emptyStyle;
85
+ element.setAttribute("href", record ? toDataUrl(record, "text/css") : fallback);
86
+ }
87
+ }
88
+
89
+ const srcset = element.getAttribute("srcset");
90
+ if (srcset) {
91
+ element.setAttribute("srcset", rewriteSrcset(srcset));
92
+ }
93
+ };
94
+
95
+ // Intercept DOM attribute writes to keep resources local.
96
+ const originalSetAttribute = Element.prototype.setAttribute;
97
+ Element.prototype.setAttribute = function(name, value) {
98
+ const attr = String(name).toLowerCase();
99
+ if (attr === "src" || attr === "href" || attr === "srcset") {
100
+ if (!readyResolved) {
101
+ const pendingValue = String(value);
102
+ onReady(() => originalSetAttribute.call(this, name, pendingValue));
103
+ return;
104
+ }
105
+ if (attr === "srcset") {
106
+ const rewritten = rewriteSrcset(String(value));
107
+ return originalSetAttribute.call(this, name, rewritten);
108
+ }
109
+
110
+ const tag = (this.tagName || "").toLowerCase();
111
+ const rel = (this.getAttribute && this.getAttribute("rel")) || "";
112
+ const relLower = rel.toLowerCase();
113
+
114
+ if (isLocalResource(String(value))) {
115
+ return originalSetAttribute.call(this, name, value);
116
+ }
117
+ const localPath = findLocalPath(String(value));
118
+ if (localPath) {
119
+ return originalSetAttribute.call(this, name, localPath);
120
+ }
121
+ const record = findByUrl(String(value));
122
+ if (record) {
123
+ const fallbackType = attr === "href" && relLower.includes("stylesheet") ? "text/css" : undefined;
124
+ const dataUrl = toDataUrl(record, fallbackType);
125
+ return originalSetAttribute.call(this, name, dataUrl);
126
+ }
127
+ if (attr === "src") {
128
+ const fallback = tag === "script" ? emptyScript : transparentGif;
129
+ return originalSetAttribute.call(this, name, fallback);
130
+ }
131
+ if (attr === "href") {
132
+ const fallback = relLower === "stylesheet" ? emptyStyle : emptyStyle;
133
+ return originalSetAttribute.call(this, name, fallback);
134
+ }
135
+ }
136
+ return originalSetAttribute.call(this, name, value);
137
+ };
138
+
139
+ // Patch property setters (e.g. img.src) so direct assignments are rewritten.
140
+ const patchProperty = (proto, prop, handler) => {
141
+ try {
142
+ const desc = Object.getOwnPropertyDescriptor(proto, prop);
143
+ if (!desc || !desc.set) return;
144
+ Object.defineProperty(proto, prop, {
145
+ configurable: true,
146
+ get: desc.get,
147
+ set: function(value) {
148
+ return handler.call(this, value, desc.set);
149
+ }
150
+ });
151
+ } catch {}
152
+ };
153
+
154
+ patchProperty(HTMLImageElement.prototype, "src", function(value, setter) {
155
+ const rawValue = String(value);
156
+ if (!readyResolved) {
157
+ onReady(() => {
158
+ if (isLocalResource(rawValue)) {
159
+ setter.call(this, rawValue);
160
+ return;
161
+ }
162
+ const localPath = findLocalPath(rawValue);
163
+ if (localPath) {
164
+ setter.call(this, localPath);
165
+ return;
166
+ }
167
+ const record = findByUrl(rawValue);
168
+ const next = record ? toDataUrl(record) : transparentGif;
169
+ setter.call(this, next);
170
+ });
171
+ return;
172
+ }
173
+ if (isLocalResource(rawValue)) {
174
+ setter.call(this, rawValue);
175
+ return;
176
+ }
177
+ const localPath = findLocalPath(rawValue);
178
+ if (localPath) {
179
+ setter.call(this, localPath);
180
+ return;
181
+ }
182
+ const record = findByUrl(rawValue);
183
+ const next = record ? toDataUrl(record) : transparentGif;
184
+ setter.call(this, next);
185
+ });
186
+
187
+ patchProperty(HTMLScriptElement.prototype, "src", function(value, setter) {
188
+ const rawValue = String(value);
189
+ if (!readyResolved) {
190
+ onReady(() => {
191
+ if (isLocalResource(rawValue)) {
192
+ setter.call(this, rawValue);
193
+ return;
194
+ }
195
+ const localPath = findLocalPath(rawValue);
196
+ if (localPath) {
197
+ setter.call(this, localPath);
198
+ return;
199
+ }
200
+ const record = findByUrl(rawValue);
201
+ const next = record ? toDataUrl(record) : emptyScript;
202
+ setter.call(this, next);
203
+ });
204
+ return;
205
+ }
206
+ if (isLocalResource(rawValue)) {
207
+ setter.call(this, rawValue);
208
+ return;
209
+ }
210
+ const localPath = findLocalPath(rawValue);
211
+ if (localPath) {
212
+ setter.call(this, localPath);
213
+ return;
214
+ }
215
+ const record = findByUrl(rawValue);
216
+ const next = record ? toDataUrl(record) : emptyScript;
217
+ setter.call(this, next);
218
+ });
219
+
220
+ patchProperty(HTMLLinkElement.prototype, "href", function(value, setter) {
221
+ const rawValue = String(value);
222
+ const rel = (this.getAttribute && this.getAttribute("rel")) || "";
223
+ const relLower = rel.toLowerCase();
224
+ if (!readyResolved) {
225
+ onReady(() => {
226
+ if (isLocalResource(rawValue)) {
227
+ setter.call(this, rawValue);
228
+ return;
229
+ }
230
+ const localPath = findLocalPath(rawValue);
231
+ if (localPath) {
232
+ setter.call(this, localPath);
233
+ return;
234
+ }
235
+ const record = findByUrl(rawValue);
236
+ const next = record ? toDataUrl(record, relLower.includes("stylesheet") ? "text/css" : undefined) : emptyStyle;
237
+ setter.call(this, next);
238
+ });
239
+ return;
240
+ }
241
+ if (isLocalResource(rawValue)) {
242
+ setter.call(this, rawValue);
243
+ return;
244
+ }
245
+ const localPath = findLocalPath(rawValue);
246
+ if (localPath) {
247
+ setter.call(this, localPath);
248
+ return;
249
+ }
250
+ const record = findByUrl(rawValue);
251
+ const next = record ? toDataUrl(record, relLower.includes("stylesheet") ? "text/css" : undefined) : emptyStyle;
252
+ setter.call(this, next);
253
+ });
254
+
255
+ patchProperty(HTMLImageElement.prototype, "srcset", function(value, setter) {
256
+ const rawValue = String(value);
257
+ if (!readyResolved) {
258
+ onReady(() => {
259
+ const next = rewriteSrcset(rawValue);
260
+ setter.call(this, next);
261
+ });
262
+ return;
263
+ }
264
+ const next = rewriteSrcset(rawValue);
265
+ setter.call(this, next);
266
+ });
267
+
268
+ // Observe DOM mutations and rewrite any new elements or attributes.
269
+ const observer = new MutationObserver((mutations) => {
270
+ for (const mutation of mutations) {
271
+ if (mutation.type === "attributes" && mutation.target) {
272
+ rewriteElement(mutation.target);
273
+ }
274
+ if (mutation.type === "childList") {
275
+ mutation.addedNodes.forEach((node) => {
276
+ if (node && node.nodeType === 1) {
277
+ rewriteElement(node);
278
+ const descendants = node.querySelectorAll ? node.querySelectorAll("img,source,video,audio,script,link,iframe") : [];
279
+ descendants.forEach((el) => rewriteElement(el));
280
+ }
281
+ });
282
+ }
283
+ }
284
+ });
285
+
286
+ observer.observe(document.documentElement, {
287
+ attributes: true,
288
+ childList: true,
289
+ subtree: true,
290
+ attributeFilter: ["src", "href", "srcset"]
291
+ });
292
+
293
+ document.querySelectorAll("img,source,video,audio,script,link,iframe").forEach((el) => rewriteElement(el));
294
+ `
295
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayEventSourceStub: ScriptHacker;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayEventSourceStub = void 0;
4
+ exports.replayEventSourceStub = {
5
+ id: "replay-eventsource-stub",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Stub EventSource to prevent live network connections.
9
+ if (window.EventSource) {
10
+ const OriginalEventSource = window.EventSource;
11
+ window.EventSource = function(url) {
12
+ const source = {
13
+ url,
14
+ readyState: 1,
15
+ close: function() {},
16
+ addEventListener: function() {},
17
+ removeEventListener: function() {},
18
+ dispatchEvent: function() { return false; }
19
+ };
20
+ return source;
21
+ };
22
+ window.EventSource.__pagepocketOriginal = OriginalEventSource;
23
+ }
24
+ `
25
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayFetchResponder: ScriptHacker;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayFetchResponder = void 0;
4
+ exports.replayFetchResponder = {
5
+ id: "replay-fetch-responder",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Patch fetch to serve from recorded network data.
9
+ const originalFetch = (typeof __pagepocketOriginalFetch === "function")
10
+ ? __pagepocketOriginalFetch
11
+ : window.fetch.bind(window);
12
+ window.fetch = async (input, init = {}) => {
13
+ if (ready && typeof ready.then === "function") {
14
+ await ready;
15
+ }
16
+ const url = typeof input === "string" ? input : input.url;
17
+ const method = (init && init.method) || (typeof input === "string" ? "GET" : input.method || "GET");
18
+ const body = init && init.body;
19
+ try {
20
+ const record = findRecord(method, url, body);
21
+ if (record) {
22
+ return responseFromRecord(record);
23
+ }
24
+ } catch (err) {
25
+ console.warn("pagepocket fetch replay fallback", { url, method, err });
26
+ }
27
+ return new Response("", { status: 404, statusText: "Not Found" });
28
+ };
29
+ window.fetch.__pagepocketOriginal = originalFetch;
30
+ ensureReplayPatches && ensureReplayPatches();
31
+
32
+ `
33
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replaySvgImageRewriter: ScriptHacker;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replaySvgImageRewriter = void 0;
4
+ exports.replaySvgImageRewriter = {
5
+ id: "replay-svg-image-rewriter",
6
+ stage: "replay",
7
+ build: () => `
8
+ (function(){
9
+ const xlinkNs = "http://www.w3.org/1999/xlink";
10
+ const transparentGif = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
11
+
12
+ let readyResolved = false;
13
+ if (ready && typeof ready.then === "function") {
14
+ ready.then(() => {
15
+ readyResolved = true;
16
+ });
17
+ } else {
18
+ readyResolved = true;
19
+ }
20
+
21
+ const onReady = (callback) => {
22
+ if (readyResolved) {
23
+ callback();
24
+ return;
25
+ }
26
+ if (ready && typeof ready.then === "function") {
27
+ ready.then(callback);
28
+ } else {
29
+ callback();
30
+ }
31
+ };
32
+
33
+ const resolveHref = (value) => {
34
+ if (!value) return null;
35
+ if (isLocalResource(value)) return value;
36
+ const localPath = findLocalPath(value);
37
+ if (localPath) return localPath;
38
+ const record = findByUrl(value);
39
+ if (record) return toDataUrl(record);
40
+ return transparentGif;
41
+ };
42
+
43
+ const rewriteImage = (el) => {
44
+ if (!el || !el.getAttribute) return;
45
+ const href = el.getAttribute("href") || (el.getAttributeNS && el.getAttributeNS(xlinkNs, "href"));
46
+ if (!href) return;
47
+ if (href.startsWith("data:") || href.startsWith("blob:") || isLocalResource(href)) return;
48
+ if (!readyResolved) {
49
+ try { el.setAttributeNS(xlinkNs, "href", transparentGif); } catch {}
50
+ try { el.setAttribute("href", transparentGif); } catch {}
51
+ onReady(() => rewriteImage(el));
52
+ return;
53
+ }
54
+ const next = resolveHref(href);
55
+ if (!next) return;
56
+ try { el.setAttributeNS(xlinkNs, "href", next); } catch {}
57
+ try { el.setAttribute("href", next); } catch {}
58
+ };
59
+
60
+ const observer = new MutationObserver((mutations) => {
61
+ for (const mutation of mutations) {
62
+ if (mutation.type === "attributes" && mutation.target && mutation.target.tagName && mutation.target.tagName.toLowerCase() === "image") {
63
+ rewriteImage(mutation.target);
64
+ }
65
+ if (mutation.type === "childList") {
66
+ mutation.addedNodes.forEach((node) => {
67
+ if (node && node.nodeType === 1) {
68
+ if ((node.tagName || "").toLowerCase() === "image") {
69
+ rewriteImage(node);
70
+ }
71
+ const descendants = node.querySelectorAll ? node.querySelectorAll("image") : [];
72
+ descendants.forEach((img) => rewriteImage(img));
73
+ }
74
+ });
75
+ }
76
+ }
77
+ });
78
+
79
+ observer.observe(document.documentElement, {
80
+ attributes: true,
81
+ childList: true,
82
+ subtree: true,
83
+ attributeFilter: ["href", "xlink:href"]
84
+ });
85
+
86
+ document.querySelectorAll("image").forEach((el) => rewriteImage(el));
87
+ })();
88
+ `
89
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayWebSocketStub: ScriptHacker;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayWebSocketStub = void 0;
4
+ exports.replayWebSocketStub = {
5
+ id: "replay-websocket-stub",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Stub WebSocket to prevent live network connections.
9
+ if (window.WebSocket) {
10
+ const OriginalWebSocket = window.WebSocket;
11
+ window.WebSocket = function(url, protocols) {
12
+ const socket = {
13
+ url,
14
+ readyState: 1,
15
+ send: function() {},
16
+ close: function() {},
17
+ addEventListener: function() {},
18
+ removeEventListener: function() {},
19
+ dispatchEvent: function() { return false; }
20
+ };
21
+ return socket;
22
+ };
23
+ window.WebSocket.__pagepocketOriginal = OriginalWebSocket;
24
+ }
25
+ `
26
+ };
@@ -0,0 +1,2 @@
1
+ import type { ScriptHacker } from "./types";
2
+ export declare const replayXhrResponder: ScriptHacker;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replayXhrResponder = void 0;
4
+ exports.replayXhrResponder = {
5
+ id: "replay-xhr-responder",
6
+ stage: "replay",
7
+ build: () => `
8
+ // Patch XHR so app code sees consistent responses offline.
9
+ const originalOpen = XMLHttpRequest.prototype.open;
10
+ const originalSend = XMLHttpRequest.prototype.send;
11
+ const waitForReady = () => {
12
+ if (ready && typeof ready.then === "function") {
13
+ return ready;
14
+ }
15
+ return Promise.resolve();
16
+ };
17
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
18
+ this.__pagepocketMethod = method;
19
+ this.__pagepocketUrl = url;
20
+ return originalOpen.call(this, method, url, ...rest);
21
+ };
22
+ XMLHttpRequest.prototype.send = function(body) {
23
+ const method = this.__pagepocketMethod || "GET";
24
+ const url = this.__pagepocketUrl || "";
25
+ const xhr = this;
26
+ waitForReady().then(() => {
27
+ let record = null;
28
+ try {
29
+ record = findRecord(method, url, body);
30
+ } catch (err) {
31
+ console.warn("pagepocket xhr replay fallback", { url, method, err });
32
+ }
33
+ if (record) {
34
+ const responseText = record.responseBody || "";
35
+ const status = record.status || 200;
36
+ const statusText = record.statusText || "OK";
37
+
38
+ setTimeout(() => {
39
+ defineProp(xhr, "readyState", 4);
40
+ defineProp(xhr, "status", status);
41
+ defineProp(xhr, "statusText", statusText);
42
+ if (xhr.responseType === "arraybuffer" && record.responseBodyBase64) {
43
+ const bytes = decodeBase64(record.responseBodyBase64);
44
+ defineProp(xhr, "response", bytes.buffer);
45
+ defineProp(xhr, "responseText", "");
46
+ } else if (xhr.responseType === "blob" && record.responseBodyBase64) {
47
+ const bytes = decodeBase64(record.responseBodyBase64);
48
+ defineProp(xhr, "response", new Blob([bytes]));
49
+ defineProp(xhr, "responseText", "");
50
+ } else {
51
+ defineProp(xhr, "response", responseText);
52
+ defineProp(xhr, "responseText", responseText);
53
+ }
54
+ if (typeof xhr.onreadystatechange === "function") xhr.onreadystatechange();
55
+ if (typeof xhr.onload === "function") xhr.onload(new Event("load"));
56
+ if (typeof xhr.onloadend === "function") xhr.onloadend(new Event("loadend"));
57
+ if (xhr.dispatchEvent) {
58
+ xhr.dispatchEvent(new Event("readystatechange"));
59
+ xhr.dispatchEvent(new Event("load"));
60
+ xhr.dispatchEvent(new Event("loadend"));
61
+ }
62
+ }, 0);
63
+ return;
64
+ }
65
+
66
+ const status = 404;
67
+ const statusText = "Not Found";
68
+
69
+ setTimeout(() => {
70
+ defineProp(xhr, "readyState", 4);
71
+ defineProp(xhr, "status", status);
72
+ defineProp(xhr, "statusText", statusText);
73
+ defineProp(xhr, "response", "");
74
+ defineProp(xhr, "responseText", "");
75
+ if (typeof xhr.onreadystatechange === "function") xhr.onreadystatechange();
76
+ if (typeof xhr.onload === "function") xhr.onload(new Event("load"));
77
+ if (typeof xhr.onloadend === "function") xhr.onloadend(new Event("loadend"));
78
+ if (xhr.dispatchEvent) {
79
+ xhr.dispatchEvent(new Event("readystatechange"));
80
+ xhr.dispatchEvent(new Event("load"));
81
+ xhr.dispatchEvent(new Event("loadend"));
82
+ }
83
+ }, 0);
84
+ });
85
+ return;
86
+ };
87
+ XMLHttpRequest.prototype.open.__pagepocketOriginal = originalOpen;
88
+ XMLHttpRequest.prototype.send.__pagepocketOriginal = originalSend;
89
+ ensureReplayPatches && ensureReplayPatches();
90
+ `
91
+ };
@@ -0,0 +1,10 @@
1
+ export type HackerStage = "preload" | "replay";
2
+ export type HackerContext = {
3
+ stage: HackerStage;
4
+ };
5
+ export type ScriptHacker = {
6
+ id: string;
7
+ stage: "preload" | "replay";
8
+ build: (context: HackerContext) => string;
9
+ };
10
+ export type HackerModule = ScriptHacker;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export { PagePocket } from "./pagepocket";
2
+ export type { PagePocketOptions } from "./pagepocket";
3
+ export type { FetchRecord, NetworkRecord, LighterceptorNetworkRecord, SnapshotData } from "./types";
4
+ export { buildReplayScript } from "./replay-script";
5
+ export { buildPreloadScript } from "./preload";
6
+ export { findFaviconDataUrl, mapLighterceptorRecords, toDataUrlFromRecord } from "./network-records";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toDataUrlFromRecord = exports.mapLighterceptorRecords = exports.findFaviconDataUrl = exports.buildPreloadScript = exports.buildReplayScript = exports.PagePocket = void 0;
4
+ var pagepocket_1 = require("./pagepocket");
5
+ Object.defineProperty(exports, "PagePocket", { enumerable: true, get: function () { return pagepocket_1.PagePocket; } });
6
+ var replay_script_1 = require("./replay-script");
7
+ Object.defineProperty(exports, "buildReplayScript", { enumerable: true, get: function () { return replay_script_1.buildReplayScript; } });
8
+ var preload_1 = require("./preload");
9
+ Object.defineProperty(exports, "buildPreloadScript", { enumerable: true, get: function () { return preload_1.buildPreloadScript; } });
10
+ var network_records_1 = require("./network-records");
11
+ Object.defineProperty(exports, "findFaviconDataUrl", { enumerable: true, get: function () { return network_records_1.findFaviconDataUrl; } });
12
+ Object.defineProperty(exports, "mapLighterceptorRecords", { enumerable: true, get: function () { return network_records_1.mapLighterceptorRecords; } });
13
+ Object.defineProperty(exports, "toDataUrlFromRecord", { enumerable: true, get: function () { return network_records_1.toDataUrlFromRecord; } });
@@ -0,0 +1,4 @@
1
+ import type { LighterceptorNetworkRecord, NetworkRecord } from "./types";
2
+ export declare const toDataUrlFromRecord: (record: NetworkRecord) => string | null;
3
+ export declare const findFaviconDataUrl: (records: NetworkRecord[]) => string | null;
4
+ export declare const mapLighterceptorRecords: (records: LighterceptorNetworkRecord[] | undefined) => NetworkRecord[];