@pagepocket/lib 0.8.6 → 0.9.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.
Files changed (64) hide show
  1. package/dist/cheerio/types.d.ts +5 -0
  2. package/dist/cheerio/types.js +1 -0
  3. package/dist/core/completion.js +2 -1
  4. package/dist/core/content-store.js +2 -2
  5. package/dist/css-rewrite.d.ts +1 -1
  6. package/dist/css-rewrite.js +2 -2
  7. package/dist/hackers/replay-dom-rewrite/script-part-1.d.ts +1 -0
  8. package/dist/hackers/replay-dom-rewrite/script-part-1.js +202 -0
  9. package/dist/hackers/replay-dom-rewrite/script-part-2.d.ts +1 -0
  10. package/dist/hackers/replay-dom-rewrite/script-part-2.js +173 -0
  11. package/dist/hackers/replay-dom-rewrite.js +3 -373
  12. package/dist/hackers/replay-svg-image.js +32 -8
  13. package/dist/hackers/replay-xhr.js +3 -3
  14. package/dist/path-resolver.js +2 -2
  15. package/dist/replace-elements/actions.d.ts +3 -3
  16. package/dist/replace-elements/actions.js +36 -16
  17. package/dist/replace-elements/match.d.ts +2 -2
  18. package/dist/replace-elements/match.js +22 -11
  19. package/dist/replace-elements/normalize.d.ts +1 -1
  20. package/dist/replace-elements/normalize.js +4 -2
  21. package/dist/replay/match-api.js +29 -17
  22. package/dist/replay/templates/replay-script-template.js +16 -332
  23. package/dist/replay/templates/replay-script-template.part-1.d.ts +5 -0
  24. package/dist/replay/templates/replay-script-template.part-1.js +101 -0
  25. package/dist/replay/templates/replay-script-template.part-2.d.ts +3 -0
  26. package/dist/replay/templates/replay-script-template.part-2.js +222 -0
  27. package/dist/replay/templates/replay-script-template.part-3.d.ts +3 -0
  28. package/dist/replay/templates/replay-script-template.part-3.js +9 -0
  29. package/dist/resource-proxy/pathname-variants.js +8 -5
  30. package/dist/resource-proxy.js +10 -10
  31. package/dist/resources.d.ts +3 -2
  32. package/dist/resources.js +6 -3
  33. package/dist/rewrite-links/js-imports.d.ts +1 -1
  34. package/dist/rewrite-links/link-rel.d.ts +2 -2
  35. package/dist/rewrite-links/meta-refresh.d.ts +1 -1
  36. package/dist/rewrite-links/meta-refresh.js +6 -3
  37. package/dist/rewrite-links/srcset.d.ts +1 -1
  38. package/dist/rewrite-links/srcset.js +4 -2
  39. package/dist/rewrite-links/url-resolve.d.ts +2 -2
  40. package/dist/rewrite-links/url-resolve.js +2 -2
  41. package/dist/rewrite-links.d.ts +1 -1
  42. package/dist/rewrite-links.js +12 -6
  43. package/dist/snapshot-builder/build-snapshot.js +2 -3
  44. package/dist/snapshot-builder/capture-index/index-capture.js +2 -1
  45. package/dist/snapshot-builder/emit-document.d.ts +1 -1
  46. package/dist/snapshot-builder/emit-document.js +1 -1
  47. package/dist/snapshot-builder/grouping.js +2 -2
  48. package/dist/snapshot-builder/path-map.d.ts +1 -1
  49. package/dist/snapshot-builder/path-map.js +1 -1
  50. package/dist/snapshot-builder/resources-path.js +8 -4
  51. package/dist/snapshot-builder/rewrite-resource.d.ts +2 -2
  52. package/dist/snapshot-builder/rewrite-resource.js +2 -2
  53. package/dist/types.d.ts +3 -3
  54. package/dist/units/internal/async-queue.d.ts +9 -0
  55. package/dist/units/internal/async-queue.js +57 -0
  56. package/dist/units/internal/deferred-tracker.d.ts +5 -0
  57. package/dist/units/internal/deferred-tracker.js +13 -0
  58. package/dist/units/internal/runtime.d.ts +37 -0
  59. package/dist/units/internal/runtime.js +113 -0
  60. package/dist/units/runner.js +3 -184
  61. package/dist/utils.d.ts +1 -1
  62. package/dist/utils.js +6 -6
  63. package/package.json +5 -4
  64. package/README.md +0 -357
