@nitpicker/crawler 0.9.0 → 0.12.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 (148) hide show
  1. package/lib/archive/archive-accessor.d.ts +87 -14
  2. package/lib/archive/archive-accessor.js +162 -36
  3. package/lib/archive/archive.d.ts +262 -24
  4. package/lib/archive/archive.js +397 -86
  5. package/lib/archive/cache/compute-archive-cache-key.d.ts +39 -0
  6. package/lib/archive/cache/compute-archive-cache-key.js +95 -0
  7. package/lib/archive/cache/extract-archive-to-cache.d.ts +43 -0
  8. package/lib/archive/cache/extract-archive-to-cache.js +309 -0
  9. package/lib/archive/cache/get-archive-cache-root.d.ts +20 -0
  10. package/lib/archive/cache/get-archive-cache-root.js +53 -0
  11. package/lib/archive/cache/is-archive-cache-disabled.d.ts +24 -0
  12. package/lib/archive/cache/is-archive-cache-disabled.js +34 -0
  13. package/lib/archive/cache/resolve-archive-cache-dir.d.ts +26 -0
  14. package/lib/archive/cache/resolve-archive-cache-dir.js +32 -0
  15. package/lib/archive/database.d.ts +411 -26
  16. package/lib/archive/database.js +1881 -540
  17. package/lib/archive/derive-lineage-from-parent.d.ts +37 -0
  18. package/lib/archive/derive-lineage-from-parent.js +42 -0
  19. package/lib/archive/filesystem/peek-tar-top-dir.d.ts +28 -0
  20. package/lib/archive/filesystem/peek-tar-top-dir.js +65 -0
  21. package/lib/archive/get-failed-page-messages.d.ts +43 -0
  22. package/lib/archive/get-failed-page-messages.js +131 -0
  23. package/lib/archive/init-schema.d.ts +53 -2
  24. package/lib/archive/init-schema.js +399 -15
  25. package/lib/archive/is-inventory-source.d.ts +21 -0
  26. package/lib/archive/is-inventory-source.js +22 -0
  27. package/lib/archive/meta/assert-compatible-version.d.ts +39 -0
  28. package/lib/archive/meta/assert-compatible-version.js +72 -0
  29. package/lib/archive/meta/classify-jsonld-type.d.ts +23 -0
  30. package/lib/archive/meta/classify-jsonld-type.js +43 -0
  31. package/lib/archive/meta/compare-semver.d.ts +23 -0
  32. package/lib/archive/meta/compare-semver.js +51 -0
  33. package/lib/archive/meta/compute-page-denormalized.d.ts +21 -0
  34. package/lib/archive/meta/compute-page-denormalized.js +35 -0
  35. package/lib/archive/meta/derive-flat-from-meta.d.ts +35 -0
  36. package/lib/archive/meta/derive-flat-from-meta.js +158 -0
  37. package/lib/archive/meta/derive-meta-extras.d.ts +20 -0
  38. package/lib/archive/meta/derive-meta-extras.js +23 -0
  39. package/lib/archive/meta/extract-tags-for-archive.d.ts +18 -0
  40. package/lib/archive/meta/extract-tags-for-archive.js +36 -0
  41. package/lib/archive/meta/summarize-jsonld.d.ts +17 -0
  42. package/lib/archive/meta/summarize-jsonld.js +29 -0
  43. package/lib/archive/meta/summarize-tags.d.ts +16 -0
  44. package/lib/archive/meta/summarize-tags.js +33 -0
  45. package/lib/archive/meta/types.d.ts +207 -0
  46. package/lib/archive/meta/types.js +33 -0
  47. package/lib/archive/migrate-crawl-errors.d.ts +20 -0
  48. package/lib/archive/migrate-crawl-errors.js +38 -0
  49. package/lib/archive/migrate-html-blob-tables.d.ts +24 -0
  50. package/lib/archive/migrate-html-blob-tables.js +53 -0
  51. package/lib/archive/migrate-inventory-runs.d.ts +29 -0
  52. package/lib/archive/migrate-inventory-runs.js +52 -0
  53. package/lib/archive/migrate-page-errors.d.ts +16 -0
  54. package/lib/archive/migrate-page-errors.js +35 -0
  55. package/lib/archive/migrate-pages-resources-source.d.ts +16 -0
  56. package/lib/archive/migrate-pages-resources-source.js +46 -0
  57. package/lib/archive/page.d.ts +187 -49
  58. package/lib/archive/page.js +258 -63
  59. package/lib/archive/peek-archive-lock.d.ts +40 -0
  60. package/lib/archive/peek-archive-lock.js +62 -0
  61. package/lib/archive/resolve-redirect-chain.d.ts +33 -0
  62. package/lib/archive/resolve-redirect-chain.js +27 -0
  63. package/lib/archive/types.d.ts +168 -26
  64. package/lib/classify-error-kind.d.ts +19 -0
  65. package/lib/classify-error-kind.js +122 -0
  66. package/lib/crawler/build-js-redirect-edge.d.ts +68 -0
  67. package/lib/crawler/build-js-redirect-edge.js +57 -0
  68. package/lib/crawler/build-redirect-event.d.ts +24 -0
  69. package/lib/crawler/build-redirect-event.js +28 -0
  70. package/lib/crawler/clear-dns-burned-host-cache.d.ts +6 -0
  71. package/lib/crawler/clear-dns-burned-host-cache.js +11 -0
  72. package/lib/crawler/close-browser-safely.d.ts +64 -0
  73. package/lib/crawler/close-browser-safely.js +73 -0
  74. package/lib/crawler/crawler.d.ts +7 -2
  75. package/lib/crawler/crawler.js +919 -113
  76. package/lib/crawler/create-change-phase-handler.d.ts +54 -0
  77. package/lib/crawler/create-change-phase-handler.js +44 -0
  78. package/lib/crawler/derive-js-redirect-target.d.ts +68 -0
  79. package/lib/crawler/derive-js-redirect-target.js +129 -0
  80. package/lib/crawler/derive-page-source.d.ts +23 -0
  81. package/lib/crawler/derive-page-source.js +28 -0
  82. package/lib/crawler/derive-resource-source.d.ts +33 -0
  83. package/lib/crawler/derive-resource-source.js +37 -0
  84. package/lib/crawler/dns-burned-host-cache.d.ts +26 -0
  85. package/lib/crawler/dns-burned-host-cache.js +25 -0
  86. package/lib/crawler/dns-burned-host-short-circuit-counter.d.ts +13 -0
  87. package/lib/crawler/dns-burned-host-short-circuit-counter.js +11 -0
  88. package/lib/crawler/drain-phase-errors.d.ts +48 -0
  89. package/lib/crawler/drain-phase-errors.js +35 -0
  90. package/lib/crawler/fetch-destination.d.ts +12 -4
  91. package/lib/crawler/fetch-destination.js +132 -18
  92. package/lib/crawler/format-crawl-progress.d.ts +12 -3
  93. package/lib/crawler/format-crawl-progress.js +14 -6
  94. package/lib/crawler/handle-browser-close.d.ts +29 -0
  95. package/lib/crawler/handle-browser-close.js +28 -0
  96. package/lib/crawler/is-html-content-type.d.ts +17 -0
  97. package/lib/crawler/is-html-content-type.js +19 -0
  98. package/lib/crawler/is-js-redirect-error-shape.d.ts +40 -0
  99. package/lib/crawler/is-js-redirect-error-shape.js +53 -0
  100. package/lib/crawler/is-likely-html-url.d.ts +22 -0
  101. package/lib/crawler/is-likely-html-url.js +65 -0
  102. package/lib/crawler/is-puppeteer-fallback-candidate.d.ts +16 -0
  103. package/lib/crawler/is-puppeteer-fallback-candidate.js +63 -0
  104. package/lib/crawler/kill-process-tree.d.ts +94 -0
  105. package/lib/crawler/kill-process-tree.js +178 -0
  106. package/lib/crawler/link-list.d.ts +21 -1
  107. package/lib/crawler/link-list.js +25 -4
  108. package/lib/crawler/link-to-page-data.d.ts +13 -5
  109. package/lib/crawler/link-to-page-data.js +26 -5
  110. package/lib/crawler/log-undrained-phase-errors.d.ts +37 -0
  111. package/lib/crawler/log-undrained-phase-errors.js +34 -0
  112. package/lib/crawler/normalize-content-type.d.ts +14 -0
  113. package/lib/crawler/normalize-content-type.js +20 -0
  114. package/lib/crawler/partition-urls-by-html.d.ts +16 -0
  115. package/lib/crawler/partition-urls-by-html.js +23 -0
  116. package/lib/crawler/plan-sub-resource-emits.d.ts +63 -0
  117. package/lib/crawler/plan-sub-resource-emits.js +44 -0
  118. package/lib/crawler/preload-short-circuit-error.d.ts +22 -0
  119. package/lib/crawler/preload-short-circuit-error.js +25 -0
  120. package/lib/crawler/redirect-dest-key.d.ts +19 -0
  121. package/lib/crawler/redirect-dest-key.js +27 -0
  122. package/lib/crawler/resource-to-page-data.d.ts +28 -0
  123. package/lib/crawler/resource-to-page-data.js +59 -0
  124. package/lib/crawler/should-burn-host.d.ts +78 -0
  125. package/lib/crawler/should-burn-host.js +61 -0
  126. package/lib/crawler/should-get-fallback-on-head-failure.d.ts +38 -0
  127. package/lib/crawler/should-get-fallback-on-head-failure.js +46 -0
  128. package/lib/crawler/types.d.ts +229 -1
  129. package/lib/crawler-orchestrator.d.ts +105 -3
  130. package/lib/crawler-orchestrator.js +620 -20
  131. package/lib/crawler.d.ts +8 -2
  132. package/lib/crawler.js +6 -1
  133. package/lib/permanent-error-kinds.d.ts +43 -0
  134. package/lib/permanent-error-kinds.js +48 -0
  135. package/lib/resource-row-to-lookup-result.d.ts +13 -0
  136. package/lib/resource-row-to-lookup-result.js +20 -0
  137. package/lib/types.d.ts +95 -1
  138. package/lib/utils/compute-file-sha256.d.ts +23 -0
  139. package/lib/utils/compute-file-sha256.js +55 -0
  140. package/lib/utils/error/emit-error-with-retry.d.ts +40 -0
  141. package/lib/utils/error/emit-error-with-retry.js +44 -0
  142. package/lib/utils/error/emit-error.d.ts +39 -0
  143. package/lib/utils/error/emit-error.js +41 -0
  144. package/lib/utils/object/parse-response-headers.d.ts +12 -0
  145. package/lib/utils/object/parse-response-headers.js +26 -0
  146. package/package.json +11 -11
  147. package/lib/utils/error/error-emitter.d.ts +0 -18
  148. package/lib/utils/error/error-emitter.js +0 -29
