@nitpicker/crawler 0.12.0 → 0.13.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 (349) hide show
  1. package/README.md +6 -4
  2. package/lib/archive/archive-accessor.d.ts +2 -2
  3. package/lib/archive/archive-accessor.js +2 -2
  4. package/lib/archive/archive-lock.d.ts +7 -0
  5. package/lib/archive/archive-lock.js +7 -0
  6. package/lib/archive/archive.d.ts +63 -16
  7. package/lib/archive/archive.js +56 -17
  8. package/lib/archive/create-adjunct-tables.d.ts +43 -0
  9. package/lib/archive/create-adjunct-tables.js +213 -0
  10. package/lib/archive/create-entity-tables.d.ts +173 -0
  11. package/lib/archive/create-entity-tables.js +318 -0
  12. package/lib/archive/create-progress-reporter.d.ts +30 -0
  13. package/lib/archive/create-progress-reporter.js +38 -0
  14. package/lib/archive/create-ref-tables.d.ts +35 -0
  15. package/lib/archive/create-ref-tables.js +188 -0
  16. package/lib/archive/database.d.ts +92 -345
  17. package/lib/archive/database.js +168 -1942
  18. package/lib/archive/db-ops/_shared/clear-write-ref-caches.d.ts +27 -0
  19. package/lib/archive/db-ops/_shared/clear-write-ref-caches.js +34 -0
  20. package/lib/archive/db-ops/_shared/create-write-ref-caches.d.ts +17 -0
  21. package/lib/archive/db-ops/_shared/create-write-ref-caches.js +26 -0
  22. package/lib/archive/db-ops/_shared/decode-json-ref.d.ts +17 -0
  23. package/lib/archive/db-ops/_shared/decode-json-ref.js +31 -0
  24. package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.d.ts +20 -0
  25. package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.js +53 -0
  26. package/lib/archive/db-ops/_shared/resolve-content-item-id.d.ts +61 -0
  27. package/lib/archive/db-ops/_shared/resolve-content-item-id.js +111 -0
  28. package/lib/archive/db-ops/_shared/resolve-url-or-blob.d.ts +23 -0
  29. package/lib/archive/db-ops/_shared/resolve-url-or-blob.js +29 -0
  30. package/lib/archive/db-ops/_shared/retry-setting.d.ts +16 -0
  31. package/lib/archive/db-ops/_shared/retry-setting.js +18 -0
  32. package/lib/archive/db-ops/_shared/safe-parse-json.d.ts +11 -0
  33. package/lib/archive/db-ops/_shared/safe-parse-json.js +18 -0
  34. package/lib/archive/db-ops/_shared/types.d.ts +53 -0
  35. package/lib/archive/db-ops/_shared/types.js +1 -0
  36. package/lib/archive/db-ops/_shared/upsert-blob-ref.d.ts +25 -0
  37. package/lib/archive/db-ops/_shared/upsert-blob-ref.js +48 -0
  38. package/lib/archive/db-ops/_shared/upsert-content-type-ref.d.ts +30 -0
  39. package/lib/archive/db-ops/_shared/upsert-content-type-ref.js +45 -0
  40. package/lib/archive/db-ops/_shared/upsert-json-ref.d.ts +22 -0
  41. package/lib/archive/db-ops/_shared/upsert-json-ref.js +41 -0
  42. package/lib/archive/db-ops/_shared/upsert-response-headers.d.ts +35 -0
  43. package/lib/archive/db-ops/_shared/upsert-response-headers.js +49 -0
  44. package/lib/archive/db-ops/_shared/upsert-url-ref.d.ts +39 -0
  45. package/lib/archive/db-ops/_shared/upsert-url-ref.js +62 -0
  46. package/lib/archive/db-ops/analysis/replace-analysis-violations.d.ts +28 -0
  47. package/lib/archive/db-ops/analysis/replace-analysis-violations.js +152 -0
  48. package/lib/archive/db-ops/anchors/get-anchors-on-page.d.ts +10 -0
  49. package/lib/archive/db-ops/anchors/get-anchors-on-page.js +21 -0
  50. package/lib/archive/db-ops/config/get-base-url.d.ts +8 -0
  51. package/lib/archive/db-ops/config/get-base-url.js +14 -0
  52. package/lib/archive/db-ops/config/get-config.d.ts +10 -0
  53. package/lib/archive/db-ops/config/get-config.js +27 -0
  54. package/lib/archive/db-ops/config/get-name.d.ts +8 -0
  55. package/lib/archive/db-ops/config/get-name.js +14 -0
  56. package/lib/archive/db-ops/config/info-column-allowlist.d.ts +7 -0
  57. package/lib/archive/db-ops/config/info-column-allowlist.js +26 -0
  58. package/lib/archive/db-ops/config/info-json-columns.d.ts +5 -0
  59. package/lib/archive/db-ops/config/info-json-columns.js +10 -0
  60. package/lib/archive/db-ops/config/set-config.d.ts +12 -0
  61. package/lib/archive/db-ops/config/set-config.js +21 -0
  62. package/lib/archive/db-ops/config/update-config.d.ts +17 -0
  63. package/lib/archive/db-ops/config/update-config.js +36 -0
  64. package/lib/archive/db-ops/errors/insert-crawl-error.d.ts +15 -0
  65. package/lib/archive/db-ops/errors/insert-crawl-error.js +21 -0
  66. package/lib/archive/db-ops/errors/insert-page-error.d.ts +21 -0
  67. package/lib/archive/db-ops/errors/insert-page-error.js +28 -0
  68. package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.d.ts +22 -0
  69. package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.js +141 -0
  70. package/lib/archive/db-ops/html/get-html-of-page-by-id.d.ts +18 -0
  71. package/lib/archive/db-ops/html/get-html-of-page-by-id.js +29 -0
  72. package/lib/archive/db-ops/inventory/record-inventory-run.d.ts +21 -0
  73. package/lib/archive/db-ops/inventory/record-inventory-run.js +38 -0
  74. package/lib/archive/db-ops/lifecycle/checkpoint.d.ts +8 -0
  75. package/lib/archive/db-ops/lifecycle/checkpoint.js +9 -0
  76. package/lib/archive/db-ops/lifecycle/destroy.d.ts +6 -0
  77. package/lib/archive/db-ops/lifecycle/destroy.js +7 -0
  78. package/lib/archive/db-ops/lifecycle/init.d.ts +22 -0
  79. package/lib/archive/db-ops/lifecycle/init.js +42 -0
  80. package/lib/archive/db-ops/meta/get-jsonld-of-page.d.ts +13 -0
  81. package/lib/archive/db-ops/meta/get-jsonld-of-page.js +27 -0
  82. package/lib/archive/db-ops/meta/get-tags-of-page.d.ts +12 -0
  83. package/lib/archive/db-ops/meta/get-tags-of-page.js +28 -0
  84. package/lib/archive/db-ops/pages/order/set-url-order.d.ts +8 -0
  85. package/lib/archive/db-ops/pages/order/set-url-order.js +32 -0
  86. package/lib/archive/db-ops/pages/read/build-page-query.d.ts +18 -0
  87. package/lib/archive/db-ops/pages/read/build-page-query.js +40 -0
  88. package/lib/archive/db-ops/pages/read/get-crawling-state.d.ts +70 -0
  89. package/lib/archive/db-ops/pages/read/get-crawling-state.js +98 -0
  90. package/lib/archive/db-ops/pages/read/get-existing-page-urls.d.ts +15 -0
  91. package/lib/archive/db-ops/pages/read/get-existing-page-urls.js +30 -0
  92. package/lib/archive/db-ops/pages/read/get-page-count.d.ts +12 -0
  93. package/lib/archive/db-ops/pages/read/get-page-count.js +21 -0
  94. package/lib/archive/db-ops/pages/read/get-page-source-by-url.d.ts +24 -0
  95. package/lib/archive/db-ops/pages/read/get-page-source-by-url.js +28 -0
  96. package/lib/archive/db-ops/pages/read/get-pages-with-rels.d.ts +38 -0
  97. package/lib/archive/db-ops/pages/read/get-pages-with-rels.js +107 -0
  98. package/lib/archive/db-ops/pages/read/get-pages.d.ts +11 -0
  99. package/lib/archive/db-ops/pages/read/get-pages.js +51 -0
  100. package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.d.ts +18 -0
  101. package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.js +25 -0
  102. package/lib/archive/db-ops/pages/read/reconstruct-page-rows.d.ts +31 -0
  103. package/lib/archive/db-ops/pages/read/reconstruct-page-rows.js +32 -0
  104. package/lib/archive/db-ops/pages/reset/repromote-external-pages.d.ts +24 -0
  105. package/lib/archive/db-ops/pages/reset/repromote-external-pages.js +93 -0
  106. package/lib/archive/db-ops/pages/reset/reset-failed-pages.d.ts +47 -0
  107. package/lib/archive/db-ops/pages/reset/reset-failed-pages.js +124 -0
  108. package/lib/archive/db-ops/pages/write/insert-inventory-seeds.d.ts +37 -0
  109. package/lib/archive/db-ops/pages/write/insert-inventory-seeds.js +72 -0
  110. package/lib/archive/db-ops/pages/write/insert-jsonld.d.ts +17 -0
  111. package/lib/archive/db-ops/pages/write/insert-jsonld.js +49 -0
  112. package/lib/archive/db-ops/pages/write/insert-page.d.ts +36 -0
  113. package/lib/archive/db-ops/pages/write/insert-page.js +208 -0
  114. package/lib/archive/db-ops/pages/write/insert-tags.d.ts +16 -0
  115. package/lib/archive/db-ops/pages/write/insert-tags.js +34 -0
  116. package/lib/archive/db-ops/pages/write/link-redirect-sources.d.ts +36 -0
  117. package/lib/archive/db-ops/pages/write/link-redirect-sources.js +93 -0
  118. package/lib/archive/db-ops/pages/write/record-redirect.d.ts +35 -0
  119. package/lib/archive/db-ops/pages/write/record-redirect.js +100 -0
  120. package/lib/archive/db-ops/pages/write/set-skipped-page.d.ts +13 -0
  121. package/lib/archive/db-ops/pages/write/set-skipped-page.js +22 -0
  122. package/lib/archive/db-ops/pages/write/update-page.d.ts +29 -0
  123. package/lib/archive/db-ops/pages/write/update-page.js +334 -0
  124. package/lib/archive/db-ops/pages/write/write-page-html-blob.d.ts +19 -0
  125. package/lib/archive/db-ops/pages/write/write-page-html-blob.js +41 -0
  126. package/lib/archive/db-ops/referrers/get-redirects-for-pages.d.ts +9 -0
  127. package/lib/archive/db-ops/referrers/get-redirects-for-pages.js +15 -0
  128. package/lib/archive/db-ops/referrers/get-referrers-of-page.d.ts +17 -0
  129. package/lib/archive/db-ops/referrers/get-referrers-of-page.js +32 -0
  130. package/lib/archive/db-ops/referrers/get-referrers-of-resource.d.ts +8 -0
  131. package/lib/archive/db-ops/referrers/get-referrers-of-resource.js +15 -0
  132. package/lib/archive/db-ops/resources/build-resource-query.d.ts +25 -0
  133. package/lib/archive/db-ops/resources/build-resource-query.js +29 -0
  134. package/lib/archive/db-ops/resources/get-existing-resource-urls.d.ts +9 -0
  135. package/lib/archive/db-ops/resources/get-existing-resource-urls.js +24 -0
  136. package/lib/archive/db-ops/resources/get-resource-by-url.d.ts +13 -0
  137. package/lib/archive/db-ops/resources/get-resource-by-url.js +22 -0
  138. package/lib/archive/db-ops/resources/get-resource-url-list.d.ts +9 -0
  139. package/lib/archive/db-ops/resources/get-resource-url-list.js +13 -0
  140. package/lib/archive/db-ops/resources/get-resources.d.ts +8 -0
  141. package/lib/archive/db-ops/resources/get-resources.js +11 -0
  142. package/lib/archive/db-ops/resources/insert-inventory-resources.d.ts +24 -0
  143. package/lib/archive/db-ops/resources/insert-inventory-resources.js +64 -0
  144. package/lib/archive/db-ops/resources/insert-resource-referrers.d.ts +15 -0
  145. package/lib/archive/db-ops/resources/insert-resource-referrers.js +54 -0
  146. package/lib/archive/db-ops/resources/insert-resource.d.ts +34 -0
  147. package/lib/archive/db-ops/resources/insert-resource.js +73 -0
  148. package/lib/archive/db-ops/resources/reconstruct-resource-rows.d.ts +26 -0
  149. package/lib/archive/db-ops/resources/reconstruct-resource-rows.js +30 -0
  150. package/lib/archive/decode-html-blob.d.ts +18 -0
  151. package/lib/archive/decode-html-blob.js +31 -0
  152. package/lib/archive/derive-lineage-from-parent.d.ts +1 -1
  153. package/lib/archive/derive-lineage-from-parent.js +1 -1
  154. package/lib/archive/drop-legacy-tables.d.ts +45 -0
  155. package/lib/archive/drop-legacy-tables.js +56 -0
  156. package/lib/archive/filesystem/rename.js +1 -1
  157. package/lib/archive/get-failed-page-messages.d.ts +5 -4
  158. package/lib/archive/get-failed-page-messages.js +5 -4
  159. package/lib/archive/init-schema.d.ts +35 -39
  160. package/lib/archive/init-schema.js +99 -460
  161. package/lib/archive/limited-page-ids.d.ts +2 -1
  162. package/lib/archive/limited-page-ids.js +5 -4
  163. package/lib/archive/meta/assert-compatible-version.d.ts +24 -3
  164. package/lib/archive/meta/assert-compatible-version.js +24 -3
  165. package/lib/archive/meta/types.d.ts +87 -1
  166. package/lib/archive/meta/types.js +34 -2
  167. package/lib/archive/migrate-entity-tables.d.ts +45 -0
  168. package/lib/archive/migrate-entity-tables.js +56 -0
  169. package/lib/archive/migrate-ref-tables.d.ts +25 -0
  170. package/lib/archive/migrate-ref-tables.js +38 -0
  171. package/lib/archive/page-meta-column-maps.d.ts +32 -0
  172. package/lib/archive/page-meta-column-maps.js +43 -0
  173. package/lib/archive/page.d.ts +6 -6
  174. package/lib/archive/page.js +5 -5
  175. package/lib/archive/peek-archive-lock.d.ts +2 -2
  176. package/lib/archive/peek-archive-lock.js +2 -2
  177. package/lib/archive/populate-entity-tables/collapse-anchor-rows.d.ts +41 -0
  178. package/lib/archive/populate-entity-tables/collapse-anchor-rows.js +87 -0
  179. package/lib/archive/populate-entity-tables/derive-dom-path.d.ts +35 -0
  180. package/lib/archive/populate-entity-tables/derive-dom-path.js +72 -0
  181. package/lib/archive/populate-entity-tables/is-blob-ref-value.d.ts +16 -0
  182. package/lib/archive/populate-entity-tables/is-blob-ref-value.js +19 -0
  183. package/lib/archive/populate-entity-tables/match-images-to-dom-paths.d.ts +66 -0
  184. package/lib/archive/populate-entity-tables/match-images-to-dom-paths.js +96 -0
  185. package/lib/archive/populate-entity-tables/populate-anchor-edges.d.ts +33 -0
  186. package/lib/archive/populate-entity-tables/populate-anchor-edges.js +153 -0
  187. package/lib/archive/populate-entity-tables/populate-content-items.d.ts +40 -0
  188. package/lib/archive/populate-entity-tables/populate-content-items.js +141 -0
  189. package/lib/archive/populate-entity-tables/populate-entities.d.ts +81 -0
  190. package/lib/archive/populate-entity-tables/populate-entities.js +111 -0
  191. package/lib/archive/populate-entity-tables/populate-image-items.d.ts +91 -0
  192. package/lib/archive/populate-entity-tables/populate-image-items.js +223 -0
  193. package/lib/archive/populate-entity-tables/populate-page-meta.d.ts +33 -0
  194. package/lib/archive/populate-entity-tables/populate-page-meta.js +267 -0
  195. package/lib/archive/populate-entity-tables/populate-resource-items.d.ts +22 -0
  196. package/lib/archive/populate-entity-tables/populate-resource-items.js +114 -0
  197. package/lib/archive/populate-entity-tables/populate-resource-ref-edges.d.ts +31 -0
  198. package/lib/archive/populate-entity-tables/populate-resource-ref-edges.js +33 -0
  199. package/lib/archive/populate-entity-tables/resolve-blob-refs.d.ts +31 -0
  200. package/lib/archive/populate-entity-tables/resolve-blob-refs.js +100 -0
  201. package/lib/archive/populate-entity-tables/resolve-content-type-refs.d.ts +22 -0
  202. package/lib/archive/populate-entity-tables/resolve-content-type-refs.js +27 -0
  203. package/lib/archive/populate-entity-tables/resolve-header-sets.d.ts +49 -0
  204. package/lib/archive/populate-entity-tables/resolve-header-sets.js +122 -0
  205. package/lib/archive/populate-entity-tables/resolve-json-refs.d.ts +25 -0
  206. package/lib/archive/populate-entity-tables/resolve-json-refs.js +67 -0
  207. package/lib/archive/populate-entity-tables/resolve-text-refs.d.ts +30 -0
  208. package/lib/archive/populate-entity-tables/resolve-text-refs.js +61 -0
  209. package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.d.ts +21 -0
  210. package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.js +27 -0
  211. package/lib/archive/populate-entity-tables/resolve-url-refs.d.ts +33 -0
  212. package/lib/archive/populate-entity-tables/resolve-url-refs.js +60 -0
  213. package/lib/archive/populate-entity-tables/test-utils/count-rows.d.ts +17 -0
  214. package/lib/archive/populate-entity-tables/test-utils/count-rows.js +20 -0
  215. package/lib/archive/populate-entity-tables/test-utils/seed-content-items.d.ts +25 -0
  216. package/lib/archive/populate-entity-tables/test-utils/seed-content-items.js +42 -0
  217. package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.d.ts +23 -0
  218. package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.js +178 -0
  219. package/lib/archive/populate-entity-tables/types.d.ts +157 -0
  220. package/lib/archive/populate-entity-tables/types.js +12 -0
  221. package/lib/archive/populate-entity-tables/upsert-text-refs.d.ts +38 -0
  222. package/lib/archive/populate-entity-tables/upsert-text-refs.js +78 -0
  223. package/lib/archive/populate-ref-tables/classify-content-type.d.ts +16 -0
  224. package/lib/archive/populate-ref-tables/classify-content-type.js +52 -0
  225. package/lib/archive/populate-ref-tables/compute-content-hash.d.ts +22 -0
  226. package/lib/archive/populate-ref-tables/compute-content-hash.js +26 -0
  227. package/lib/archive/populate-ref-tables/compute-header-flags.d.ts +16 -0
  228. package/lib/archive/populate-ref-tables/compute-header-flags.js +70 -0
  229. package/lib/archive/populate-ref-tables/content-type-rules.d.ts +38 -0
  230. package/lib/archive/populate-ref-tables/content-type-rules.js +133 -0
  231. package/lib/archive/populate-ref-tables/create-header-table-caches.d.ts +25 -0
  232. package/lib/archive/populate-ref-tables/create-header-table-caches.js +49 -0
  233. package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.d.ts +15 -0
  234. package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.js +15 -0
  235. package/lib/archive/populate-ref-tables/decode-data-uri.d.ts +21 -0
  236. package/lib/archive/populate-ref-tables/decode-data-uri.js +126 -0
  237. package/lib/archive/populate-ref-tables/decompose-header-set.d.ts +29 -0
  238. package/lib/archive/populate-ref-tables/decompose-header-set.js +157 -0
  239. package/lib/archive/populate-ref-tables/decompose-url.d.ts +25 -0
  240. package/lib/archive/populate-ref-tables/decompose-url.js +70 -0
  241. package/lib/archive/populate-ref-tables/header-stability.d.ts +19 -0
  242. package/lib/archive/populate-ref-tables/header-stability.js +22 -0
  243. package/lib/archive/populate-ref-tables/header-value-cache-key.d.ts +17 -0
  244. package/lib/archive/populate-ref-tables/header-value-cache-key.js +19 -0
  245. package/lib/archive/populate-ref-tables/normalize-mime.d.ts +24 -0
  246. package/lib/archive/populate-ref-tables/normalize-mime.js +36 -0
  247. package/lib/archive/populate-ref-tables/populate-blob-refs.d.ts +38 -0
  248. package/lib/archive/populate-ref-tables/populate-blob-refs.js +134 -0
  249. package/lib/archive/populate-ref-tables/populate-content-type-refs.d.ts +27 -0
  250. package/lib/archive/populate-ref-tables/populate-content-type-refs.js +70 -0
  251. package/lib/archive/populate-ref-tables/populate-header-tables.d.ts +35 -0
  252. package/lib/archive/populate-ref-tables/populate-header-tables.js +80 -0
  253. package/lib/archive/populate-ref-tables/populate-json-refs.d.ts +29 -0
  254. package/lib/archive/populate-ref-tables/populate-json-refs.js +101 -0
  255. package/lib/archive/populate-ref-tables/populate-refs.d.ts +51 -0
  256. package/lib/archive/populate-ref-tables/populate-refs.js +62 -0
  257. package/lib/archive/populate-ref-tables/populate-text-refs.d.ts +32 -0
  258. package/lib/archive/populate-ref-tables/populate-text-refs.js +133 -0
  259. package/lib/archive/populate-ref-tables/populate-url-refs.d.ts +28 -0
  260. package/lib/archive/populate-ref-tables/populate-url-refs.js +148 -0
  261. package/lib/archive/populate-ref-tables/test-utils/count-rows.d.ts +15 -0
  262. package/lib/archive/populate-ref-tables/test-utils/count-rows.js +17 -0
  263. package/lib/archive/populate-ref-tables/types.d.ts +197 -0
  264. package/lib/archive/populate-ref-tables/types.js +7 -0
  265. package/lib/archive/populate-ref-tables/upsert-one-header-set.d.ts +34 -0
  266. package/lib/archive/populate-ref-tables/upsert-one-header-set.js +208 -0
  267. package/lib/archive/populate-ref-tables/volatile-header-names.d.ts +20 -0
  268. package/lib/archive/populate-ref-tables/volatile-header-names.js +33 -0
  269. package/lib/archive/redirect-table.d.ts +4 -2
  270. package/lib/archive/redirect-table.js +15 -10
  271. package/lib/archive/resolve-redirect-chain.d.ts +3 -3
  272. package/lib/archive/resolve-redirect-chain.js +2 -2
  273. package/lib/archive/resource.d.ts +1 -1
  274. package/lib/archive/retarget-legacy-fk-tables.d.ts +47 -0
  275. package/lib/archive/retarget-legacy-fk-tables.js +107 -0
  276. package/lib/archive/test-utils/fk-parent-tables.d.ts +15 -0
  277. package/lib/archive/test-utils/fk-parent-tables.js +19 -0
  278. package/lib/archive/test-utils/seed-content-item.d.ts +35 -0
  279. package/lib/archive/test-utils/seed-content-item.js +42 -0
  280. package/lib/archive/test-utils/setup-legacy-fk-db.d.ts +33 -0
  281. package/lib/archive/test-utils/setup-legacy-fk-db.js +270 -0
  282. package/lib/archive/types.d.ts +127 -24
  283. package/lib/archive/verify-migration/capture-rejection.d.ts +24 -0
  284. package/lib/archive/verify-migration/capture-rejection.js +31 -0
  285. package/lib/archive/verify-migration/check-anchor-edges-count.d.ts +34 -0
  286. package/lib/archive/verify-migration/check-anchor-edges-count.js +72 -0
  287. package/lib/archive/verify-migration/check-anchor-edges-sum.d.ts +13 -0
  288. package/lib/archive/verify-migration/check-anchor-edges-sum.js +27 -0
  289. package/lib/archive/verify-migration/check-content-items-count.d.ts +16 -0
  290. package/lib/archive/verify-migration/check-content-items-count.js +30 -0
  291. package/lib/archive/verify-migration/check-content-type-preservation.d.ts +22 -0
  292. package/lib/archive/verify-migration/check-content-type-preservation.js +40 -0
  293. package/lib/archive/verify-migration/check-foreign-key-integrity.d.ts +31 -0
  294. package/lib/archive/verify-migration/check-foreign-key-integrity.js +47 -0
  295. package/lib/archive/verify-migration/check-image-items-count.d.ts +12 -0
  296. package/lib/archive/verify-migration/check-image-items-count.js +26 -0
  297. package/lib/archive/verify-migration/check-page-meta-count.d.ts +15 -0
  298. package/lib/archive/verify-migration/check-page-meta-count.js +31 -0
  299. package/lib/archive/verify-migration/check-reader-parity.d.ts +23 -0
  300. package/lib/archive/verify-migration/check-reader-parity.js +211 -0
  301. package/lib/archive/verify-migration/check-resource-items-count.d.ts +17 -0
  302. package/lib/archive/verify-migration/check-resource-items-count.js +33 -0
  303. package/lib/archive/verify-migration/check-url-round-trip.d.ts +43 -0
  304. package/lib/archive/verify-migration/check-url-round-trip.js +112 -0
  305. package/lib/archive/verify-migration/types.d.ts +70 -0
  306. package/lib/archive/verify-migration/types.js +63 -0
  307. package/lib/archive/verify-migration/verify-migration.d.ts +41 -0
  308. package/lib/archive/verify-migration/verify-migration.js +120 -0
  309. package/lib/crawler/build-redirect-event.d.ts +1 -1
  310. package/lib/crawler/build-redirect-event.js +1 -1
  311. package/lib/crawler/capture-image-dom-paths.d.ts +33 -0
  312. package/lib/crawler/capture-image-dom-paths.js +39 -0
  313. package/lib/crawler/clear-dns-burned-host-cache.d.ts +1 -1
  314. package/lib/crawler/clear-dns-burned-host-cache.js +1 -1
  315. package/lib/crawler/collect-image-dom-paths.d.ts +23 -0
  316. package/lib/crawler/collect-image-dom-paths.js +64 -0
  317. package/lib/crawler/crawler.d.ts +19 -0
  318. package/lib/crawler/crawler.js +40 -26
  319. package/lib/crawler/dns-burned-host-cache.d.ts +3 -3
  320. package/lib/crawler/dns-burned-host-cache.js +3 -3
  321. package/lib/crawler/dns-burned-host-short-circuit-counter.d.ts +2 -2
  322. package/lib/crawler/dns-burned-host-short-circuit-counter.js +2 -2
  323. package/lib/crawler/inject-scope-auth.d.ts +1 -1
  324. package/lib/crawler/inject-scope-auth.js +1 -1
  325. package/lib/crawler/normalize-content-type.d.ts +1 -1
  326. package/lib/crawler/normalize-content-type.js +1 -1
  327. package/lib/crawler/types.d.ts +3 -3
  328. package/lib/crawler-orchestrator.d.ts +9 -0
  329. package/lib/crawler-orchestrator.js +44 -28
  330. package/lib/crawler.d.ts +12 -0
  331. package/lib/crawler.js +21 -0
  332. package/lib/permanent-error-kinds.d.ts +1 -1
  333. package/lib/permanent-error-kinds.js +1 -1
  334. package/lib/types.d.ts +1 -1
  335. package/lib/utils/compute-file-sha256.d.ts +5 -4
  336. package/lib/utils/compute-file-sha256.js +5 -4
  337. package/lib/utils/error/emit-error-with-retry.d.ts +1 -1
  338. package/lib/utils/error/emit-error-with-retry.js +1 -1
  339. package/package.json +10 -10
  340. package/lib/archive/migrate-crawl-errors.d.ts +0 -20
  341. package/lib/archive/migrate-crawl-errors.js +0 -38
  342. package/lib/archive/migrate-html-blob-tables.d.ts +0 -24
  343. package/lib/archive/migrate-html-blob-tables.js +0 -53
  344. package/lib/archive/migrate-inventory-runs.d.ts +0 -29
  345. package/lib/archive/migrate-inventory-runs.js +0 -52
  346. package/lib/archive/migrate-page-errors.d.ts +0 -16
  347. package/lib/archive/migrate-page-errors.js +0 -35
  348. package/lib/archive/migrate-pages-resources-source.d.ts +0 -16
  349. package/lib/archive/migrate-pages-resources-source.js +0 -46
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Collects every `<img>` in a document — its `outerHTML` and its
3
+ * `dom_path` string — in document order.
4
+ *
5
+ * **Self-contained by contract.** This function is passed verbatim to
6
+ * puppeteer's `page.evaluate`, which serialises the function source and
7
+ * executes it inside the browser: it must not reference imports,
8
+ * module-scope bindings, or any closure state. That constraint is also
9
+ * what makes single-sourcing possible — the exact same function body
10
+ * runs in the browser during a live crawl AND in Node (against a jsdom
11
+ * document) in its spec, so the dom-path derivation cannot drift between
12
+ * the two runtimes. The spec additionally pins its output against
13
+ * {@link ../archive/populate-entity-tables/derive-dom-path.ts} (the
14
+ * Node-side derivation the migration script uses) element-for-element.
15
+ * @param doc - The document to walk. Defaults to the global `document`,
16
+ * which is how the in-browser `page.evaluate(collectImageDomPaths)`
17
+ * call resolves it; Node callers (specs) pass a jsdom document.
18
+ * @returns Candidates in document order.
19
+ * @example
20
+ * const candidates = await page.evaluate(collectImageDomPaths);
21
+ */
22
+ export function collectImageDomPaths(doc) {
23
+ const target = doc ?? document;
24
+ /**
25
+ * Counts earlier same-tag siblings, returning the 1-based ordinal.
26
+ * @param element - The element whose ordinal is being computed.
27
+ * @param tag - The element's lower-cased tag name.
28
+ * @returns 1-based ordinal among same-tag siblings.
29
+ */
30
+ function computeSiblingOrdinal(element, tag) {
31
+ let count = 1;
32
+ let sibling = element.previousElementSibling;
33
+ while (sibling !== null) {
34
+ if (sibling.tagName.toLowerCase() === tag) {
35
+ count += 1;
36
+ }
37
+ sibling = sibling.previousElementSibling;
38
+ }
39
+ return count;
40
+ }
41
+ /**
42
+ * Derives the slash-joined dom_path for one element.
43
+ * @param element - The element to derive the path for.
44
+ * @returns The dom_path string.
45
+ */
46
+ function deriveDomPath(element) {
47
+ const segments = [];
48
+ let current = element;
49
+ while (current !== null) {
50
+ const tag = current.tagName.toLowerCase();
51
+ if (tag === 'html') {
52
+ segments.unshift('html');
53
+ break;
54
+ }
55
+ segments.unshift(`${tag}[${computeSiblingOrdinal(current, tag)}]`);
56
+ current = current.parentElement;
57
+ }
58
+ return segments.join('/');
59
+ }
60
+ return Array.from(target.querySelectorAll('img'), (img) => ({
61
+ outerHTML: img.outerHTML,
62
+ path: deriveDomPath(img),
63
+ }));
64
+ }
@@ -81,6 +81,25 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
81
81
  start(urls: ExURL[], opts?: {
82
82
  recursive?: boolean;
83
83
  }): void;