@@ -2,10 +2,12 @@ import { urlEquivalent } from "../utils.js";
2
2
  export function matchAPI(options) {
3
3
  const { records, byKey, baseUrl, method, url, body } = options;
4
4
  const normalizeBody = (value) => {
5
- if (value === undefined || value === null)
5
+ if (value === undefined || value === null) {
6
6
  return "";
7
- if (typeof value === "string")
7
+ }
8
+ if (typeof value === "string") {
8
9
  return value;
10
+ }
9
11
  try {
10
12
  return String(value);
11
13
  }
@@ -36,13 +38,14 @@ export function matchAPI(options) {
36
38
  return new URL(input, baseUrl);
37
39
  }
38
40
  catch {
39
- return null;
41
+ return undefined;
40
42
  }
41
43
  };
42
44
  const toPathSearch = (input) => {
43
45
  const parsed = safeUrl(input);
44
- if (!parsed)
46
+ if (!parsed) {
45
47
  return input;
48
+ }
46
49
  return parsed.pathname + parsed.search;
47
50
  };
48
51
  const toPathname = (input) => {
@@ -52,8 +55,9 @@ export function matchAPI(options) {
52
55
  const buildUrlVariants = (input) => {
53
56
  const variants = new Set();
54
57
  const push = (value) => {
55
- if (!value)
58
+ if (!value) {
56
59
  return;
60
+ }
57
61
  variants.add(value);
58
62
  };
59
63
  const raw = String(input ?? "");
@@ -79,12 +83,14 @@ export function matchAPI(options) {
79
83
  const bodyValue = normalizeBody(body);
80
84
  const methodValue = (method || "GET").toUpperCase();
81
85
  const tryLookup = (keyMethod, keyBody) => {
82
- if (!byKey)
86
+ if (!byKey) {
83
87
  return undefined;
88
+ }
84
89
  for (const urlVariant of urlVariants) {
85
90
  const record = byKey.get(makeKey(keyMethod, urlVariant, keyBody));
86
- if (record)
91
+ if (record) {
87
92
  return record;
93
+ }
88
94
  }
89
95
  return undefined;
90
96
  };
@@ -96,15 +102,16 @@ export function matchAPI(options) {
96
102
  ];
97
103
  for (const [keyMethod, keyBody] of matchOrder) {
98
104
  const record = tryLookup(keyMethod, keyBody);
99
- if (record)
105
+ if (record) {
100
106
  return record;
107
+ }
101
108
  }
102
- const toUrlOrNull = (value) => {
109
+ const toUrlOrUndefined = (value) => {
103
110
  try {
104
111
  return new URL(value, baseUrl);
105
112
  }
106
113
  catch {
107
- return null;
114
+ return undefined;
108
115
  }
109
116
  };
110
117
  const normalizePath = (value) => {
@@ -124,8 +131,8 @@ export function matchAPI(options) {
124
131
  return true;
125
132
  }
126
133
  // Relaxed fallback: allow origin mismatch but keep path/search stable.
127
- const left = toUrlOrNull(inputUrl);
128
- const right = toUrlOrNull(recordUrl);
134
+ const left = toUrlOrUndefined(inputUrl);
135
+ const right = toUrlOrUndefined(recordUrl);
129
136
  if (!left || !right) {
130
137
  return false;
131
138
  }
@@ -140,23 +147,28 @@ export function matchAPI(options) {
140
147
  };
141
148
  const scanRecords = (keyMethod, keyBody) => {
142
149
  for (const record of records || []) {
143
- if (!record || !record.url || !record.method)
150
+ if (!record || !record.url || !record.method) {
144
151
  continue;
145
- if (record.method.toUpperCase() !== keyMethod)
152
+ }
153
+ if (record.method.toUpperCase() !== keyMethod) {
146
154
  continue;
147
- if (!urlMatches(url, record.url))
155
+ }
156
+ if (!urlMatches(url, record.url)) {
148
157
  continue;
158
+ }
149
159
  const recordBody = record.requestBody || record.requestBodyBase64 || "";
150
- if (keyBody && recordBody !== keyBody)
160
+ if (keyBody && recordBody !== keyBody) {
151
161
  continue;
162
+ }
152
163
  return record;
153
164
  }
154
165
  return undefined;
155
166
  };
156
167
  for (const [keyMethod, keyBody] of matchOrder) {
157
168
  const record = scanRecords(keyMethod, keyBody);
158
- if (record)
169
+ if (record) {
159
170
  return record;
171
+ }
160
172
  }
161
173
  return undefined;
162
174
  }
@@ -1,337 +1,21 @@
1
1
  import { matchAPISource } from "./match-api-source.js";
2
+ import { buildReplayInjectedScriptPart1 } from "./replay-script-template.part-1.js";
3
+ import { buildReplayInjectedScriptPart2 } from "./replay-script-template.part-2.js";
4
+ import { buildReplayInjectedScriptPart3 } from "./replay-script-template.part-3.js";
2
5
  import { resourceProxyScript } from "./resource-proxy-script.js";
3
6
  export const buildReplayInjectedScript = (options) => {
4
7
  const { basePayload, apiPayload, hackerScripts } = options;
5
- return `
6
- <script>
7
- (function(){
8
- const baseUrl = ${basePayload};
9
- const apiUrl = ${apiPayload};
10
- const resourcesPathUrl = "/resources_path.json";
11
- const __pagepocketOriginalFetch = window.fetch ? window.fetch.bind(window) : null;
12
-
13
- ${resourceProxyScript}
14
-
15
- const loadResourcesPath = async () => {
16
- try {
17
- const injected = window && window.__pagepocketResourcesPath;
18
- if (injected && injected.version === "1.0" && Array.isArray(injected.items)) {
19
- return injected;
20
- }
21
-
22
- if (!__pagepocketOriginalFetch) {
23
- throw new Error("Fetch is unavailable");
24
- }
25
- const response = await __pagepocketOriginalFetch(resourcesPathUrl);
26
- if (!response.ok) {
27
- throw new Error("Failed to load resources_path.json");
28
- }
29
- const json = await response.json();
30
- if (!json || json.version !== "1.0" || !Array.isArray(json.items)) {
31
- throw new Error("Invalid resources_path.json");
32
- }
33
- return json;
34
- } catch {
35
- return { version: "1.0", createdAt: 0, items: [] };
36
- }
37
- };
38
-
39
- const loadApiSnapshot = async () => {
40
- try {
41
- const injected = window && window.__pagepocketApiSnapshot;
42
- if (injected && injected.version === "1.0" && Array.isArray(injected.records)) {
43
- return injected;
44
- }
45
-
46
- if (!__pagepocketOriginalFetch) {
47
- throw new Error("Fetch is unavailable");
48
- }
49
- const response = await __pagepocketOriginalFetch(apiUrl);
50
- if (!response.ok) {
51
- throw new Error("Failed to load api.json");
52
- }
53
- return await response.json();
54
- } catch {
55
- return { version: "1.0", url: baseUrl, createdAt: 0, records: [] };
56
- }
57
- };
58
-
59
- const originalResponseJson = Response && Response.prototype && Response.prototype.json;
60
- if (originalResponseJson) {
61
- Response.prototype.json = function(...args) {
62
- try {
63
- return originalResponseJson.apply(this, args).catch(() => null);
64
- } catch {
65
- return Promise.resolve(null);
66
- }
67
- };
68
- }
69
-
70
- const ensureReplayPatches = () => {
71
- try {
72
- if (!window.fetch.__pagepocketOriginal && typeof __pagepocketOriginalFetch === "function") {
73
- window.fetch.__pagepocketOriginal = __pagepocketOriginalFetch;
74
- }
75
- } catch {}
76
- try {
77
- if (!XMLHttpRequest.prototype.send.__pagepocketOriginal) {
78
- XMLHttpRequest.prototype.send.__pagepocketOriginal = XMLHttpRequest.prototype.send;
79
- }
80
- } catch {}
81
- };
82
-
83
- let records = [];
84
- const byKey = new Map();
85
-
86
- let resourceIndex = null;
87
- let embeddedByPath = new Map();
88
- const blobUrlByPath = new Map();
89
-
90
- const normalizeUrl = (input) => {
91
- try { return new URL(input, baseUrl).toString(); } catch { return input; }
92
- };
93
-
94
- const normalizeBody = (body) => {
95
- if (body === undefined || body === null) return "";
96
- if (typeof body === "string") return body;
97
- try { return String(body); } catch { return ""; }
98
- };
99
-
100
- const makeKey = (method, url, body) => method.toUpperCase() + " " + normalizeUrl(url) + " " + normalizeBody(body);
101
- const makeVariantKeys = (method, url, body) => [makeKey(method, url, body)];
102
-
103
- const matchAPI = ${matchAPISource};
104
-
105
- const primeLookups = (snapshot) => {
106
- records = snapshot.records || [];
107
- byKey.clear();
108
- for (const record of records) {
109
- if (!record || !record.url || !record.method) continue;
110
- const keys = makeVariantKeys(record.method, record.url, record.requestBody || record.requestBodyBase64 || "");
111
- for (const key of keys) {
112
- if (!byKey.has(key)) {
113
- byKey.set(key, record);
114
- }
115
- }
116
- }
117
- };
118
-
119
- const ready = (async () => {
120
- const [apiSnapshot, resourcesPath] = await Promise.all([loadApiSnapshot(), loadResourcesPath()]);
121
- resourceIndex = __pagepocketResourceProxy.buildIndex(resourcesPath || {});
122
-
123
- embeddedByPath = new Map();
124
- try {
125
- const items = (resourcesPath && resourcesPath.items) || [];
126
- for (const item of items) {
127
- if (!item || !item.path || !item.data || item.dataEncoding !== "base64") {
128
- continue;
129
- }
130
- embeddedByPath.set(item.path, item);
131
- }
132
- } catch {}
133
-
134
- const snapshot = apiSnapshot || {};
135
- primeLookups(snapshot);
136
- return snapshot;
137
- })();
138
-
139
- const isLocalResource = (value) => {
140
- if (!value) return false;
141
- if (value.startsWith("data:") || value.startsWith("blob:")) return true;
142
- // Protocol-relative URLs ("//host/path") are NOT local paths.
143
- // Treat them as absolute URLs so they can be mapped via resources_path.json.
144
- if (value.startsWith("//")) return false;
145
- if (value.startsWith("/")) return true;
146
- return false;
147
- };
148
-
149
- const findRecord = (method, url, body) => {
150
- return matchAPI({ records, byKey, baseUrl, method, url, body });
151
- };
152
-
153
- const urlLookupCache = new Map();
154
- const findByUrl = (url) => {
155
- if (isLocalResource(url)) return null;
156
- if (urlLookupCache.has(url)) {
157
- return urlLookupCache.get(url);
158
- }
159
- const record = matchAPI({ records, byKey, baseUrl, method: "GET", url, body: "" });
160
- urlLookupCache.set(url, record || null);
161
- return record;
162
- };
163
-
164
- const findLocalPath = (url) => {
165
- try {
166
- if (!url || isLocalResource(String(url))) {
167
- return null;
168
- }
169
- if (!resourceIndex) {
170
- return null;
171
- }
172
-
173
- const resolvedPath = __pagepocketResourceProxy.resolveToLocalPath(String(url), baseUrl, resourceIndex);
174
- if (!resolvedPath) {
175
- return null;
176
- }
177
-
178
- const embedded = embeddedByPath && embeddedByPath.get(resolvedPath);
179
- if (embedded && embedded.dataEncoding === "base64" && embedded.data) {
180
- if (blobUrlByPath.has(resolvedPath)) {
181
- return blobUrlByPath.get(resolvedPath);
182
- }
183
-
184
- const binary = atob(embedded.data);
185
- const bytes = new Uint8Array(binary.length);
186
- for (let i = 0; i < binary.length; i += 1) {
187
- bytes[i] = binary.charCodeAt(i);
188
- }
189
-
190
- const mime = embedded.mimeType || "application/octet-stream";
191
- const blob = new Blob([bytes], { type: mime });
192
- const blobUrl = URL.createObjectURL(blob);
193
- blobUrlByPath.set(resolvedPath, blobUrl);
194
- return blobUrl;
195
- }
196
-
197
- return resolvedPath;
198
- } catch {
199
- return null;
200
- }
201
- };
202
-
203
- /**
204
- * Rewrite a resource URL to a snapshot-local URL.
205
- *
206
- * Strategy (in order):
207
- * 1) If already local (data:/blob:/absolute path), keep as-is.
208
- * 2) If resources_path.json can map it to a local file, return that path.
209
- * 3) Otherwise, if we have a recorded body for the URL, return a data: URL
210
- * (used as a placeholder for some resource types).
211
- * 4) Otherwise, keep the original URL.
212
- */
213
- const rewriteResourceUrl = (value, ctx) => {
214
- try {
215
- const raw = String(value || "");
216
- if (!raw) {
217
- return raw;
218
- }
219
-
220
- if (isLocalResource(raw)) {
221
- return raw;
222
- }
223
-
224
- const localPath = findLocalPath(raw);
225
- if (localPath) {
226
- return localPath;
227
- }
228
-
229
- const fallbackType = ctx && ctx.fallbackType ? String(ctx.fallbackType) : undefined;
230
- const record = findByUrl(raw);
231
- if (record) {
232
- const dataUrl = toDataUrl(record, fallbackType);
233
- if (dataUrl) {
234
- return dataUrl;
235
- }
236
- }
237
-
238
- return raw;
239
- } catch {
240
- try {
241
- return String(value || "");
242
- } catch {
243
- return value;
244
- }
245
- }
246
- };
247
-
248
- const defineProp = (obj, key, value) => {
249
- try {
250
- Object.defineProperty(obj, key, { value, configurable: true });
251
- } catch {}
252
- };
253
-
254
- const decodeBase64 = (input) => {
255
- try {
256
- const binary = atob(input || "");
257
- const bytes = new Uint8Array(binary.length);
258
- Array.from(binary).forEach((char, index) => {
259
- bytes[index] = char.charCodeAt(0);
260
- });
261
- return bytes;
262
- } catch {
263
- return new Uint8Array();
264
- }
265
- };
266
-
267
- const bytesToBase64 = (bytes) => {
268
- const binary = Array.from(bytes, (value) => String.fromCharCode(value)).join("");
269
- return btoa(binary);
270
- };
271
-
272
- const textToBase64 = (text) => {
273
- try {
274
- const bytes = new TextEncoder().encode(text || "");
275
- return bytesToBase64(bytes);
276
- } catch {
277
- return btoa(text || "");
278
- }
279
- };
280
-
281
- const getContentType = (record) => {
282
- const headers = record.responseHeaders || {};
283
- for (const key in headers) {
284
- if (key.toLowerCase() === "content-type") {
285
- return headers[key] || "application/octet-stream";
286
- }
287
- }
288
- return "application/octet-stream";
289
- };
290
-
291
- const dataUrlCache = new Map();
292
- const toDataUrl = (record, fallbackType) => {
293
- if (!record) return "";
294
- const contentType = getContentType(record) || fallbackType || "application/octet-stream";
295
- const cacheKey = (record.url || "") + "|" + contentType + "|" + (record.responseEncoding || "") + "|" +
296
- (record.responseBodyBase64 ? "b64:" + record.responseBodyBase64.length : "txt:" + (record.responseBody ? record.responseBody.length : 0));
297
- if (dataUrlCache.has(cacheKey)) {
298
- return dataUrlCache.get(cacheKey);
299
- }
300
- if (record.responseEncoding === "base64" && record.responseBodyBase64) {
301
- const dataUrl = "data:" + contentType + ";base64," + record.responseBodyBase64;
302
- dataUrlCache.set(cacheKey, dataUrl);
303
- return dataUrl;
304
- }
305
- if (record.responseBody) {
306
- const dataUrl = "data:" + contentType + ";base64," + textToBase64(record.responseBody);
307
- dataUrlCache.set(cacheKey, dataUrl);
308
- return dataUrl;
309
- }
310
- const dataUrl = "data:" + (fallbackType || "application/octet-stream") + ",";
311
- dataUrlCache.set(cacheKey, dataUrl);
312
- return dataUrl;
313
- };
314
-
315
- const responseFromRecord = (record) => {
316
- const headers = new Headers(record.responseHeaders || {});
317
- if (record.responseEncoding === "base64" && record.responseBodyBase64) {
318
- const bytes = decodeBase64(record.responseBodyBase64);
319
- return new Response(bytes, {
320
- status: record.status || 200,
321
- statusText: record.statusText || "OK",
322
- headers
323
- });
324
- }
325
- const bodyText = record.responseBody || "";
326
- return new Response(bodyText, {
327
- status: record.status || 200,
328
- statusText: record.statusText || "OK",
329
- headers
330
- });
331
- };
332
-
333
- ${hackerScripts}
334
- })();
335
- </script>
336
- `;
8
+ return [
9
+ buildReplayInjectedScriptPart1({
10
+ basePayload,
11
+ apiPayload,
12
+ resourceProxyScript
13
+ }),
14
+ buildReplayInjectedScriptPart2({
15
+ matchAPISource
16
+ }),
17
+ buildReplayInjectedScriptPart3({
18
+ hackerScripts
19
+ })
20
+ ].join("");
337
21
  };
@@ -0,0 +1,5 @@
1
+ export declare const buildReplayInjectedScriptPart1: (options: {
2
+ basePayload: string;
3
+ apiPayload: string;
4
+ resourceProxyScript: string;
5
+ }) => string;
@@ -0,0 +1,101 @@
1
+ export const buildReplayInjectedScriptPart1 = (options) => {
2
+ const { basePayload, apiPayload, resourceProxyScript } = options;
3
+ return `
4
+ <script>
5
+ (function(){
6
+ const baseUrl = ${basePayload};
7
+ const apiUrl = ${apiPayload};
8
+ const resourcesPathUrl = "/resources_path.json";
9
+ const __pagepocketOriginalFetch = window.fetch ? window.fetch.bind(window) : null;
10
+
11
+ ${resourceProxyScript}
12
+
13
+ const loadResourcesPath = async () => {
14
+ try {
15
+ const injected = window && window.__pagepocketResourcesPath;
16
+ if (injected && injected.version === "1.0" && Array.isArray(injected.items)) {
17
+ return injected;
18
+ }
19
+
20
+ if (!__pagepocketOriginalFetch) {
21
+ throw new Error("Fetch is unavailable");
22
+ }
23
+ const response = await __pagepocketOriginalFetch(resourcesPathUrl);
24
+ if (!response.ok) {
25
+ throw new Error("Failed to load resources_path.json");
26
+ }
27
+ const json = await response.json();
28
+ if (!json || json.version !== "1.0" || !Array.isArray(json.items)) {
29
+ throw new Error("Invalid resources_path.json");
30
+ }
31
+ return json;
32
+ } catch {
33
+ return { version: "1.0", createdAt: 0, items: [] };
34
+ }
35
+ };
36
+
37
+ const loadApiSnapshot = async () => {
38
+ try {
39
+ const injected = window && window.__pagepocketApiSnapshot;
40
+ if (injected && injected.version === "1.0" && Array.isArray(injected.records)) {
41
+ return injected;
42
+ }
43
+
44
+ if (!__pagepocketOriginalFetch) {
45
+ throw new Error("Fetch is unavailable");
46
+ }
47
+ const response = await __pagepocketOriginalFetch(apiUrl);
48
+ if (!response.ok) {
49
+ throw new Error("Failed to load api.json");
50
+ }
51
+ return await response.json();
52
+ } catch {
53
+ return { version: "1.0", url: baseUrl, createdAt: 0, records: [] };
54
+ }
55
+ };
56
+
57
+ const originalResponseJson = Response && Response.prototype && Response.prototype.json;
58
+ if (originalResponseJson) {
59
+ Response.prototype.json = function(...args) {
60
+ try {
61
+ return originalResponseJson.apply(this, args).catch(() => null);
62
+ } catch {
63
+ return Promise.resolve(null);
64
+ }
65
+ };
66
+ }
67
+
68
+ const ensureReplayPatches = () => {
69
+ try {
70
+ if (!window.fetch.__pagepocketOriginal && typeof __pagepocketOriginalFetch === "function") {
71
+ window.fetch.__pagepocketOriginal = __pagepocketOriginalFetch;
72
+ }
73
+ } catch {}
74
+ try {
75
+ if (!XMLHttpRequest.prototype.send.__pagepocketOriginal) {
76
+ XMLHttpRequest.prototype.send.__pagepocketOriginal = XMLHttpRequest.prototype.send;
77
+ }
78
+ } catch {}
79
+ };
80
+
81
+ let records = [];
82
+ const byKey = new Map();
83
+
84
+ let resourceIndex = null;
85
+ let embeddedByPath = new Map();
86
+ const blobUrlByPath = new Map();
87
+
88
+ const normalizeUrl = (input) => {
89
+ try { return new URL(input, baseUrl).toString(); } catch { return input; }
90
+ };
91
+
92
+ const normalizeBody = (body) => {
93
+ if (body === undefined || body === null) return "";
94
+ if (typeof body === "string") return body;
95
+ try { return String(body); } catch { return ""; }
96
+ };
97
+
98
+ const makeKey = (method, url, body) => method.toUpperCase() + " " + normalizeUrl(url) + " " + normalizeBody(body);
99
+ const makeVariantKeys = (method, url, body) => [makeKey(method, url, body)];
100
+ `;
101
+ };
@@ -0,0 +1,3 @@
1
+ export declare const buildReplayInjectedScriptPart2: (options: {
2
+ matchAPISource: string;
3
+ }) => string;