@@ -0,0 +1,73 @@
1
+ import { crawlerLog } from '../debug.js';
2
+ import { killProcessTree } from './kill-process-tree.js';
3
+ /**
4
+ * Default time to wait for a graceful `browser.close()` before force-killing
5
+ * the underlying Chromium process, in milliseconds.
6
+ */
7
+ const DEFAULT_CLOSE_TIMEOUT_MS = 30 * 1000;
8
+ /**
9
+ * Closes a Puppeteer browser, falling back to a hard tree-kill if the graceful
10
+ * close hangs.
11
+ *
12
+ * WHY: When a page's Chromium session dies mid-scrape (e.g. a viewport change
13
+ * detaches the frame, surfacing `Attempted to use detached Frame` or
14
+ * `Session closed`), the CDP connection can be left wedged. A bare
15
+ * `await browser.close()` then never settles, stalling the `deal()` worker and
16
+ * hanging the whole crawl. Racing the close against a timeout and SIGKILLing
17
+ * the Chromium process tree (parent + renderer/network/zygote children) on
18
+ * expiry guarantees the worker always completes and no orphan subprocesses are
19
+ * left behind.
20
+ *
21
+ * The losing timer is cleared explicitly in `.finally()` so it never keeps the
22
+ * event loop alive after the race settles (a plain `delay()` in `Promise.race`
23
+ * would leak the timer until it fires).
24
+ *
25
+ * The tree-kill happens via {@link killProcessTree}, which enumerates
26
+ * descendants through `ps` (POSIX) or delegates to `taskkill /T /F` (Windows).
27
+ * `childProcess.kill('SIGKILL')` is still invoked on the parent up-front
28
+ * because Node's `ChildProcess.killed` flag governs how Node treats the
29
+ * spawn handle (reaping etc.); without it the parent would linger in Node's
30
+ * process table even after the OS-level kill.
31
+ * @param browser - The browser to close.
32
+ * @param timeoutMs - Milliseconds to wait for a graceful close before force-killing.
33
+ * Defaults to {@link DEFAULT_CLOSE_TIMEOUT_MS}.
34
+ * @param deps - Test-time overrides (default-free for production callers).
35
+ * @returns `true` if the graceful close timed out (and a tree-kill was
36
+ * attempted), `false` if `close()` settled in time.
37
+ */
38
+ export async function closeBrowserSafely(browser, timeoutMs = DEFAULT_CLOSE_TIMEOUT_MS, deps = {}) {
39
+ // Capture the process up-front: after a successful close() puppeteer
40
+ // releases its internal reference and process() returns null, so we would
41
+ // have no handle to tree-kill on timeout.
42
+ const childProcess = browser.process();
43
+ let timeoutHandle;
44
+ const timedOut = await Promise.race([
45
+ browser
46
+ .close()
47
+ .then(() => false)
48
+ .catch(() => false),
49
+ new Promise((resolve) => {
50
+ timeoutHandle = setTimeout(() => resolve(true), timeoutMs);
51
+ }),
52
+ ]).finally(() => {
53
+ if (timeoutHandle) {
54
+ clearTimeout(timeoutHandle);
55
+ }
56
+ });
57
+ if (timedOut && childProcess && !childProcess.killed) {
58
+ // Mark the Node ChildProcess as killed so Node's reaping logic treats
59
+ // it correctly; then walk the OS process tree.
60
+ childProcess.kill('SIGKILL');
61
+ // Capture pid once: ChildProcess.pid is technically `number | undefined`
62
+ // (undefined before spawn settles), and reading it twice across the
63
+ // `await` below would force the second read to re-widen back to
64
+ // `number | undefined` regardless of the typeof guard. Snapshotting
65
+ // makes the type and the runtime value match.
66
+ const pid = childProcess.pid;
67
+ if (typeof pid === 'number') {
68
+ const killTree = deps.killTree ?? ((p, sig) => killProcessTree(p, sig, { log: crawlerLog }));
69
+ await killTree(pid, 'SIGKILL');
70
+ }
71
+ }
72
+ return timedOut;
73
+ }
@@ -53,8 +53,11 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
53
53
  * @param pending - URLs that were pending (not yet scraped) in the previous session.