84
+ /**
85
+ * Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
86
+ *
87
+ * WHY per-URL browser: Each URL gets its own browser instance to ensure
88
+ * complete isolation (cookies, cache, service workers). The browser is always
89
+ * closed in the `finally` block, even on error.
90
+ *
91
+ * The cascade-guard contract for the puppeteer-fallback success / skipped
92
+ * branches can be exercised via `vi.spyOn(Crawler.prototype,
93
+ * '_launchBrowserAndScrape')` in unit tests. There is no production
94
+ * consumer outside this class.
95
+ * @internal
96
+ * @param url - Target URL to scrape
97
+ * @param update - Callback for progress messages
98
+ * @param isExternal - Whether the URL is external to the crawl scope
99
+ * @param metadataOnly - When true, only extract title metadata
100
+ * @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
101
+ * @returns The scrape result from beholder
102
+ */
84
103
  private _launchBrowserAndScrape;
85
104
  /**
86
105
  * The default maximum number of concurrent scraping processes.
@@ -13,6 +13,7 @@ import { classifyErrorKind } from '../classify-error-kind.js';
13
13
  import { crawlerLog } from '../debug.js';
14
14
  import { buildJsRedirectEdge } from './build-js-redirect-edge.js';
15
15
  import { buildRedirectEvent } from './build-redirect-event.js';
16
+ import { captureImageDomPaths } from './capture-image-dom-paths.js';
16
17
  import { createChangePhaseHandler } from './create-change-phase-handler.js';
17
18
  import { derivePageSource } from './derive-page-source.js';
18
19
  import { detectPaginationPattern } from './detect-pagination-pattern.js';
@@ -469,31 +470,6 @@ class Crawler extends EventEmitter {
469
470
  }
470
471
  }
471
472
  }
472
- /**
473
- * Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
474
- *
475
- * WHY per-URL browser: Each URL gets its own browser instance to ensure
476
- * complete isolation (cookies, cache, service workers). The browser is always
477
- * closed in the `finally` block, even on error.
478
- * @param url - Target URL to scrape
479
- * @param update - Callback for progress messages
480
- * @param isExternal - Whether the URL is external to the crawl scope
481
- * @param metadataOnly - When true, only extract title metadata
482
- * @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
483
- * @returns The scrape result from beholder
484
- */
485
- /**
486
- * @param url
487
- * @param update
488
- * @param isExternal
489
- * @param metadataOnly
490
- * @param headCheckResult
491
- * @internal
492
- * cascade-guard contract for the puppeteer-fallback success / skipped
493
- * branches can be exercised via `vi.spyOn(Crawler.prototype,
494
- * '_launchBrowserAndScrape')` in unit tests. There is no production
495
- * consumer outside this class.
496
- */
497
473
  /**
498
474
  * Resolve the source label of the page being scraped so sub-resources
499
475
  * captured during its render can inherit the correct lineage label
@@ -1185,7 +1161,7 @@ class Crawler extends EventEmitter {
1185
1161
  // - the source is not committed via `setPage`/`updatePage` on this
1186
1162
  // path (the redirect-edge handler in `#runDeal` only calls
1187
1163
  // `linkList.done` + `emit('redirect', ...)` → `Archive.setRedirect`),
1188
- // so `recordRedirect` → `#getIdByUrl` creates a NULL-status
1164
+ // so `recordRedirect` → `resolveContentItemId` creates a NULL-status
1189
1165
  // placeholder row for the source if it did not already exist;
1190
1166
  // - `#linkRedirectSources` then stamps `status = 301
1191
1167
  // statusText='Moved Permanently'` because NULL satisfies its
@@ -1312,6 +1288,25 @@ class Crawler extends EventEmitter {
1312
1288
  },
1313
1289
  });
1314
1290
  }
1291
+ /**
1292
+ * Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
1293
+ *
1294
+ * WHY per-URL browser: Each URL gets its own browser instance to ensure
1295
+ * complete isolation (cookies, cache, service workers). The browser is always
1296
+ * closed in the `finally` block, even on error.
1297
+ *
1298
+ * The cascade-guard contract for the puppeteer-fallback success / skipped
1299
+ * branches can be exercised via `vi.spyOn(Crawler.prototype,
1300
+ * '_launchBrowserAndScrape')` in unit tests. There is no production
1301
+ * consumer outside this class.
1302
+ * @internal
1303
+ * @param url - Target URL to scrape
1304
+ * @param update - Callback for progress messages
1305
+ * @param isExternal - Whether the URL is external to the crawl scope
1306
+ * @param metadataOnly - When true, only extract title metadata
1307
+ * @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
1308
+ * @returns The scrape result from beholder
1309
+ */
1315
1310
  // eslint-disable-next-line no-restricted-syntax -- intentional `private` (vs `#`) so tests can spyOn the prototype to drive the puppeteer-fallback cascade-guard branches without a full browser mock; see JSDoc above.
