@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,8 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Retrieves the crawl session name from the `info` table.
4
+ * @param knex - Knex query builder connected to the archive DB.
5
+ * @returns The name string.
6
+ * @throws {Error} If no name is found in the database.
7
+ */
8
+ export declare function getName(knex: Knex): Promise<string>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Retrieves the crawl session name from the `info` table.
3
+ * @param knex - Knex query builder connected to the archive DB.
4
+ * @returns The name string.
5
+ * @throws {Error} If no name is found in the database.
6
+ */
7
+ export async function getName(knex) {
8
+ const selected = await knex.select('name').from('info');
9
+ if (!selected[0]) {
10
+ throw new Error('No name');
11
+ }
12
+ const [{ name }] = selected;
13
+ return name;
14
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Columns of the `info` table that `setConfig` / `updateConfig` are allowed to
3
+ * write. Any key outside this set is silently dropped so callers can splat a
4
+ * wider runtime config (with extras like `cwd`) without hitting "no such
5
+ * column" at the SQL layer.
6
+ */
7
+ export declare const INFO_COLUMN_ALLOWLIST: ReadonlySet<string>;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Columns of the `info` table that `setConfig` / `updateConfig` are allowed to
3
+ * write. Any key outside this set is silently dropped so callers can splat a
4
+ * wider runtime config (with extras like `cwd`) without hitting "no such
5
+ * column" at the SQL layer.
6
+ */
7
+ export const INFO_COLUMN_ALLOWLIST = new Set([
8
+ 'version',
9
+ 'name',
10
+ 'baseUrl',
11
+ 'roots',
12
+ 'recursive',
13
+ 'interval',
14
+ 'image',
15
+ 'fetchExternal',
16
+ 'parallels',
17
+ 'excludes',
18
+ 'excludeKeywords',
19
+ 'excludeUrls',
20
+ 'maxExcludedDepth',
21
+ 'retry',
22
+ 'fromList',
23
+ 'disableQueries',
24
+ 'userAgent',
25
+ 'ignoreRobots',
26
+ ]);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Subset of {@link ./info-column-allowlist.ts} that is stored as a JSON-encoded
3
+ * string and therefore needs `JSON.stringify` on write.
4
+ */
5
+ export declare const INFO_JSON_COLUMNS: ReadonlySet<string>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Subset of {@link ./info-column-allowlist.ts} that is stored as a JSON-encoded
3
+ * string and therefore needs `JSON.stringify` on write.
4
+ */
5
+ export const INFO_JSON_COLUMNS = new Set([
6
+ 'roots',
7
+ 'excludes',
8
+ 'excludeKeywords',
9
+ 'excludeUrls',
10
+ ]);
@@ -0,0 +1,12 @@
1
+ import type { Config } from '../../types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Stores the crawl configuration in the `info` table.
5
+ * Only fields in {@link ./info-column-allowlist.ts} are forwarded — any extra
6
+ * runtime-only field on the input is silently dropped so callers can splat
7
+ * a wider config object without producing SQL errors. JSON-array fields
8
+ * are serialized via `JSON.stringify`.
9
+ * @param knex - Knex query builder connected to the archive DB.
10
+ * @param config - The {@link Config} object to store.
11
+ */
12
+ export declare function setConfig(knex: Knex, config: Config): Promise<number[]>;
@@ -0,0 +1,21 @@
1
+ import { INFO_COLUMN_ALLOWLIST } from './info-column-allowlist.js';
2
+ import { INFO_JSON_COLUMNS } from './info-json-columns.js';
3
+ /**
4
+ * Stores the crawl configuration in the `info` table.
5
+ * Only fields in {@link ./info-column-allowlist.ts} are forwarded — any extra
6
+ * runtime-only field on the input is silently dropped so callers can splat
7
+ * a wider config object without producing SQL errors. JSON-array fields
8
+ * are serialized via `JSON.stringify`.
9
+ * @param knex - Knex query builder connected to the archive DB.
10
+ * @param config - The {@link Config} object to store.
11
+ */
12
+ export async function setConfig(knex, config) {
13
+ const payload = {};
14
+ for (const [key, value] of Object.entries(config)) {
15
+ if (!INFO_COLUMN_ALLOWLIST.has(key)) {
16
+ continue;
17
+ }
18
+ payload[key] = INFO_JSON_COLUMNS.has(key) ? JSON.stringify(value) : value;
19
+ }
20
+ return knex.from('info').insert(payload);
21
+ }
@@ -0,0 +1,17 @@
1
+ import type { Config } from '../../types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Update the single row in the `info` table with a partial config patch.
5
+ *
6
+ * Used by the append flow to extend `roots` (and any other tweakable
7
+ * field) without replacing the entire row. JSON-array fields are serialized on
8
+ * the fly; primitive fields are written verbatim. Unspecified fields stay as-is.
9
+ *
10
+ * Unknown keys (anything outside the allow-list of `info`-table columns) are
11
+ * silently dropped instead of being passed to SQL, so callers that splat a
12
+ * wider runtime config (e.g. `CrawlConfig` with `cwd` / `executablePath`)
13
+ * cannot accidentally trigger a "no such column" SQL error.
14
+ * @param knex - Knex query builder connected to the archive DB.
15
+ * @param patch - Partial {@link Config} fields to overwrite. `undefined` values are skipped.
16
+ */
17
+ export declare function updateConfig(knex: Knex, patch: Partial<Config>): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { INFO_COLUMN_ALLOWLIST } from './info-column-allowlist.js';
2
+ import { INFO_JSON_COLUMNS } from './info-json-columns.js';
3
+ /**
4
+ * Update the single row in the `info` table with a partial config patch.
5
+ *
6
+ * Used by the append flow to extend `roots` (and any other tweakable
7
+ * field) without replacing the entire row. JSON-array fields are serialized on
8
+ * the fly; primitive fields are written verbatim. Unspecified fields stay as-is.
9
+ *
10
+ * Unknown keys (anything outside the allow-list of `info`-table columns) are
11
+ * silently dropped instead of being passed to SQL, so callers that splat a
12
+ * wider runtime config (e.g. `CrawlConfig` with `cwd` / `executablePath`)
13
+ * cannot accidentally trigger a "no such column" SQL error.
14
+ * @param knex - Knex query builder connected to the archive DB.
15
+ * @param patch - Partial {@link Config} fields to overwrite. `undefined` values are skipped.
16
+ */
17
+ export async function updateConfig(knex, patch) {
18
+ const payload = {};
19
+ for (const [key, value] of Object.entries(patch)) {
20
+ if (value === undefined) {
21
+ continue;
22
+ }
23
+ if (!INFO_COLUMN_ALLOWLIST.has(key)) {
24
+ continue;
25
+ }
26
+ if (INFO_JSON_COLUMNS.has(key)) {
27
+ payload[key] = JSON.stringify(value);
28
+ continue;
29
+ }
30
+ payload[key] = value;
31
+ }
32
+ if (Object.keys(payload).length === 0) {
33
+ return;
34
+ }
35
+ await knex.from('info').update(payload);
36
+ }
@@ -0,0 +1,15 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Records a crawler-level (`error` channel) failure into `crawl_errors`.
4
+ *
5
+ * Unlike `insertPageError` this is not tied to a scraped page: `url`
6
+ * may be an external link that never became a page row, or `null` for a
7
+ * process-level error. The cause is intentionally not stored — it is derived
8
+ * on read so that older archives (which only have `error.log`) and freshly
9
+ * captured rows classify identically.
10
+ * @param knex - Knex query builder connected to the archive DB.
11
+ * @param url - The URL the error is about, or `null` for a process-level error.
12
+ * @param message - The error message (one line is enough for classification).
13
+ * @param isExternal - Whether the URL is external to the crawl scope.
14
+ */
15
+ export declare function insertCrawlError(knex: Knex, url: string | null, message: string, isExternal?: boolean): Promise<void>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Records a crawler-level (`error` channel) failure into `crawl_errors`.
3
+ *
4
+ * Unlike `insertPageError` this is not tied to a scraped page: `url`
5
+ * may be an external link that never became a page row, or `null` for a
6
+ * process-level error. The cause is intentionally not stored — it is derived
7
+ * on read so that older archives (which only have `error.log`) and freshly
8
+ * captured rows classify identically.
9
+ * @param knex - Knex query builder connected to the archive DB.
10
+ * @param url - The URL the error is about, or `null` for a process-level error.
11
+ * @param message - The error message (one line is enough for classification).
12
+ * @param isExternal - Whether the URL is external to the crawl scope.
13
+ */
14
+ export async function insertCrawlError(knex, url, message, isExternal = false) {
15
+ await knex('crawl_errors').insert({
16
+ url,
17
+ isExternal: isExternal ? 1 : 0,
18
+ message,
19
+ createdAt: Date.now(),
20
+ });
21
+ }
@@ -0,0 +1,21 @@
1
+ import type { WriteRefCaches } from '../_shared/types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Records a partial scrape failure against the page identified by `url`.
5
+ *
6
+ * The page row is resolved (or inserted as a stub) via
7
+ * {@link resolveContentItemId} so the error can be recorded even before
8
+ * `setPage` has run — useful when the failure fires during scraping
9
+ * (e.g. mid-`scrapeStart`) and the orchestrator enqueues this write
10
+ * before the success write for the same URL.
11
+ *
12
+ * A single page can have multiple `page_errors` rows (e.g. both
13
+ * `desktop-compact` and `mobile-small` viewports failing).
14
+ * @param knex - Knex query builder connected to the archive DB.
15
+ * @param caches - The connection's write-side id caches.
16
+ * @param url - URL of the page being scraped.
17
+ * @param phase - Scrape phase name (typically `'retryExhausted'`).
18
+ * @param message - Human-readable failure message.
19
+ * @param isExternal - Whether the URL is external. Defaults to `false`.
20
+ */
21
+ export declare function insertPageError(knex: Knex, caches: WriteRefCaches, url: string, phase: string, message: string, isExternal?: boolean): Promise<void>;
@@ -0,0 +1,28 @@
1
+ import { resolveContentItemId } from '../_shared/resolve-content-item-id.js';
2
+ /**
3
+ * Records a partial scrape failure against the page identified by `url`.
4
+ *
5
+ * The page row is resolved (or inserted as a stub) via
6
+ * {@link resolveContentItemId} so the error can be recorded even before
7
+ * `setPage` has run — useful when the failure fires during scraping
8
+ * (e.g. mid-`scrapeStart`) and the orchestrator enqueues this write
9
+ * before the success write for the same URL.
10
+ *
11
+ * A single page can have multiple `page_errors` rows (e.g. both
12
+ * `desktop-compact` and `mobile-small` viewports failing).
13
+ * @param knex - Knex query builder connected to the archive DB.
14
+ * @param caches - The connection's write-side id caches.
15
+ * @param url - URL of the page being scraped.
16
+ * @param phase - Scrape phase name (typically `'retryExhausted'`).
17
+ * @param message - Human-readable failure message.
18
+ * @param isExternal - Whether the URL is external. Defaults to `false`.
19
+ */
20
+ export async function insertPageError(knex, caches, url, phase, message, isExternal = false) {
21
+ const pageId = await resolveContentItemId(knex, caches, url, isExternal ? 1 : 0);
22
+ await knex('page_errors').insert({
23
+ pageId,
24
+ phase,
25
+ message,
26
+ createdAt: Date.now(),
27
+ });
28
+ }
@@ -0,0 +1,22 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Hostnames whose `crawl_errors` history is consistently DNS failures and
4
+ * for which no recent 2xx-3xx page or resource is recorded — i.e. hosts
5
+ * the previous crawl already proved unreachable. Returned in lower-cased
6
+ * form. Used by `CrawlerOrchestrator.#preloadDnsBurnedHostCache` so the
7
+ * next session short-circuits HEAD pre-flight on these hosts.
8
+ *
9
+ * Implementation: a coarse `LIKE` filter over `crawl_errors.message`
10
+ * narrows the row set, then `classifyErrorKind` confirms `'dns'` in JS
11
+ * (the regex is the single truth source — DB-side filters never narrow
12
+ * it). Exclusion bags are built from a single `pages` and a single
13
+ * `resources` scan: any host with a 2xx-3xx page, a 2xx-3xx resource, or
14
+ * a `pages.lastCrawledAt` newer than its latest DNS error is dropped
15
+ * (the host probably recovered between the failure and the last crawl).
16
+ *
17
+ * Returns `[]` on legacy archives that pre-date the `crawl_errors`
18
+ * table — the `hasTable` guard keeps the call non-destructive.
19
+ * @param knex - Knex query builder connected to the archive DB.
20
+ * @returns Lower-cased hostnames safe to short-circuit.
21
+ */
22
+ export declare function listDnsBurnedHostCandidates(knex: Knex): Promise<string[]>;
@@ -0,0 +1,141 @@
1
+ import { classifyErrorKind } from '../../../classify-error-kind.js';
2
+ /**
3
+ * Hostnames whose `crawl_errors` history is consistently DNS failures and
4
+ * for which no recent 2xx-3xx page or resource is recorded — i.e. hosts
5
+ * the previous crawl already proved unreachable. Returned in lower-cased
6
+ * form. Used by `CrawlerOrchestrator.#preloadDnsBurnedHostCache` so the
7
+ * next session short-circuits HEAD pre-flight on these hosts.
8
+ *
9
+ * Implementation: a coarse `LIKE` filter over `crawl_errors.message`
10
+ * narrows the row set, then `classifyErrorKind` confirms `'dns'` in JS
11
+ * (the regex is the single truth source — DB-side filters never narrow
12
+ * it). Exclusion bags are built from a single `pages` and a single
13
+ * `resources` scan: any host with a 2xx-3xx page, a 2xx-3xx resource, or
14
+ * a `pages.lastCrawledAt` newer than its latest DNS error is dropped
15
+ * (the host probably recovered between the failure and the last crawl).
16
+ *
17
+ * Returns `[]` on legacy archives that pre-date the `crawl_errors`
18
+ * table — the `hasTable` guard keeps the call non-destructive.
19
+ * @param knex - Knex query builder connected to the archive DB.
20
+ * @returns Lower-cased hostnames safe to short-circuit.
21
+ */
22
+ export async function listDnsBurnedHostCandidates(knex) {
23
+ const hasCrawlErrors = await knex.schema.hasTable('crawl_errors');
24
+ if (!hasCrawlErrors) {
25
+ return [];
26
+ }
27
+ // Coarse SQL filter: cheap LIKE OR-chain over `message`. The dns regex
28
+ // truth source lives in `classifyErrorKind`, so we only need to feed it
29
+ // rows that COULD match a DNS token. Each LIKE is anchored on a known
30
+ // substring of the regex so future additions to the regex (without
31
+ // matching new SQL terms) widen the JS-side filter only — never narrow it.
32
+ //
33
+ // `%EAI_AGAIN%` is deliberately NOT in the SQL filter: it now classifies
34
+ // as `dns-transient` (local resolver hiccup), not `dns`, so it must not
35
+ // reach this candidate set. The `%getaddrinfo%` term still pulls
36
+ // `getaddrinfo EAI_AGAIN ...` rows but the JS-side `classifyErrorKind`
37
+ // check (first-match-wins) routes them to `dns-transient` and they
38
+ // silently drop out — keeping the cache focused on real NXDOMAIN.
39
+ const dnsLikeRows = (await knex('crawl_errors')
40
+ .select('url', 'message', 'createdAt')
41
+ .whereNotNull('url')
42
+ .where((qb) => {
43
+ qb.where('message', 'like', '%ENOTFOUND%')
44
+ .orWhere('message', 'like', '%getaddrinfo%')
45
+ .orWhere('message', 'like', '%ERR_NAME_NOT_RESOLVED%')
46
+ .orWhere('message', 'like', '%ERR_NAME_RESOLUTION_FAILED%');
47
+ }));
48
+ if (dnsLikeRows.length === 0) {
49
+ return [];
50
+ }
51
+ // Map<hostname, latestErrorCreatedAt> for hosts whose error message
52
+ // confidently classifies as DNS (LIKE matched but classifyErrorKind says
53
+ // e.g. `unknown` → drop).
54
+ const candidateLatestErrorAt = new Map();
55
+ for (const row of dnsLikeRows) {
56
+ if (classifyErrorKind(row.message) !== 'dns') {
57
+ continue;
58
+ }
59
+ let host;
60
+ try {
61
+ host = new URL(row.url).hostname.toLowerCase();
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ if (!host) {
67
+ continue;
68
+ }
69
+ const createdAt = typeof row.createdAt === 'number' ? row.createdAt : 0;
70
+ const previous = candidateLatestErrorAt.get(host) ?? 0;
71
+ if (createdAt > previous) {
72
+ candidateLatestErrorAt.set(host, createdAt);
73
+ }
74
+ }
75
+ if (candidateLatestErrorAt.size === 0) {
76
+ return [];
77
+ }
78
+ // Exclusion-bag #1: pages with a 2xx-3xx status anywhere on the host.
79
+ // Tracking the latest `last_crawled_at` per host lets us additionally
80
+ // drop hosts whose last successful contact post-dates the most recent
81
+ // DNS error (the host probably came back after a transient outage).
82
+ const pageOkRows = (await knex('content_items')
83
+ .join('url_refs', 'content_items.url_id', 'url_refs.id')
84
+ .select('url_refs.url as url', 'content_items.last_crawled_at as lastCrawledAt')
85
+ .whereBetween('content_items.status', [200, 399]));
86
+ const pageOkHosts = new Set();
87
+ const latestPageOkAt = new Map();
88
+ for (const row of pageOkRows) {
89
+ let host;
90
+ try {
91
+ host = new URL(row.url).hostname.toLowerCase();
92
+ }
93
+ catch {
94
+ continue;
95
+ }
96
+ pageOkHosts.add(host);
97
+ if (typeof row.lastCrawledAt === 'number') {
98
+ const previous = latestPageOkAt.get(host) ?? 0;
99
+ if (row.lastCrawledAt > previous) {
100
+ latestPageOkAt.set(host, row.lastCrawledAt);
101
+ }
102
+ }
103
+ }
104
+ // Exclusion-bag #2: non-HTML resources with a 2xx-3xx status. resources
105
+ // have no timestamp column so this is presence-only.
106
+ const resourceOkRows = (await knex('resource_items')
107
+ .join('url_refs', 'resource_items.url_id', 'url_refs.id')
108
+ .select('url_refs.url as url')
109
+ .whereBetween('resource_items.status', [200, 399]));
110
+ const resourceOkHosts = new Set();
111
+ for (const row of resourceOkRows) {
112
+ let host;
113
+ try {
114
+ host = new URL(row.url).hostname.toLowerCase();
115
+ }
116
+ catch {
117
+ continue;
118
+ }
119
+ resourceOkHosts.add(host);
120
+ }
121
+ // A candidate host is burned only if neither pages nor resources hold a
122
+ // 2xx-3xx for it, AND its latest 2xx page (if any) is not newer than
123
+ // the latest DNS error. The third check guards against re-burning a
124
+ // host that recovered between the last DNS failure and the most recent
125
+ // crawl.
126
+ const burned = [];
127
+ for (const [host, latestErrorAt] of candidateLatestErrorAt) {
128
+ if (pageOkHosts.has(host)) {
129
+ continue;
130
+ }
131
+ if (resourceOkHosts.has(host)) {
132
+ continue;
133
+ }
134
+ const latestOkAt = latestPageOkAt.get(host);
135
+ if (typeof latestOkAt === 'number' && latestOkAt > latestErrorAt) {
136
+ continue;
137
+ }
138
+ burned.push(host);
139
+ }
140
+ return burned;
141
+ }
@@ -0,0 +1,18 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Reads the HTML snapshot stored as a zstd-compressed BLOB for the given page.
4
+ *
5
+ * Joins `page_html_ref` → `page_html_blobs` and decompresses inline. Returns
6
+ * `null` when the page has no stored body (a non-HTML resource, a redirect
7
+ * source, a degraded render). Read works identically on read-only / stub
8
+ * connections — the special-cased "do we have a loose dir vs zip?" branching
9
+ * the previous file-backed layout required is gone.
10
+ *
11
+ * Tables `page_html_ref` and `page_html_blobs` are created by `initSchema`.
12
+ * Older `.nitpicker` archives that predate this migration must be passed
13
+ * through `scripts/migrate-to-0.10.mjs` before they can be read.
14
+ * @param knex - Knex query builder connected to the archive DB.
15
+ * @param pageId - The database ID of the page.
16
+ * @returns The decompressed HTML string, or `null` if no snapshot is stored.
17
+ */
18
+ export declare function getHtmlOfPageById(knex: Knex, pageId: number): Promise<string | null>;
@@ -0,0 +1,29 @@
1
+ import { decodeStoredBlob } from '../../decode-html-blob.js';
2
+ /**
3
+ * Reads the HTML snapshot stored as a zstd-compressed BLOB for the given page.
4
+ *
5
+ * Joins `page_html_ref` → `page_html_blobs` and decompresses inline. Returns
6
+ * `null` when the page has no stored body (a non-HTML resource, a redirect
7
+ * source, a degraded render). Read works identically on read-only / stub
8
+ * connections — the special-cased "do we have a loose dir vs zip?" branching
9
+ * the previous file-backed layout required is gone.
10
+ *
11
+ * Tables `page_html_ref` and `page_html_blobs` are created by `initSchema`.
12
+ * Older `.nitpicker` archives that predate this migration must be passed
13
+ * through `scripts/migrate-to-0.10.mjs` before they can be read.
14
+ * @param knex - Knex query builder connected to the archive DB.
15
+ * @param pageId - The database ID of the page.
16
+ * @returns The decompressed HTML string, or `null` if no snapshot is stored.
17
+ */
18
+ export async function getHtmlOfPageById(knex, pageId) {
19
+ const row = await knex
20
+ .from('page_html_ref')
21
+ .join('page_html_blobs', 'page_html_ref.hash', '=', 'page_html_blobs.hash')
22
+ .select('page_html_blobs.body as body', 'page_html_blobs.codec as codec')
23
+ .where('page_html_ref.page_id', pageId)
24
+ .first();
25
+ if (!row) {
26
+ return null;
27
+ }
28
+ return decodeStoredBlob(row.body, row.codec);
29
+ }
@@ -0,0 +1,21 @@
1
+ import type { InventoryRunMeta } from '../../types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Appends one row to the `inventory_runs` audit log.
5
+ *
6
+ * Called by `CrawlerOrchestrator.inventory` on every successful
7
+ * `--inventory <list>` invocation so the archive carries a durable
8
+ * record of which deploy list was applied when and at what scale —
9
+ * the operational question "did we apply last month's list" the
10
+ * archive itself can answer without consulting external bookkeeping.
11
+ *
12
+ * Append-only. There is intentionally no UPDATE path and no UNIQUE
13
+ * constraint on `source_file_sha256`; two applies of the same list
14
+ * each get their own row. Duplicate detection is left to readers —
15
+ * the hash is recorded as the content-identity key they would use.
16
+ * Field-level NULL semantics live on {@link InventoryRunMeta}.
17
+ * @param knex - Knex query builder connected to the archive DB.
18
+ * @param meta - The run metadata to record. Only `ran_at` is required.
19
+ * @returns The autoincremented `id` of the newly-inserted row.
20
+ */
21
+ export declare function recordInventoryRun(knex: Knex, meta: InventoryRunMeta): Promise<number>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Appends one row to the `inventory_runs` audit log.
3
+ *
4
+ * Called by `CrawlerOrchestrator.inventory` on every successful
5
+ * `--inventory <list>` invocation so the archive carries a durable
6
+ * record of which deploy list was applied when and at what scale —
7
+ * the operational question "did we apply last month's list" the
8
+ * archive itself can answer without consulting external bookkeeping.
9
+ *
10
+ * Append-only. There is intentionally no UPDATE path and no UNIQUE
11
+ * constraint on `source_file_sha256`; two applies of the same list
12
+ * each get their own row. Duplicate detection is left to readers —
13
+ * the hash is recorded as the content-identity key they would use.
14
+ * Field-level NULL semantics live on {@link InventoryRunMeta}.
15
+ * @param knex - Knex query builder connected to the archive DB.
16
+ * @param meta - The run metadata to record. Only `ran_at` is required.
17
+ * @returns The autoincremented `id` of the newly-inserted row.
18
+ */
19
+ export async function recordInventoryRun(knex, meta) {
20
+ const inserted = await knex
21
+ .from('inventory_runs')
22
+ .insert({
23
+ ran_at: meta.ran_at,
24
+ list_label: meta.list_label ?? null,
25
+ source_file_sha256: meta.source_file_sha256 ?? null,
26
+ total_lines: meta.total_lines ?? null,
27
+ new_pages: meta.new_pages ?? null,
28
+ new_resources: meta.new_resources ?? null,
29
+ scope_skipped: meta.scope_skipped ?? null,
30
+ notes: meta.notes ?? null,
31
+ })
32
+ .returning('id');
33
+ const id = inserted[0]?.id;
34
+ if (typeof id !== 'number') {
35
+ throw new TypeError('recordInventoryRun: INSERT returned no row id');
36
+ }
37
+ return id;
38
+ }
@@ -0,0 +1,8 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Forces a WAL checkpoint, writing all pending WAL data back to the main database file.
4
+ * Uses TRUNCATE mode to reset the WAL file to zero bytes after checkpointing.
5
+ * This ensures the database is fully self-contained in `db.sqlite` before archiving.
6
+ * @param knex - Knex query builder connected to the archive DB.
7
+ */
8
+ export declare function checkpoint(knex: Knex): Promise<void>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Forces a WAL checkpoint, writing all pending WAL data back to the main database file.
3
+ * Uses TRUNCATE mode to reset the WAL file to zero bytes after checkpointing.
4
+ * This ensures the database is fully self-contained in `db.sqlite` before archiving.
5
+ * @param knex - Knex query builder connected to the archive DB.
6
+ */
7
+ export async function checkpoint(knex) {
8
+ await knex.raw('PRAGMA wal_checkpoint(TRUNCATE)');
9
+ }
@@ -0,0 +1,6 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Destroys the database connection, releasing all pooled resources.
4
+ * @param knex - Knex query builder connected to the archive DB.
5
+ */
6
+ export declare function destroy(knex: Knex): Promise<void>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Destroys the database connection, releasing all pooled resources.
3
+ * @param knex - Knex query builder connected to the archive DB.
4
+ */
5
+ export async function destroy(knex) {
6
+ await knex.destroy();
7
+ }
@@ -0,0 +1,22 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Initializes the database schema if tables do not exist, then runs the
4
+ * one remaining lightweight migration (`info.roots`).
5
+ *
6
+ * There is deliberately no per-table lazy-migration chain here:
7
+ * `assertCompatibleVersion` (called below, before any schema work)
8
+ * rejects every archive older than the current format, so a connection
9
+ * that reaches `initSchema` is either brand new (initSchema provisions
10
+ * the full schema) or was produced by `scripts/migrate-to-0.13.mjs`
11
+ * (which guarantees the full table set before it repacks). A
12
+ * `hasTable`-guarded catch-up migration could therefore never fire —
13
+ * schema catch-up for old archives is the migration script's job, not
14
+ * the open path's.
15
+ *
16
+ * In read-only mode schema init + migration are SKIPPED so the same DB
17
+ * can be opened safely by a viewer attached to a live (or interrupted)
18
+ * crawl without rewriting the user's tmpDir.
19
+ * @param knex - Knex query builder connected to the archive DB.
20
+ * @param readOnly - When true, skip schema init + migrations.
21
+ */
22
+ export declare function init(knex: Knex, readOnly: boolean): Promise<void>;
@@ -0,0 +1,42 @@
1
+ import { applyConnectionPragmas, initSchema } from '../../init-schema.js';
2
+ import { assertCompatibleVersion } from '../../meta/assert-compatible-version.js';
3
+ import { migrateInfoRoots } from '../../migrate-info-roots.js';
4
+ /**
5
+ * Initializes the database schema if tables do not exist, then runs the
6
+ * one remaining lightweight migration (`info.roots`).
7
+ *
8
+ * There is deliberately no per-table lazy-migration chain here:
9
+ * `assertCompatibleVersion` (called below, before any schema work)
10
+ * rejects every archive older than the current format, so a connection
11
+ * that reaches `initSchema` is either brand new (initSchema provisions
12
+ * the full schema) or was produced by `scripts/migrate-to-0.13.mjs`
13
+ * (which guarantees the full table set before it repacks). A
14
+ * `hasTable`-guarded catch-up migration could therefore never fire —
15
+ * schema catch-up for old archives is the migration script's job, not
16
+ * the open path's.
17
+ *
18
+ * In read-only mode schema init + migration are SKIPPED so the same DB
19
+ * can be opened safely by a viewer attached to a live (or interrupted)
20
+ * crawl without rewriting the user's tmpDir.
21
+ * @param knex - Knex query builder connected to the archive DB.
22
+ * @param readOnly - When true, skip schema init + migrations.
23
+ */
24
+ export async function init(knex, readOnly) {
25
+ // Connection-level PRAGMAs (foreign_keys, mmap_size, …) must be
26
+ // reapplied on every connect — they are not persisted across opens.
27
+ // They are safe in read-only mode because they don't write to the
28
+ // user's tmpDir, just configure the libsql connection.
29
+ await applyConnectionPragmas(knex);
30
+ // Reject incompatible archives before any further work. Runs for both
31
+ // writer and read-only (stub viewer) connections so old
32
+ // `._nitpicker-*` stubs surface a clear error instead of
33
+ // dereferencing missing columns at query time. New archives (no
34
+ // `info` table yet) pass through; the schema is filled in by
35
+ // `initSchema` below.
36
+ await assertCompatibleVersion(knex);
37
+ if (readOnly) {
38
+ return;
39
+ }
40
+ await initSchema(knex);
41
+ await migrateInfoRoots(knex);
42
+ }