54
54
  * @param scraped - URLs that were already scraped in the previous session.
55
55
  * @param resources - Resource URLs that were already captured in the previous session.
56
+ * @param pagesScrapedOffset - Number of HTML pages already rendered in previous
57
+ * sessions, used to seed the session-spanning progress counter. Defaults to 0
58
+ * for callers that don't need cross-session accuracy in the progress display.
56
59
  */
57
- resume(pending: string[], scraped: string[], resources: string[]): void;
60
+ resume(pending: string[], scraped: string[], resources: string[], pagesScrapedOffset?: number): void;
58
61
  /**
59
62
  * Start crawling from one or more root URLs.
60
63
  *
@@ -68,7 +71,8 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
68
71
  * before reaching the dealer so a URL that exists in both sources — which
69
72
  * is common in append-mode when a new root coincides with a repromoted
70
73
  * previously-external page — does not race on two parallel slots.
71
- * @param urls - The list of root URLs to begin crawling from. Must be non-empty.
74
+ * @param urls - The list of root URLs to begin crawling from. May be empty
75
+ * when resumed pending URLs already exist (for example `--retry-failed`).
72
76
  * @param opts - Optional overrides; currently only `recursive` is honoured.
73
77
  * @param opts.recursive - When `false`, disables recursive discovery and forces list-mode.
74
78
  * Defaults to the constructor option's `recursive` value.
@@ -77,6 +81,7 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
77
81
  start(urls: ExURL[], opts?: {
78
82
  recursive?: boolean;
79
83
  }): void;
84
+ private _launchBrowserAndScrape;
80
85
  /**
81
86
  * The default maximum number of concurrent scraping processes.
82
87
  *