1316
1311
  async _launchBrowserAndScrape(url, update, isExternal, metadataOnly, headCheckResult) {
1317
1312
  update('Launching browser%dots%');
@@ -1405,6 +1400,25 @@ class Crawler extends EventEmitter {
1405
1400
  retries: this.#options.retry,
1406
1401
  headCheckResult,
1407
1402
  });
1403
+ // Image dom-path capture runs here — after the scrape completed but
1404
+ // while `page` is still alive — because beholder's image metadata
1405
+ // carries each element's `outerHTML` with no positional
1406
+ // information. The captured candidates ride on the page data into
1407
+ // `image_items.dom_path_text_id` resolution at write time; a
1408
+ // capture failure (or a page with no images) falls back to the
1409
+ // synthetic `unknown/<n>` markers, so this stays best-effort.
1410
+ if (result.type === 'success' &&
1411
+ result.pageData &&
1412
+ result.pageData.imageList.length > 0) {
1413
+ const imageDomPaths = await captureImageDomPaths(page);
1414
+ if (imageDomPaths !== undefined) {
1415
+ const withDomPaths = {
1416
+ ...result.pageData,
1417
+ imageDomPaths,
1418
+ };
1419
+ result.pageData = withDomPaths;
1420
+ }
1421
+ }
1408
1422
  update('Closing browser%dots%');
