@pagepocket/lib 0.7.1 → 0.8.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 (261) hide show
  1. package/README.md +7 -6
  2. package/dist/build-snapshot-from-bundle.d.ts +23 -0
  3. package/dist/build-snapshot-from-bundle.js +68 -0
  4. package/dist/builtin-blacklist.js +3 -6
  5. package/dist/bundle/from-network-store.d.ts +10 -0
  6. package/dist/bundle/from-network-store.js +26 -0
  7. package/dist/bundle/types.d.ts +32 -0
  8. package/dist/bundle/types.js +2 -0
  9. package/dist/capture/index.d.ts +14 -0
  10. package/dist/capture/index.js +86 -0
  11. package/dist/capture/memory-content-store.d.ts +4 -0
  12. package/dist/capture/memory-content-store.js +42 -0
  13. package/dist/capture/types.d.ts +61 -0
  14. package/dist/capture/types.js +2 -0
  15. package/dist/content-store.js +3 -8
  16. package/dist/content-type.d.ts +1 -1
  17. package/dist/content-type.js +2 -28
  18. package/dist/core/_impl/completion.d.ts +4 -0
  19. package/dist/core/_impl/completion.js +29 -0
  20. package/dist/core/_impl/content-store.d.ts +21 -0
  21. package/dist/core/_impl/content-store.js +91 -0
  22. package/dist/core/_impl/debug.d.ts +1 -0
  23. package/dist/core/_impl/debug.js +16 -0
  24. package/dist/core/_impl/inflight-tracker.d.ts +19 -0
  25. package/dist/core/_impl/inflight-tracker.js +48 -0
  26. package/dist/core/_impl/pagepocket.d.ts +27 -0
  27. package/dist/core/_impl/pagepocket.js +155 -0
  28. package/dist/core/capture/_impl/memory-content-store.d.ts +4 -0
  29. package/dist/core/capture/_impl/memory-content-store.js +42 -0
  30. package/dist/core/capture/_impl/types.d.ts +61 -0
  31. package/dist/core/capture/_impl/types.js +2 -0
  32. package/dist/core/capture/internal/memory-content-store.d.ts +4 -0
  33. package/dist/core/capture/internal/memory-content-store.js +42 -0
  34. package/dist/core/capture/internal/types.d.ts +61 -0
  35. package/dist/core/capture/internal/types.js +2 -0
  36. package/dist/core/capture/memory-content-store.d.ts +4 -0
  37. package/dist/core/capture/memory-content-store.js +38 -0
  38. package/dist/core/capture/types.d.ts +61 -0
  39. package/dist/core/capture/types.js +1 -0
  40. package/dist/core/completion.d.ts +4 -0
  41. package/dist/core/completion.js +23 -0
  42. package/dist/core/content-store.d.ts +21 -0
  43. package/dist/core/content-store.js +54 -0
  44. package/dist/core/debug.d.ts +1 -0
  45. package/dist/core/debug.js +12 -0
  46. package/dist/core/file-tree-merge.d.ts +2 -0
  47. package/dist/core/file-tree-merge.js +27 -0
  48. package/dist/core/file-tree.d.ts +36 -0
  49. package/dist/core/file-tree.js +1 -0
  50. package/dist/core/inflight-tracker.d.ts +19 -0
  51. package/dist/core/inflight-tracker.js +44 -0
  52. package/dist/core/internal/completion.d.ts +4 -0
  53. package/dist/core/internal/completion.js +29 -0
  54. package/dist/core/internal/content-store.d.ts +21 -0
  55. package/dist/core/internal/content-store.js +91 -0
  56. package/dist/core/internal/debug.d.ts +1 -0
  57. package/dist/core/internal/debug.js +16 -0
  58. package/dist/core/internal/inflight-tracker.d.ts +19 -0
  59. package/dist/core/internal/inflight-tracker.js +48 -0
  60. package/dist/core/internal/pagepocket.d.ts +27 -0
  61. package/dist/core/internal/pagepocket.js +155 -0
  62. package/dist/core/pagepocket.d.ts +38 -0
  63. package/dist/core/pagepocket.js +57 -0
  64. package/dist/core/plugin/_impl/context.d.ts +47 -0
  65. package/dist/core/plugin/_impl/context.js +142 -0
  66. package/dist/core/plugin/_impl/runner.d.ts +12 -0
  67. package/dist/core/plugin/_impl/runner.js +232 -0
  68. package/dist/core/plugin/_impl/types.d.ts +108 -0
  69. package/dist/core/plugin/_impl/types.js +2 -0
  70. package/dist/core/plugin/context.d.ts +47 -0
  71. package/dist/core/plugin/context.js +205 -0
  72. package/dist/core/plugin/internal/context.d.ts +47 -0
  73. package/dist/core/plugin/internal/context.js +142 -0
  74. package/dist/core/plugin/internal/runner.d.ts +12 -0
  75. package/dist/core/plugin/internal/runner.js +232 -0
  76. package/dist/core/plugin/internal/types.d.ts +108 -0
  77. package/dist/core/plugin/internal/types.js +2 -0
  78. package/dist/core/plugin/runner-utils.d.ts +9 -0
  79. package/dist/core/plugin/runner-utils.js +29 -0
  80. package/dist/core/plugin/runner.d.ts +12 -0
  81. package/dist/core/plugin/runner.js +118 -0
  82. package/dist/core/plugin/types.d.ts +117 -0
  83. package/dist/core/plugin/types.js +1 -0
  84. package/dist/core/runtime/types.d.ts +14 -0
  85. package/dist/core/runtime/types.js +2 -0
  86. package/dist/css-rewrite.js +1 -5
  87. package/dist/debug.d.ts +0 -1
  88. package/dist/debug.js +3 -5
  89. package/dist/files/types.d.ts +41 -0
  90. package/dist/files/types.js +2 -0
  91. package/dist/hack-html.js +20 -13
  92. package/dist/hackers/index.d.ts +1 -1
  93. package/dist/hackers/index.js +24 -27
  94. package/dist/hackers/preload-fetch.d.ts +1 -1
  95. package/dist/hackers/preload-fetch.js +1 -4
  96. package/dist/hackers/preload-xhr.d.ts +1 -1
  97. package/dist/hackers/preload-xhr.js +1 -4
  98. package/dist/hackers/replay-beacon.d.ts +1 -1
  99. package/dist/hackers/replay-beacon.js +1 -4
  100. package/dist/hackers/replay-block-text-fragment.d.ts +1 -1
  101. package/dist/hackers/replay-block-text-fragment.js +1 -4
  102. package/dist/hackers/replay-css-proxy.d.ts +1 -1
  103. package/dist/hackers/replay-css-proxy.js +9 -12
  104. package/dist/hackers/replay-dom-rewrite.d.ts +1 -1
  105. package/dist/hackers/replay-dom-rewrite.js +165 -154
  106. package/dist/hackers/replay-eventsource.d.ts +1 -1
  107. package/dist/hackers/replay-eventsource.js +1 -4
  108. package/dist/hackers/replay-fetch.d.ts +1 -1
  109. package/dist/hackers/replay-fetch.js +1 -4
  110. package/dist/hackers/replay-history-path.d.ts +1 -1
  111. package/dist/hackers/replay-history-path.js +1 -4
  112. package/dist/hackers/replay-svg-image.d.ts +1 -1
  113. package/dist/hackers/replay-svg-image.js +1 -4
  114. package/dist/hackers/replay-websocket.d.ts +1 -1
  115. package/dist/hackers/replay-websocket.js +1 -4
  116. package/dist/hackers/replay-xhr.d.ts +1 -1
  117. package/dist/hackers/replay-xhr.js +1 -4
  118. package/dist/hackers/types.js +1 -2
  119. package/dist/index.d.ts +29 -13
  120. package/dist/index.js +23 -44
  121. package/dist/kind-map.d.ts +68 -0
  122. package/dist/kind-map.js +58 -0
  123. package/dist/network-store.js +12 -1
  124. package/dist/pagepocket.d.ts +19 -4
  125. package/dist/pagepocket.js +36 -102
  126. package/dist/path-resolver.d.ts +1 -2
  127. package/dist/path-resolver.js +9 -16
  128. package/dist/plugin/builtins/build-snapshot-plugin.d.ts +5 -0
  129. package/dist/plugin/builtins/build-snapshot-plugin.js +84 -0
  130. package/dist/plugin/builtins/replace-elements-plugin.d.ts +8 -0
  131. package/dist/plugin/builtins/replace-elements-plugin.js +13 -0
  132. package/dist/plugin/builtins/to-directory-plugin.d.ts +7 -0
  133. package/dist/plugin/builtins/to-directory-plugin.js +20 -0
  134. package/dist/plugin/builtins/to-zip-plugin.d.ts +5 -0
  135. package/dist/plugin/builtins/to-zip-plugin.js +19 -0
  136. package/dist/plugin/context.d.ts +47 -0
  137. package/dist/plugin/context.js +142 -0
  138. package/dist/plugin/runner.d.ts +12 -0
  139. package/dist/plugin/runner.js +232 -0
  140. package/dist/plugin/types.d.ts +108 -0
  141. package/dist/plugin/types.js +2 -0
  142. package/dist/plugins/build-files-from-capture.d.ts +5 -0
  143. package/dist/plugins/build-files-from-capture.js +85 -0
  144. package/dist/plugins/build-warc.d.ts +5 -0
  145. package/dist/plugins/build-warc.js +225 -0
  146. package/dist/plugins/builtins/manifest.d.ts +2 -0
  147. package/dist/plugins/builtins/manifest.js +42 -0
  148. package/dist/plugins/builtins/snapshot-directory.d.ts +2 -0
  149. package/dist/plugins/builtins/snapshot-directory.js +24 -0
  150. package/dist/plugins/builtins/snapshot-zip.d.ts +2 -0
  151. package/dist/plugins/builtins/snapshot-zip.js +25 -0
  152. package/dist/plugins/capture-http-lighterceptor.d.ts +5 -0
  153. package/dist/plugins/capture-http-lighterceptor.js +85 -0
  154. package/dist/plugins/capture-http-puppeteer.d.ts +5 -0
  155. package/dist/plugins/capture-http-puppeteer.js +85 -0
  156. package/dist/plugins/host.d.ts +37 -0
  157. package/dist/plugins/host.js +105 -0
  158. package/dist/plugins/index.d.ts +6 -0
  159. package/dist/plugins/index.js +11 -0
  160. package/dist/plugins/ordering.d.ts +2 -0
  161. package/dist/plugins/ordering.js +19 -0
  162. package/dist/plugins/types.d.ts +51 -0
  163. package/dist/plugins/types.js +2 -0
  164. package/dist/preload.js +3 -7
  165. package/dist/replace-elements/actions.d.ts +5 -0
  166. package/dist/replace-elements/actions.js +86 -0
  167. package/dist/replace-elements/match.d.ts +5 -0
  168. package/dist/replace-elements/match.js +46 -0
  169. package/dist/replace-elements/normalize.d.ts +21 -0
  170. package/dist/replace-elements/normalize.js +50 -0
  171. package/dist/replace-elements.d.ts +1 -1
  172. package/dist/replace-elements.js +5 -185
  173. package/dist/replay/match-api.d.ts +10 -0
  174. package/dist/replay/match-api.js +162 -0
  175. package/dist/replay/templates/match-api-source.d.ts +1 -0
  176. package/dist/replay/templates/match-api-source.js +137 -0
  177. package/dist/replay/templates/replay-script-template.d.ts +5 -0
  178. package/dist/replay/templates/replay-script-template.js +337 -0
  179. package/dist/replay/templates/resource-proxy-script.d.ts +1 -0
  180. package/dist/replay/templates/resource-proxy-script.js +274 -0
  181. package/dist/replay-script.d.ts +3 -10
  182. package/dist/replay-script.js +11 -625
  183. package/dist/resource-filter.d.ts +1 -1
  184. package/dist/resource-filter.js +1 -5
  185. package/dist/resource-proxy/escape-percent.d.ts +1 -0
  186. package/dist/resource-proxy/escape-percent.js +12 -0
  187. package/dist/resource-proxy/multimap.d.ts +3 -0
  188. package/dist/resource-proxy/multimap.js +18 -0
  189. package/dist/resource-proxy/pathname-variants.d.ts +3 -0
  190. package/dist/resource-proxy/pathname-variants.js +54 -0
  191. package/dist/resource-proxy.d.ts +4 -2
  192. package/dist/resource-proxy.js +48 -117
  193. package/dist/resources.js +4 -42
  194. package/dist/rewrite-links/js-imports.d.ts +3 -0
  195. package/dist/rewrite-links/js-imports.js +56 -0
  196. package/dist/rewrite-links/link-rel.d.ts +2 -0
  197. package/dist/rewrite-links/link-rel.js +10 -0
  198. package/dist/rewrite-links/meta-refresh.d.ts +3 -0
  199. package/dist/rewrite-links/meta-refresh.js +22 -0
  200. package/dist/rewrite-links/skip.d.ts +1 -0
  201. package/dist/rewrite-links/skip.js +10 -0
  202. package/dist/rewrite-links/srcset.d.ts +3 -0
  203. package/dist/rewrite-links/srcset.js +63 -0
  204. package/dist/rewrite-links/url-resolve.d.ts +3 -0
  205. package/dist/rewrite-links/url-resolve.js +13 -0
  206. package/dist/rewrite-links.d.ts +3 -3
  207. package/dist/rewrite-links.js +31 -240
  208. package/dist/snapshot-builder/api.d.ts +3 -0
  209. package/dist/snapshot-builder/api.js +6 -0
  210. package/dist/snapshot-builder/build-snapshot.d.ts +3 -0
  211. package/dist/snapshot-builder/build-snapshot.js +138 -0
  212. package/dist/snapshot-builder/capture-index/index-capture.d.ts +13 -0
  213. package/dist/snapshot-builder/capture-index/index-capture.js +168 -0
  214. package/dist/snapshot-builder/capture-index/index.d.ts +2 -0
  215. package/dist/snapshot-builder/capture-index/index.js +1 -0
  216. package/dist/snapshot-builder/capture-index/types.d.ts +12 -0
  217. package/dist/snapshot-builder/capture-index/types.js +1 -0
  218. package/dist/snapshot-builder/capture-index.d.ts +12 -0
  219. package/dist/snapshot-builder/capture-index.js +173 -0
  220. package/dist/snapshot-builder/emit-document.d.ts +24 -0
  221. package/dist/snapshot-builder/emit-document.js +50 -0
  222. package/dist/snapshot-builder/grouping.d.ts +8 -0
  223. package/dist/snapshot-builder/grouping.js +87 -0
  224. package/dist/snapshot-builder/http.d.ts +6 -0
  225. package/dist/snapshot-builder/http.js +28 -0
  226. package/dist/snapshot-builder/index.d.ts +4 -0
  227. package/dist/snapshot-builder/index.js +2 -0
  228. package/dist/snapshot-builder/path-map.d.ts +3 -0
  229. package/dist/snapshot-builder/path-map.js +35 -0
  230. package/dist/snapshot-builder/resources-path.d.ts +23 -0
  231. package/dist/snapshot-builder/resources-path.js +47 -0
  232. package/dist/snapshot-builder/rewrite-resource.d.ts +18 -0
  233. package/dist/snapshot-builder/rewrite-resource.js +52 -0
  234. package/dist/snapshot-builder/types.d.ts +37 -0
  235. package/dist/snapshot-builder/types.js +2 -0
  236. package/dist/snapshot-builder.d.ts +12 -8
  237. package/dist/snapshot-builder.js +252 -27
  238. package/dist/types.d.ts +122 -78
  239. package/dist/types.js +4 -2
  240. package/dist/units/contracts-bridge.d.ts +76 -0
  241. package/dist/units/contracts-bridge.js +6 -0
  242. package/dist/units/index.d.ts +4 -0
  243. package/dist/units/index.js +2 -0
  244. package/dist/units/runner.d.ts +11 -0
  245. package/dist/units/runner.js +270 -0
  246. package/dist/units/types.d.ts +39 -0
  247. package/dist/units/types.js +1 -0
  248. package/dist/utils/streams.d.ts +2 -0
  249. package/dist/utils/streams.js +29 -0
  250. package/dist/utils.d.ts +35 -1
  251. package/dist/utils.js +107 -29
  252. package/dist/v3/contracts-bridge.d.ts +69 -0
  253. package/dist/v3/contracts-bridge.js +5 -0
  254. package/dist/v3/index.d.ts +4 -0
  255. package/dist/v3/index.js +2 -0
  256. package/dist/v3/runner.d.ts +20 -0
  257. package/dist/v3/runner.js +245 -0
  258. package/dist/v3/types.d.ts +39 -0
  259. package/dist/v3/types.js +1 -0
  260. package/dist/writers.js +3 -1
  261. package/package.json +11 -3
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToZipPlugin = void 0;
4
+ const writers_1 = require("../../writers");
5
+ class ToZipPlugin {
6
+ constructor() {
7
+ this.name = "built-in:to-zip";
8
+ }
9
+ apply(ctx) {
10
+ ctx.onFinalize(async () => {
11
+ if (!ctx.snapshot) {
12
+ throw new Error("ToZipPlugin requires ctx.snapshot");
13
+ }
14
+ const zip = await (0, writers_1.toZip)(ctx.snapshot, {});
15
+ return { kind: "zip", zip };
16
+ });
17
+ }
18
+ }
19
+ exports.ToZipPlugin = ToZipPlugin;
@@ -0,0 +1,47 @@
1
+ import type { NetworkEvent } from "@pagepocket/interceptor";
2
+ import type { ReplaceElementsConfig } from "../types";
3
+ import type { CaptureWithPluginsOptions, HtmlArtifact, PagePocketCaptureResult, PagePocketContext, PagePocketPlugin } from "./types";
4
+ type Hook<TArgs extends unknown[] = []> = (...args: TArgs) => void | Promise<void>;
5
+ type FinalizeHook = () => void | PagePocketCaptureResult | Promise<void | PagePocketCaptureResult>;
6
+ export type HookRegistries = {
7
+ init: Array<Hook>;
8
+ html: Array<Hook<[payload: {
9
+ html: HtmlArtifact;
10
+ }]>>;
11
+ beforeNetwork: Array<Hook>;
12
+ networkEvent: Array<Hook<[event: NetworkEvent]>>;
13
+ afterNetwork: Array<Hook>;
14
+ finalize: Array<FinalizeHook>;
15
+ };
16
+ export type DeferredTracker = {
17
+ defer(promise: Promise<unknown>): void;
18
+ awaitAll(): Promise<void>;
19
+ };
20
+ type HtmlBarrier = {
21
+ whenHtml(): Promise<HtmlArtifact>;
22
+ resolveHtml(html: HtmlArtifact): void;
23
+ rejectHtml(error: Error): void;
24
+ };
25
+ type HtmlHooksDoneBarrier = {
26
+ whenDone(): Promise<void>;
27
+ resolve(): void;
28
+ reject(error: Error): void;
29
+ };
30
+ export type PagePocketContextInternal = PagePocketContext & {
31
+ _hooks: HookRegistries;
32
+ _deferred: DeferredTracker;
33
+ _replaceElements: ReplaceElementsConfig[];
34
+ _htmlBarrier: HtmlBarrier;
35
+ _htmlHooksDoneBarrier: HtmlHooksDoneBarrier;
36
+ _isFinished(): boolean;
37
+ _setFinished(): void;
38
+ };
39
+ export declare const createDeferredTracker: () => DeferredTracker;
40
+ export declare const createHookRegistries: () => HookRegistries;
41
+ export declare const createPagePocketContext: (input: {
42
+ entry: PagePocketContext["entry"];
43
+ options: CaptureWithPluginsOptions;
44
+ pocketOptions: PagePocketContext["pocketOptions"];
45
+ }) => PagePocketContextInternal;
46
+ export declare const resolveEnabledPlugins: (plugins: PagePocketPlugin[], ctx: PagePocketContext) => Promise<PagePocketPlugin[]>;
47
+ export {};
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveEnabledPlugins = exports.createPagePocketContext = exports.createHookRegistries = exports.createDeferredTracker = void 0;
4
+ const createBarrier = () => {
5
+ let resolve = null;
6
+ let reject = null;
7
+ const promise = new Promise((res, rej) => {
8
+ resolve = res;
9
+ reject = rej;
10
+ });
11
+ return {
12
+ promise,
13
+ resolve: (value) => resolve?.(value),
14
+ reject: (error) => reject?.(error)
15
+ };
16
+ };
17
+ const createHtmlBarrier = (ctxRef) => {
18
+ const barrier = createBarrier();
19
+ return {
20
+ whenHtml: async () => {
21
+ if (ctxRef.html) {
22
+ return ctxRef.html;
23
+ }
24
+ return barrier.promise;
25
+ },
26
+ resolveHtml: (html) => {
27
+ barrier.resolve(html);
28
+ },
29
+ rejectHtml: (error) => {
30
+ barrier.reject(error);
31
+ }
32
+ };
33
+ };
34
+ const createHtmlHooksDoneBarrier = () => {
35
+ const barrier = createBarrier();
36
+ return {
37
+ whenDone: async () => barrier.promise,
38
+ resolve: () => barrier.resolve(undefined),
39
+ reject: (error) => barrier.reject(error)
40
+ };
41
+ };
42
+ const createDeferredTracker = () => {
43
+ const promises = new Set();
44
+ return {
45
+ defer(promise) {
46
+ promises.add(promise);
47
+ promise.finally(() => promises.delete(promise));
48
+ },
49
+ async awaitAll() {
50
+ await Promise.allSettled(Array.from(promises));
51
+ }
52
+ };
53
+ };
54
+ exports.createDeferredTracker = createDeferredTracker;
55
+ const createHookRegistries = () => ({
56
+ init: [],
57
+ html: [],
58
+ beforeNetwork: [],
59
+ networkEvent: [],
60
+ afterNetwork: [],
61
+ finalize: []
62
+ });
63
+ exports.createHookRegistries = createHookRegistries;
64
+ const createPagePocketContext = (input) => {
65
+ const state = {};
66
+ const hooks = (0, exports.createHookRegistries)();
67
+ const deferred = (0, exports.createDeferredTracker)();
68
+ const replaceElements = [];
69
+ let finished = false;
70
+ const ctx = {
71
+ entry: input.entry,
72
+ options: input.options,
73
+ pocketOptions: input.pocketOptions,
74
+ state,
75
+ _hooks: hooks,
76
+ _deferred: deferred,
77
+ _replaceElements: replaceElements,
78
+ _isFinished: () => finished,
79
+ _setFinished: () => {
80
+ finished = true;
81
+ }
82
+ };
83
+ const htmlBarrier = createHtmlBarrier(ctx);
84
+ const htmlHooksDoneBarrier = createHtmlHooksDoneBarrier();
85
+ ctx._htmlBarrier = htmlBarrier;
86
+ ctx._htmlHooksDoneBarrier = htmlHooksDoneBarrier;
87
+ ctx.whenHtml = async () => htmlBarrier.whenHtml();
88
+ ctx.whenHtmlHooksDone = async () => {
89
+ await htmlBarrier.whenHtml();
90
+ return htmlHooksDoneBarrier.whenDone();
91
+ };
92
+ ctx.onInit = (handler) => {
93
+ hooks.init.push(handler);
94
+ };
95
+ ctx.onHtml = (handler) => {
96
+ hooks.html.push(handler);
97
+ };
98
+ ctx.onBeforeNetwork = (handler) => {
99
+ hooks.beforeNetwork.push(handler);
100
+ };
101
+ ctx.onNetworkEvent = (handler) => {
102
+ hooks.networkEvent.push(handler);
103
+ };
104
+ ctx.onAfterNetwork = (handler) => {
105
+ hooks.afterNetwork.push(handler);
106
+ };
107
+ ctx.onFinalize = (handler) => {
108
+ hooks.finalize.push(handler);
109
+ };
110
+ ctx.setHtml = (next) => {
111
+ ctx.html = next;
112
+ htmlBarrier.resolveHtml(next);
113
+ };
114
+ ctx.addReplaceElements = (rules) => {
115
+ replaceElements.push(rules);
116
+ };
117
+ ctx.finish = (result) => {
118
+ if (finished) {
119
+ return;
120
+ }
121
+ ctx.result = result;
122
+ finished = true;
123
+ };
124
+ ctx.defer = (promise) => {
125
+ deferred.defer(promise);
126
+ };
127
+ return ctx;
128
+ };
129
+ exports.createPagePocketContext = createPagePocketContext;
130
+ const resolveEnabledPlugins = async (plugins, ctx) => {
131
+ const enabled = [];
132
+ for (const plugin of plugins) {
133
+ const gate = plugin.enabled;
134
+ if (gate === false) {
135
+ continue;
136
+ }
137
+ // Default enabled when gate is undefined.
138
+ enabled.push(plugin);
139
+ }
140
+ return enabled;
141
+ };
142
+ exports.resolveEnabledPlugins = resolveEnabledPlugins;
@@ -0,0 +1,12 @@
1
+ import type { InterceptTarget, NetworkEvent } from "@pagepocket/interceptor";
2
+ import type { CaptureWithPluginsOptions, PagePocketCaptureResult } from "./types";
3
+ type RunnerInput = {
4
+ pocket: {
5
+ interceptedRequestEvents(): AsyncIterable<NetworkEvent>;
6
+ };
7
+ pocketOptions: import("../types").PagePocketOptions;
8
+ target: InterceptTarget;
9
+ options: CaptureWithPluginsOptions;
10
+ };
11
+ export declare const captureWithPlugins: (input: RunnerInput) => Promise<PagePocketCaptureResult>;
12
+ export {};
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.captureWithPlugins = void 0;
4
+ const completion_1 = require("../completion");
5
+ const debug_1 = require("../debug");
6
+ const inflight_tracker_1 = require("../inflight-tracker");
7
+ const context_1 = require("./context");
8
+ const runHandlersSequentially = async (handlers, args, ctx) => {
9
+ for (const handler of handlers) {
10
+ if (ctx._isFinished()) {
11
+ return;
12
+ }
13
+ await handler(...args);
14
+ }
15
+ };
16
+ const runFinalizeHandlers = async (ctx) => {
17
+ for (const handler of ctx._hooks.finalize) {
18
+ if (ctx._isFinished()) {
19
+ return;
20
+ }
21
+ const result = await handler();
22
+ if (result) {
23
+ ctx.finish(result);
24
+ return;
25
+ }
26
+ }
27
+ };
28
+ const pluginLabel = (plugin) => {
29
+ const ctor = plugin.constructor;
30
+ const ctorName = ctor && typeof ctor.name === "string" ? ctor.name : undefined;
31
+ return {
32
+ name: plugin.name,
33
+ ctorName,
34
+ enabled: plugin.enabled
35
+ };
36
+ };
37
+ const captureWithPlugins = async (input) => {
38
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] capture start", {
39
+ targetKind: input.target.kind,
40
+ adapter: input.options.interceptor?.name,
41
+ pluginCount: input.options.plugins.length
42
+ });
43
+ const plugins = input.options.plugins;
44
+ const ctx = (0, context_1.createPagePocketContext)({
45
+ entry: input.target.kind === "url"
46
+ ? { kind: "url", url: input.target.url }
47
+ : input.target.kind === "puppeteer-page"
48
+ ? { kind: "puppeteer-page", page: input.target.page }
49
+ : input.target.kind === "cdp-tab"
50
+ ? { kind: "cdp-tab", tabId: input.target.tabId }
51
+ : input.target.kind === "html"
52
+ ? { kind: "html-string", baseUrl: input.target.baseUrl, url: input.target.url }
53
+ : (() => {
54
+ throw new Error(`Unsupported target kind: ${input.target.kind}`);
55
+ })(),
56
+ options: input.options,
57
+ pocketOptions: input.pocketOptions
58
+ });
59
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] plugins configured", plugins.map(pluginLabel));
60
+ const allPlugins = await (0, context_1.resolveEnabledPlugins)(plugins, ctx);
61
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] plugins enabled", allPlugins.map(pluginLabel));
62
+ for (const plugin of allPlugins) {
63
+ if (ctx._isFinished()) {
64
+ break;
65
+ }
66
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] plugin.apply start", pluginLabel(plugin));
67
+ await plugin.apply(ctx);
68
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] plugin.apply done", pluginLabel(plugin));
69
+ }
70
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=init start", { count: ctx._hooks.init.length });
71
+ await runHandlersSequentially(ctx._hooks.init, [], ctx);
72
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=init done");
73
+ const interceptor = input.options.interceptor;
74
+ if (!interceptor) {
75
+ // HTML-only flow.
76
+ if (input.target.kind !== "html") {
77
+ throw new Error("options.interceptor is required for non-HTML entrypoints.");
78
+ }
79
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=html (no interceptor) start");
80
+ ctx.setHtml({
81
+ htmlString: input.target.htmlString,
82
+ baseUrl: input.target.baseUrl,
83
+ url: input.target.url,
84
+ contentType: "text/html"
85
+ });
86
+ try {
87
+ await runHandlersSequentially(ctx._hooks.html, [{ html: ctx.html }], ctx);
88
+ ctx._htmlHooksDoneBarrier.resolve();
89
+ }
90
+ catch (error) {
91
+ const err = error instanceof Error ? error : new Error(String(error));
92
+ ctx._htmlHooksDoneBarrier.reject(err);
93
+ throw err;
94
+ }
95
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=html (no interceptor) done");
96
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize start", {
97
+ count: ctx._hooks.finalize.length
98
+ });
99
+ await runFinalizeHandlers(ctx);
100
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize done", { resultKind: ctx.result?.kind });
101
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] awaiting deferred work");
102
+ await ctx._deferred.awaitAll();
103
+ if (!ctx.result) {
104
+ throw new Error("No plugin produced a terminal result.");
105
+ }
106
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] capture done", { resultKind: ctx.result.kind });
107
+ return ctx.result;
108
+ }
109
+ const completionStrategies = (0, completion_1.normalizeCompletion)(input.options.completion);
110
+ const idleMs = input.options.timeoutMs ?? 5000;
111
+ const maxDurationMs = input.options.maxDurationMs;
112
+ const completion = completionStrategies.length > 0
113
+ ? completionStrategies
114
+ : [(0, completion_1.networkIdle)(idleMs), ...(maxDurationMs !== undefined ? [(0, completion_1.timeout)(maxDurationMs)] : [])];
115
+ let stopped = false;
116
+ const inflightTracker = new inflight_tracker_1.InflightTracker();
117
+ const onEvent = async (event) => {
118
+ inflightTracker.handleEvent(event);
119
+ await runHandlersSequentially(ctx._hooks.networkEvent, [event], ctx);
120
+ };
121
+ const handlers = {
122
+ onEvent(event) {
123
+ if (ctx._isFinished()) {
124
+ return;
125
+ }
126
+ input.pocket._emitNetworkEvent(event);
127
+ void onEvent(event);
128
+ },
129
+ onError(error) {
130
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] interceptor error", error);
131
+ }
132
+ };
133
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=session start");
134
+ const session = await interceptor.start(input.target, handlers, {
135
+ timeoutMs: input.options.timeoutMs,
136
+ maxDurationMs: input.options.maxDurationMs
137
+ });
138
+ try {
139
+ if (input.target.kind === "url" && session.navigate) {
140
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=navigate start", { url: input.target.url });
141
+ await session.navigate(input.target.url);
142
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=navigate done");
143
+ }
144
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=waitForHtml start");
145
+ const html = await session.waitForHtml();
146
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=waitForHtml done", {
147
+ url: html.url,
148
+ baseUrl: html.baseUrl,
149
+ contentType: html.contentType,
150
+ htmlBytes: html.htmlString.length
151
+ });
152
+ ctx.setHtml(html);
153
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=html start", { count: ctx._hooks.html.length });
154
+ try {
155
+ await runHandlersSequentially(ctx._hooks.html, [{ html }], ctx);
156
+ ctx._htmlHooksDoneBarrier.resolve();
157
+ }
158
+ catch (error) {
159
+ const err = error instanceof Error ? error : new Error(String(error));
160
+ ctx._htmlHooksDoneBarrier.reject(err);
161
+ throw err;
162
+ }
163
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=html done");
164
+ if (ctx._isFinished()) {
165
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] early finish after html", {
166
+ resultKind: ctx.result?.kind
167
+ });
168
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize start", {
169
+ count: ctx._hooks.finalize.length
170
+ });
171
+ await runFinalizeHandlers(ctx);
172
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize done", { resultKind: ctx.result?.kind });
173
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] awaiting deferred work");
174
+ await ctx._deferred.awaitAll();
175
+ if (!ctx.result) {
176
+ throw new Error("No plugin produced a terminal result.");
177
+ }
178
+ return ctx.result;
179
+ }
180
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=beforeNetwork start", {
181
+ count: ctx._hooks.beforeNetwork.length
182
+ });
183
+ await runHandlersSequentially(ctx._hooks.beforeNetwork, [], ctx);
184
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=beforeNetwork done");
185
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=startCapture start");
186
+ await session.startCapture();
187
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=startCapture done");
188
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=completion wait start", {
189
+ strategies: completion.length
190
+ });
191
+ if (completion.length === 1) {
192
+ await completion[0].wait({
193
+ now: () => Date.now(),
194
+ getStats: () => inflightTracker.getStats()
195
+ });
196
+ }
197
+ else {
198
+ await Promise.race(completion.map((strategy) => strategy.wait({
199
+ now: () => Date.now(),
200
+ getStats: () => inflightTracker.getStats()
201
+ })));
202
+ }
203
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=completion wait done");
204
+ }
205
+ finally {
206
+ if (!stopped) {
207
+ stopped = true;
208
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=session stop start");
209
+ await session.stop();
210
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=session stop done");
211
+ }
212
+ input.pocket._closeNetworkEventStream();
213
+ }
214
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=afterNetwork start", {
215
+ count: ctx._hooks.afterNetwork.length
216
+ });
217
+ await runHandlersSequentially(ctx._hooks.afterNetwork, [], ctx);
218
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=afterNetwork done");
219
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize start", {
220
+ count: ctx._hooks.finalize.length
221
+ });
222
+ await runFinalizeHandlers(ctx);
223
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] phase=finalize done", { resultKind: ctx.result?.kind });
224
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] awaiting deferred work");
225
+ await ctx._deferred.awaitAll();
226
+ if (!ctx.result) {
227
+ throw new Error("No plugin produced a terminal result.");
228
+ }
229
+ (0, debug_1.debugLog)("[pagepocket][plugin-runner] capture done", { resultKind: ctx.result.kind });
230
+ return ctx.result;
231
+ };
232
+ exports.captureWithPlugins = captureWithPlugins;
@@ -0,0 +1,108 @@
1
+ import type { NetworkEvent, NetworkInterceptorAdapter } from "@pagepocket/interceptor";
2
+ import type { ContentStore, PagePocketOptions, PathResolver, ReplaceElementsConfig, ResourceFilter } from "../types";
3
+ export type HtmlArtifact = {
4
+ baseUrl: string;
5
+ url?: string;
6
+ contentType?: string;
7
+ htmlString: string;
8
+ };
9
+ export type EntryInfo = {
10
+ kind: "url";
11
+ url: string;
12
+ } | {
13
+ kind: "puppeteer-page";
14
+ page: unknown;
15
+ url?: string;
16
+ } | {
17
+ kind: "cdp-tab";
18
+ tabId: number;
19
+ url?: string;
20
+ } | {
21
+ kind: "html-string";
22
+ baseUrl: string;
23
+ url?: string;
24
+ } | {
25
+ kind: "document";
26
+ baseUrl: string;
27
+ url?: string;
28
+ };
29
+ export type PagePocketCaptureResult = {
30
+ kind: "raw";
31
+ outputDir: string;
32
+ meta?: unknown;
33
+ } | {
34
+ kind: "zip";
35
+ zip: {
36
+ data: Uint8Array | Blob;
37
+ outputPath: string;
38
+ };
39
+ meta?: unknown;
40
+ } | {
41
+ kind: "html";
42
+ html: string;
43
+ meta?: unknown;
44
+ } | {
45
+ kind: "text";
46
+ text: string;
47
+ meta?: unknown;
48
+ } | {
49
+ kind: "custom";
50
+ value: unknown;
51
+ };
52
+ export interface CaptureWithPluginsOptions {
53
+ /** Needed only if plugins rely on network interception. */
54
+ interceptor?: NetworkInterceptorAdapter;
55
+ /** Plugins are executed sequentially in this order. */
56
+ plugins: PagePocketPlugin[];
57
+ /** Network completion. */
58
+ completion?: import("../types").CompletionStrategy | import("../types").CompletionStrategy[];
59
+ timeoutMs?: number;
60
+ maxDurationMs?: number;
61
+ /** Snapshot-related config (used by BuildSnapshotPlugin). */
62
+ filter?: ResourceFilter;
63
+ blacklist?: RegExp[];
64
+ pathResolver?: PathResolver;
65
+ contentStore?: ContentStore;
66
+ rewriteEntry?: boolean;
67
+ rewriteCSS?: boolean;
68
+ limits?: {
69
+ maxTotalBytes?: number;
70
+ maxSingleResourceBytes?: number;
71
+ maxResources?: number;
72
+ };
73
+ }
74
+ export interface PagePocketPlugin {
75
+ readonly name: string;
76
+ enabled?: boolean;
77
+ /** Register hook handlers on the context. */
78
+ apply(ctx: PagePocketContext): void | Promise<void>;
79
+ }
80
+ export interface PagePocketContext extends Record<string, unknown> {
81
+ entry: EntryInfo;
82
+ options: CaptureWithPluginsOptions;
83
+ pocketOptions: PagePocketOptions;
84
+ /** plugin shared mutable bag */
85
+ state: Record<string, unknown>;
86
+ html?: HtmlArtifact;
87
+ whenHtml(): Promise<HtmlArtifact>;
88
+ whenHtmlHooksDone(): Promise<void>;
89
+ onInit(handler: () => void | Promise<void>): void;
90
+ onHtml(handler: (payload: {
91
+ html: HtmlArtifact;
92
+ }) => void | Promise<void>): void;
93
+ onBeforeNetwork(handler: () => void | Promise<void>): void;
94
+ onNetworkEvent(handler: (event: NetworkEvent) => void | Promise<void>): void;
95
+ onAfterNetwork(handler: () => void | Promise<void>): void;
96
+ onFinalize(handler: () => void | PagePocketCaptureResult | Promise<void | PagePocketCaptureResult>): void;
97
+ /** Allow plugins to update the HTML artifact. */
98
+ setHtml(next: HtmlArtifact): void;
99
+ /** Register replaceElements rules for snapshot build. */
100
+ addReplaceElements(rules: ReplaceElementsConfig): void;
101
+ /** optional: broadcast network events */
102
+ network?: {
103
+ subscribe(): AsyncIterable<NetworkEvent>;
104
+ };
105
+ result?: PagePocketCaptureResult;
106
+ finish(result: PagePocketCaptureResult): void;
107
+ defer(promise: Promise<unknown>): void;
108
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { PagePocketContext, PagePocketPlugin } from "../plugin/types";
2
+ export declare class BuildFilesFromCapturePlugin implements PagePocketPlugin {
3
+ readonly name = "plugin:build-files-from-capture";
4
+ apply(ctx: PagePocketContext): void;
5
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BuildFilesFromCapturePlugin = void 0;
4
+ const __1 = require("..");
5
+ const capture_1 = require("../capture");
6
+ // Note: This plugin is transitional. It consumes ctx.capture (new contract)
7
+ // but reuses existing snapshot builder logic internally.
8
+ class BuildFilesFromCapturePlugin {
9
+ constructor() {
10
+ this.name = "plugin:build-files-from-capture";
11
+ }
12
+ apply(ctx) {
13
+ ctx.onFinalize(async () => {
14
+ const existingFiles = ctx.files;
15
+ if (existingFiles) {
16
+ return;
17
+ }
18
+ const capture = ctx.capture;
19
+ if (!capture) {
20
+ throw new Error("BuildFilesFromCapturePlugin requires ctx.capture");
21
+ }
22
+ const baseFilter = ctx.options.filter ?? (0, __1.createDefaultResourceFilter)();
23
+ const blacklist = ctx.options.blacklist ?? [];
24
+ const isBlacklisted = (url) => typeof url === "string" && blacklist.some((pattern) => pattern.test(url));
25
+ const filter = blacklist.length === 0
26
+ ? baseFilter
27
+ : {
28
+ shouldSave(req, res) {
29
+ if (isBlacklisted(req.url)) {
30
+ (0, __1.debugLog)("[pagepocket] blacklist match (skip save)", req.url);
31
+ return false;
32
+ }
33
+ return baseFilter.shouldSave(req, res);
34
+ }
35
+ };
36
+ const pathResolver = ctx.options.pathResolver ?? (0, __1.createDefaultPathResolver)();
37
+ const rewriteEntry = ctx.options.rewriteEntry ?? true;
38
+ const rewriteCSS = ctx.options.rewriteCSS ?? true;
39
+ const limits = ctx.options.limits;
40
+ const store = await (0, capture_1.captureToNetworkStore)({
41
+ capture,
42
+ filter,
43
+ limits
44
+ });
45
+ const entryUrl = ctx.entry.kind === "url"
46
+ ? ctx.entry.url
47
+ : ctx.entry.kind === "html-string"
48
+ ? (ctx.entry.url ?? ctx.entry.baseUrl)
49
+ : "";
50
+ const internal = ctx;
51
+ const replaceElements = internal._replaceElements && internal._replaceElements.length > 0
52
+ ? internal._replaceElements
53
+ : undefined;
54
+ const replaceElementsMerged = replaceElements
55
+ ? replaceElements.flat()
56
+ : undefined;
57
+ const snapshot = await (0, __1.buildSnapshot)({
58
+ entryUrl,
59
+ createdAt: Date.now(),
60
+ resources: store.getResources(),
61
+ apiEntries: store.getApiEntries(),
62
+ contentStore: capture.contentStore,
63
+ pathResolver,
64
+ rewriteEntry,
65
+ rewriteCSS,
66
+ replaceElements: replaceElementsMerged,
67
+ warnings: []
68
+ });
69
+ const files = {
70
+ root: {
71
+ kind: "directory",
72
+ path: "",
73
+ entries: snapshot.files.map((file) => ({
74
+ kind: "file",
75
+ path: file.path,
76
+ source: { kind: "content-ref", ref: file.source }
77
+ }))
78
+ },
79
+ content: snapshot.content
80
+ };
81
+ ctx.files = files;
82
+ });
83
+ }
84
+ }
85
+ exports.BuildFilesFromCapturePlugin = BuildFilesFromCapturePlugin;
@@ -0,0 +1,5 @@
1
+ import type { PagePocketContext, PagePocketPlugin } from "../plugin/types";
2
+ export declare class BuildWarcPlugin implements PagePocketPlugin {
3
+ readonly name = "plugin:build-warc";
4
+ apply(ctx: PagePocketContext): void;
5
+ }