1409
1423
  // JS-redirect rescue capture: when `scrapeStart` catches a
1410
1424
  // `#fetchData` throw internally (e.g. `Page.goto returned null`
@@ -3,15 +3,15 @@ import type { ErrorKind } from '../types.js';
3
3
  * In-memory set of hostnames known to be unreachable due to DNS errors
4
4
  * (e.g. `getaddrinfo ENOTFOUND`).
5
5
  *
6
- * Lives for one crawl session — cleared by {@link clearDnsBurnedHostCache} at
7
- * the same four orchestrator sites as {@link destinationCache}. Hosts are
6
+ * Lives for one crawl session — cleared by `clearDnsBurnedHostCache` at
7
+ * the same four orchestrator sites as `destinationCache`. Hosts are
8
8
  * marked in two ways:
9
9
  *
10
10
  * - **Session learning**: the `onGiveUp` callback of `#sendHeadRequest`
11
11
  * classifies the final retry error and stores `'dns'` when the matcher
12
12
  * fires. The next URL on the same hostname short-circuits before retry.
13
13
  * - **Session preload**: re-open paths (`append` / `inventory` / `retryFailed`
14
- * / `resume`) call {@link Archive.listDnsBurnedHostCandidates} and seed the
14
+ * / `resume`) call `Archive.listDnsBurnedHostCandidates` and seed the
15
15
  * map from `crawl_errors`, so previously-burned hosts cost zero retries on
16
16
  * the next crawl.
17
17
  *
@@ -2,15 +2,15 @@
2
2
  * In-memory set of hostnames known to be unreachable due to DNS errors
3
3
  * (e.g. `getaddrinfo ENOTFOUND`).
4
4
  *
5
- * Lives for one crawl session — cleared by {@link clearDnsBurnedHostCache} at
6
- * the same four orchestrator sites as {@link destinationCache}. Hosts are
5
+ * Lives for one crawl session — cleared by `clearDnsBurnedHostCache` at
6
+ * the same four orchestrator sites as `destinationCache`. Hosts are
7
7
  * marked in two ways:
8
8
  *
9
9
  * - **Session learning**: the `onGiveUp` callback of `#sendHeadRequest`
10
10
  * classifies the final retry error and stores `'dns'` when the matcher
11
11
  * fires. The next URL on the same hostname short-circuits before retry.
12
12
  * - **Session preload**: re-open paths (`append` / `inventory` / `retryFailed`
13
- * / `resume`) call {@link Archive.listDnsBurnedHostCandidates} and seed the
13
+ * / `resume`) call `Archive.listDnsBurnedHostCandidates` and seed the
14
14
  * map from `crawl_errors`, so previously-burned hosts cost zero retries on
15
15
  * the next crawl.
16
16
  *
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Session-scoped counter for how many URL fetches were short-circuited by the
3
- * {@link dnsBurnedHostCache}. The orchestrator reads this at crawl shutdown
3
+ * `dnsBurnedHostCache`. The orchestrator reads this at crawl shutdown
4
4
  * to emit a `[preload] Short-circuited N URL(s)` summary line, then
5
- * {@link clearDnsBurnedHostCache} zeroes it for the next session.
5
+ * `clearDnsBurnedHostCache` zeroes it for the next session.
6
6
  *
7
7
  * Exposed as a mutable object (not a plain `let`) so that the counter remains
8
8
  * a single shared reference across crawler / orchestrator imports — `let`
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Session-scoped counter for how many URL fetches were short-circuited by the
3
- * {@link dnsBurnedHostCache}. The orchestrator reads this at crawl shutdown
3
+ * `dnsBurnedHostCache`. The orchestrator reads this at crawl shutdown
4
4
  * to emit a `[preload] Short-circuited N URL(s)` summary line, then
5
- * {@link clearDnsBurnedHostCache} zeroes it for the next session.
5
+ * `clearDnsBurnedHostCache` zeroes it for the next session.
6
6
  *
7
7
  * Exposed as a mutable object (not a plain `let`) so that the counter remains
8
8
  * a single shared reference across crawler / orchestrator imports — `let`
@@ -3,7 +3,7 @@ import type { ExURL } from '@d-zero/shared/parse-url';
3
3
  * Copy `username` / `password` from a matched scope URL into the target URL.
4
4
  *
5
5
  * The matched scope is supplied by the caller (typically the result of a single
6
- * {@link findScopeEntry} call). This avoids the previous implementation's
6
+ * `findScopeEntry` call). This avoids the previous implementation's
7
7
  * redundant hostname lookup and re-search.
8
8
  *
9
9
  * Mutates the `url` parameter in place. Only non-empty credentials overwrite
@@ -2,7 +2,7 @@
2
2
  * Copy `username` / `password` from a matched scope URL into the target URL.
3
3
  *
4
4
  * The matched scope is supplied by the caller (typically the result of a single
5
- * {@link findScopeEntry} call). This avoids the previous implementation's
5
+ * `findScopeEntry` call). This avoids the previous implementation's
6
6
  * redundant hostname lookup and re-search.
7
7
  *
8
8
  * Mutates the `url` parameter in place. Only non-empty credentials overwrite
@@ -7,7 +7,7 @@
7
7
  * normalization, so `Text/HTML` or `text/html ` can otherwise reach the
8
8
  * database. Storing the canonical (trimmed, lower-cased) form lets the exact
9
9
  * SQL page-ness predicate (`WHERE contentType = 'text/html'`) agree with the
10
- * code-level {@link isHtmlContentType} check, which trims and lower-cases.
10
+ * code-level `isHtmlContentType` check, which trims and lower-cases.
11
11
  * @param contentType - The raw media type, or `null` when unknown.
12
12
  * @returns The trimmed, lower-cased media type, or `null` when unknown/blank.
13
13
  */
@@ -7,7 +7,7 @@
7
7
  * normalization, so `Text/HTML` or `text/html ` can otherwise reach the
8
8
  * database. Storing the canonical (trimmed, lower-cased) form lets the exact
9
9
  * SQL page-ness predicate (`WHERE contentType = 'text/html'`) agree with the
10
- * code-level {@link isHtmlContentType} check, which trims and lower-cases.
10
+ * code-level `isHtmlContentType` check, which trims and lower-cases.
11
11
  * @param contentType - The raw media type, or `null` when unknown.
12
12
  * @returns The trimmed, lower-cased media type, or `null` when unknown/blank.
13
13
  */
@@ -82,7 +82,7 @@ export type BrowserScrapeResult = ScrapeResult & {
82
82
  * exactly that.
83
83
  *
84
84
  * Consumers should also confirm the URL is meaningful via
85
- * {@link deriveJsRedirectTarget} — `about:blank`, identity values,
85
+ * `deriveJsRedirectTarget` — `about:blank`, identity values,
86
86
  * case-only or trailing-slash variants are all filtered there, not
87
87
  * here.
88
88
  */
@@ -188,7 +188,7 @@ export type ResourceLookup = (urls: readonly string[]) => Promise<ResourceLookup
188
188
  * that has not been INSERTed yet) so the caller can fall through to its
189
189
  * default behaviour.
190
190
  *
191
- * Used by {@link Crawler} during sub-resource lineage propagation:
191
+ * Used by `Crawler` during sub-resource lineage propagation:
192
192
  * `#scrapePage` consults this once per page to resolve the parent's
193
193
  * lineage when the in-memory `inventoryMode` is unavailable (i.e. on
194
194
  * `--resume` / `--retry-failed` sessions where inventory state lives only
@@ -250,7 +250,7 @@ export interface CrawlerEventTypes {
250
250
  externalPage: {
251
251
  /** The scraped page data for the external page. */
252
252
  result: PageData;
253
- /** Inventory provenance for new rows — see {@link CrawlerEventTypes.page.source}. */
253
+ /** Inventory provenance for new rows — see `CrawlerEventTypes.page.source`. */
254
254
  source?: PageSource;
255
255
  };
256
256
  /**
@@ -8,6 +8,9 @@ import Archive from './archive/archive.js';
8
8
  * Default list of external URL prefixes excluded from crawling.
9
9
  * Includes social media sharing endpoints that are commonly linked
10
10
  * but provide no useful crawl data.
11
+ * @example
12
+ * // Merged ahead of user-supplied excludeUrls when a crawl starts:
13
+ * const excludeUrls = [...DEFAULT_EXCLUDED_EXTERNAL_URLS, 'https://ads.example.com'];
11
14
  */
12
15
  export declare const DEFAULT_EXCLUDED_EXTERNAL_URLS: string[];
13
16
  /**
@@ -117,6 +120,12 @@ export declare class CrawlerOrchestrator extends EventEmitter<CrawlEvent> {
117
120
  /**
118
121
  * Write the archive to its configured file path.
119
122
  *
123
+ * The crawler's write path inserts directly into the 0.13 entity
124
+ * tables (`content_items` / `page_meta` / `anchor_edges` / …) during
125
+ * `crawling` / `append` / `resume` / `retryFailed` / `inventory`, so by
126
+ * the time `write()` is called those tables are already populated.
127
+ * This method just tars.
128
+ *
120
129
  * Emits `writeFileStart` before writing and `writeFileEnd` after
121
130
  * the write completes successfully.
122
131
  */
@@ -5,6 +5,7 @@ import { sortUrl } from '@d-zero/shared/sort-url';
5
5
  import { TypedAwaitEventEmitter as EventEmitter } from '@d-zero/shared/typed-await-event-emitter';
6
6
  import pkg from '../package.json' with { type: 'json' };
7
7
  import Archive from './archive/archive.js';
8
+ import { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
8
9
  import { clearDestinationCache } from './crawler/clear-destination-cache.js';
9
10
  import { clearDnsBurnedHostCache } from './crawler/clear-dns-burned-host-cache.js';
10
11
  import Crawler from './crawler/crawler.js';
@@ -24,6 +25,9 @@ import { WriteQueue } from './write-queue.js';
24
25
  * Default list of external URL prefixes excluded from crawling.
25
26
  * Includes social media sharing endpoints that are commonly linked
26
27
  * but provide no useful crawl data.
28
+ * @example
29
+ * // Merged ahead of user-supplied excludeUrls when a crawl starts:
30
+ * const excludeUrls = [...DEFAULT_EXCLUDED_EXTERNAL_URLS, 'https://ads.example.com'];
27
31
  */
28
32
  export const DEFAULT_EXCLUDED_EXTERNAL_URLS = [
29
33
  'https://social-plugins.line.me',
@@ -128,8 +132,8 @@ export class CrawlerOrchestrator extends EventEmitter {
128
132
  // back to the DB DEFAULT `'crawled'` and lose their
129
133
  // `'inventory-discovered'` provenance.
130
134
  lookupPageSource: async (url) => this.#archive.getPageSourceByUrl(url),
131
- // Inventory mode is opted into by `CrawlerOrchestrator.inventory`
132
- // (see T3); the default crawl path stays in normal mode so new
135
+ // Inventory mode is opted into by `CrawlerOrchestrator.inventory`;
136
+ // the default crawl path stays in normal mode so new
133
137
  // rows continue to land in pages/resources with the DB DEFAULT
134
138
  // `'crawled'` provenance label.
135
139
  inventoryMode: options?.inventoryMode ?? null,
@@ -258,6 +262,12 @@ export class CrawlerOrchestrator extends EventEmitter {
258
262
  /**
259
263
  * Write the archive to its configured file path.
260
264
  *
265
+ * The crawler's write path inserts directly into the 0.13 entity
266
+ * tables (`content_items` / `page_meta` / `anchor_edges` / …) during
267
+ * `crawling` / `append` / `resume` / `retryFailed` / `inventory`, so by
268
+ * the time `write()` is called those tables are already populated.
269
+ * This method just tars.
270
+ *
261
271
  * Emits `writeFileStart` before writing and `writeFileEnd` after
262
272
  * the write completes successfully.
263
273
  */
@@ -299,7 +309,14 @@ export class CrawlerOrchestrator extends EventEmitter {
299
309
  // Each positional URL is both a starting point and a scope entry.
300
310
  const rootHrefs = list.map((u) => u.withoutHash);
301
311
  await archive.setConfig({
302
- version: pkg.version,
312
+ // `version` is the archive-format version (see
313
+ // `assertCompatibleVersion`), NOT the npm package version. Decoupled
314
+ // because format-breaking changes and code-release cadence are
315
+ // different concerns — a patch release must not silently bump the
316
+ // format version and reject older archives, and a dev build of an
317
+ // unreleased breaking change must be able to produce archives the
318
+ // same build can read back.
319
+ version: REQUIRED_FORMAT_VERSION,
303
320
  name: fileName,
304
321
  baseUrl: rootHrefs[0],
305
322
  roots: rootHrefs,
@@ -520,13 +537,14 @@ export class CrawlerOrchestrator extends EventEmitter {
520
537
  // anchor-referenced, `scraped=0` rows. Predicted-discard leaks
521
538
  // and external anomalies are filtered out at the reader, so a
522
539
  // non-empty pending here means the previous session genuinely
523
- // stopped with interrupted in-scope work. The original hard
524
- // rejection blocked legitimate inventory runs in practice
525
- // because leak rows polluted the count; with the strict
526
- // reader those false positives are gone, so a warning is
540
+ // stopped with interrupted in-scope work. A hard rejection is
541
+ // still not warranted (with a looser reader it would block
542
+ // legitimate inventory runs whenever leak rows polluted the
543
+ // count), so a warning is
527
544
  // enough — the inventory pass continues and the crawled-wins
528
545
  // source priority keeps stale labels stable even if some of
529
546
  // the strict-pending rows happen to land on inventory seeds.
547
+ // eslint-disable-next-line no-console -- operator-facing warning, must be visible regardless of DEBUG filters
530
548
  console.warn(`inventory: archive has ${pending.length} pending URLs from a previous crawl. Proceeding — crawled-wins priority keeps their labels stable. Consider \`--resume\` first if you want the prior work finalized.`);
531
549
  }
532
550
  // Parse + scope-classify the candidate URLs. sortUrl drops
@@ -556,7 +574,7 @@ export class CrawlerOrchestrator extends EventEmitter {
556
574
  }
557
575
  // Drop URLs that are already represented in the archive (either
558
576
  // as pages or resources). Comparison key is `withoutHashAndAuth`
559
- // to mirror what `#getIdByUrl` / `insertResource` actually store.
577
+ // to mirror what `resolveContentItemId` / `insertResource` actually store.
560
578
  // Two independent reads — Promise.all halves the wait on large
561
579
  // archives where each `WHERE url IN (?)` chunk costs real I/O.
562
580
  const candidateUrls = inScope.map((u) => u.withoutHashAndAuth);
@@ -656,8 +674,8 @@ export class CrawlerOrchestrator extends EventEmitter {
656
674
  htmlSeeds.push(url);
657
675
  }
658
676
  // Bulk-record non-HTML novel URLs in `resources` as
659
- // `source='inventory-seed'` placeholders. The previous
660
- // per-URL `await setResources(...)` loop spent minutes
677
+ // `source='inventory-seed'` placeholders. A
678
+ // per-URL `await setResources(...)` loop would spend minutes
661
679
  // inside the `.bak`-protected window on large inventory
662
680
  // lists; the chunked bulk path collapses N round-trips
663
681
  // to N/500.
@@ -665,7 +683,7 @@ export class CrawlerOrchestrator extends EventEmitter {
665
683
  // Pre-insert HTML seeds as `scraped = 0`,
666
684
  // `source = 'inventory-seed'` placeholders *before* the
667
685
  // scrape phase, so a Ctrl+C between here and `setPage`
668
- // no longer loses the URL. The strict-pending set picks
686
+ // cannot lose the URL. The strict-pending set picks
669
687
  // these rows up on the next `--resume` via the
670
688
  // `OR p.source != 'crawled'` clause.
671
689
  await archive.insertInventorySeeds(htmlSeeds);
@@ -674,9 +692,9 @@ export class CrawlerOrchestrator extends EventEmitter {
674
692
  // hiccup or transient lock on the INSERT aborts the ingestion
675
693
  // and the `.bak` restore wipes the pre-inserted seeds too,
676
694
  // so "either the whole run took or none of it did" holds at
677
- // the ingestion boundary. Past behaviour swallowed the
678
- // failure post-scrape; the new boundary makes restore safe
679
- // and useful, so the swallow is gone (see
695
+ // the ingestion boundary. Audit failures are deliberately
696
+ // NOT swallowed — inside the `.bak` window a restore is
697
+ // safe and useful (see
680
698
  // {@link CrawlerOrchestrator.#writeInventoryRunRow}).
681
699
  await CrawlerOrchestrator.#writeInventoryRunRow(archive, {
682
700
  inventoryUrlsCount: inventoryUrls.length,
@@ -962,13 +980,12 @@ export class CrawlerOrchestrator extends EventEmitter {
962
980
  * static helper because the audit-row shape (timestamp stamping + label
963
981
  * auto-gen + the privacy-driven path elision documented below) is a
964
982
  * cohesive concern that benefits from staying outside the long
965
- * `inventory()` body even though only one caller remains after the
966
- * ingestion-phase consolidation.
983
+ * `inventory()` body even though it has a single caller.
967
984
  *
968
985
  * `ran_at` is stamped now (ingestion-completion timestamp; the scrape
969
986
  * phase that may follow is treated as separate). `list_label` is
970
- * auto-generated from `ran_at` when the CLI did not pass one — Phase 1
971
- * has no `--label` flag, so this is always the auto form.
987
+ * auto-generated from `ran_at` when the CLI did not pass one — there is
988
+ * no `--label` flag, so this is always the auto form.
972
989
  * `source_file_sha256` arrives pre-computed via
973
990
  * `aggregates.sourceFileSha256` (the CLI's `inventoryCrawl` ran
974
991
  * `computeFileSha256` against the input txt before the orchestrator
@@ -976,17 +993,17 @@ export class CrawlerOrchestrator extends EventEmitter {
976
993
  * the absolute path — see {@link InventoryRunAggregates} for the
977
994
  * privacy rationale.
978
995
  *
979
- * **Audit-write failures abort the ingestion phase.** The earlier
980
- * implementation swallowed them because the audit was the last write
981
- * after* the scrape, so re-throwing would have wiped a completed crawl;
982
- * with audit now lifted into the `.bak`-protected ingestion phase the
996
+ * **Audit-write failures abort the ingestion phase.** Swallowing them
997
+ * would only be justified if the audit were the last write after the
998
+ * scrape (re-throwing there would wipe a completed crawl); inside the
999
+ * `.bak`-protected ingestion phase the
983
1000
  * trade-off flips. A failed audit row is restorable: the outer catch
984
1001
  * copies `.bak` back over the archive and the operator reruns the
985
1002
  * (short) ingestion from scratch. That keeps `inventory_runs` honest
986
1003
  * (no "ran but unrecorded" rows) at the cost of one rerun.
987
1004
  *
988
- * Forward-compat: when Phase 2 introduces an explicit `--label` flag,
989
- * thread `labelOverride` through {@link inventory} into the `aggregates`
1005
+ * Forward-compat: if an explicit `--label` flag is ever added, thread
1006
+ * `labelOverride` through {@link inventory} into the `aggregates`
990
1007
  * shape so the auto-name can be overridden.
991
1008
  * @param archive - The opened archive to write the audit row into.
992
1009
  * @param aggregates - The counts captured during the inventory pass; see {@link InventoryRunAggregates}.
@@ -1005,10 +1022,9 @@ export class CrawlerOrchestrator extends EventEmitter {
1005
1022
  }
1006
1023
  /**
1007
1024
  * Tears down session-scoped crawler caches and prints a short-circuit
1008
- * summary if any URL fetches were skipped. Invoked at the four
1009
- * crawl-session boundaries (`crawling` / `append` / `inventory` /
1010
- * `retryFailed` / `resume`) where the previous `clearDestinationCache`
1011
- * call already lived.
1025
+ * summary if any URL fetches were skipped. Invoked at every
1026
+ * crawl-session boundary (`crawling` / `append` / `inventory` /
1027
+ * `retryFailed` / `resume`).
1012
1028
  */
1013
1029
  static #finalizeCrawlSession() {
1014
1030
  const skipped = dnsBurnedHostShortCircuitCounter.count;
package/lib/crawler.d.ts CHANGED
@@ -16,6 +16,7 @@ export { default as ArchiveResource } from './archive/resource.js';
16
16
  export * from './archive/types.js';
17
17
  export { default as Archive } from './archive/archive.js';
18
18
  export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
19
+ export { acquireArchiveLock, ArchiveLockError } from './archive/archive-lock.js';
19
20
  export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
20
21
  export type { ArchiveLockHolder } from './archive/peek-archive-lock.js';
21
22
  export type { FlatPageMetaColumns, JsonLdRow, JsonLdRowForInsert, TagRow, TagRowForInsert, JsonLdSummary, TagsSummary, TagInventoryEntry, PageDenormalizedColumns, } from './archive/meta/types.js';
@@ -26,3 +27,14 @@ export * from './types.js';
26
27
  export * from './crawler/types.js';
27
28
  export { classifyErrorKind } from './classify-error-kind.js';
28
29
  export { computeFileSha256 } from './utils/compute-file-sha256.js';
30
+ export { populateEntityTables } from './archive/populate-entity-tables/populate-entities.js';
31
+ export type { PageDomPathResolver } from './archive/populate-entity-tables/populate-image-items.js';
32
+ export { populateRefTables } from './archive/populate-ref-tables/populate-refs.js';
33
+ export { populateContentTypeRefs } from './archive/populate-ref-tables/populate-content-type-refs.js';
34
+ export { populateUrlRefs } from './archive/populate-ref-tables/populate-url-refs.js';
35
+ export { populateTextRefs } from './archive/populate-ref-tables/populate-text-refs.js';
36
+ export { populateJsonRefs } from './archive/populate-ref-tables/populate-json-refs.js';
37
+ export { populateBlobRefs } from './archive/populate-ref-tables/populate-blob-refs.js';
38
+ export { populateHeaderTables } from './archive/populate-ref-tables/populate-header-tables.js';
39
+ export { loadResponseHeadersBySetIds } from './archive/db-ops/_shared/load-response-headers-by-set-ids.js';
40
+ export { decodeJsonRef } from './archive/db-ops/_shared/decode-json-ref.js';
package/lib/crawler.js CHANGED
@@ -17,6 +17,7 @@ export { default as ArchiveResource } from './archive/resource.js';
17
17
  export * from './archive/types.js';
18
18
  export { default as Archive } from './archive/archive.js';
19
19
  export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
20
+ export { acquireArchiveLock, ArchiveLockError } from './archive/archive-lock.js';
20
21
  export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
21
22
  export { IncompatibleArchiveError } from './archive/meta/types.js';
22
23
  export { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
@@ -26,3 +27,23 @@ export * from './types.js';
26
27
  export * from './crawler/types.js';
27
28
  export { classifyErrorKind } from './classify-error-kind.js';
28
29
  export { computeFileSha256 } from './utils/compute-file-sha256.js';
30
+ // 0.13 ref-table population (issue #191, epic #103). Exposed as the
31
+ // public seam that the migration script (`scripts/migrate-to-0.13.mjs`)
32
+ // drives against an already-connected archive.
33
+ // The individual sub-steps are also exported so the migration script can
34
+ // resume mid-way if the caller decides to split the transaction.
35
+ export { populateEntityTables } from './archive/populate-entity-tables/populate-entities.js';
36
+ export { populateRefTables } from './archive/populate-ref-tables/populate-refs.js';
37
+ export { populateContentTypeRefs } from './archive/populate-ref-tables/populate-content-type-refs.js';
38
+ export { populateUrlRefs } from './archive/populate-ref-tables/populate-url-refs.js';
39
+ export { populateTextRefs } from './archive/populate-ref-tables/populate-text-refs.js';
40
+ export { populateJsonRefs } from './archive/populate-ref-tables/populate-json-refs.js';
41
+ export { populateBlobRefs } from './archive/populate-ref-tables/populate-blob-refs.js';
42
+ export { populateHeaderTables } from './archive/populate-ref-tables/populate-header-tables.js';
43
+ // 0.13 read-side reconstruction primitives. Exported so downstream
44
+ // readers (`@nitpicker/query`'s page-detail view) reconstruct
45
+ // `responseHeaders` / json_refs payloads with the exact same merge and
46
+ // decode semantics as the crawler's own read paths — one implementation,
47
+ // no cross-package drift.
48
+ export { loadResponseHeadersBySetIds } from './archive/db-ops/_shared/load-response-headers-by-set-ids.js';
49
+ export { decodeJsonRef } from './archive/db-ops/_shared/decode-json-ref.js';
@@ -4,7 +4,7 @@ import type { ErrorKind } from './types.js';
4
4
  * (without changing the network, the certificate, the destination host, or the
5
5
  * browser's block-list state) will almost certainly produce the same failure.
6
6
  *
7
- * Used by {@link resetFailedPages} to exclude pages whose latest recorded error
7
+ * Used by `resetFailedPages` to exclude pages whose latest recorded error
8
8
  * falls in this set, so `--retry-failed` actually converges: without the
9
9
  * exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
10
10
  * `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
@@ -3,7 +3,7 @@
3
3
  * (without changing the network, the certificate, the destination host, or the
4
4
  * browser's block-list state) will almost certainly produce the same failure.
5
5
  *
6
- * Used by {@link resetFailedPages} to exclude pages whose latest recorded error
6
+ * Used by `resetFailedPages` to exclude pages whose latest recorded error
7
7
  * falls in this set, so `--retry-failed` actually converges: without the
8
8
  * exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
9
9
  * `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
package/lib/types.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { CrawlerError, PageData } from './utils/types/types.js';
3
3
  * Aggregate counts captured during a `--inventory` invocation, forwarded to
4
4
  * `#writeInventoryRunRow` so the audit log row is consistent between the
5
5
  * HTML-seed branch and the non-HTML-only branch of
6
- * {@link CrawlerOrchestrator.inventory}.
6
+ * `CrawlerOrchestrator.inventory`.
7
7
  *
8
8
  * Spelled out here (not inlined at the call site) so a new field added to
9
9
  * the audit row has a single edit point and so each field's semantics are
@@ -2,10 +2,11 @@
2
2
  * Compute the SHA-256 digest of a file's bytes, streaming so memory stays
3
3
  * O(1) regardless of file size.
4
4
  *
5
- * Used by {@link CrawlerOrchestrator.inventory} to fingerprint the source
6
- * URL list `.txt` and store the digest on the `inventory_runs` row.
7
- * Phase 3 (`--refresh`) will key dedupe on this column; Phase 1 just
8
- * records it for operator audit.
5
+ * Used by `CrawlerOrchestrator.inventory` to fingerprint the source
6
+ * URL list `.txt` and store the digest on the `inventory_runs` row. The
7
+ * digest is the content-identity key for "was this exact list applied
8
+ * before" recorded for operator audit; nothing dedupes on it at write
9
+ * time.
9
10
  *
10
11
  * Returns `null` instead of throwing when the file cannot be read (e.g.
11
12
  * vanished mid-run, permissions issue) so the inventory run's audit row