@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,35 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates the five header decomposition tables (`header_name_refs`,
5
+ * `header_value_refs`, `header_sets`, `header_set_entries`,
6
+ * `header_flags`) from every `pages.responseHeaders` and
7
+ * `resources.responseHeaders` JSON blob (issue #191).
8
+ *
9
+ * Strategy:
10
+ *
11
+ * 1. **Warm caches** via {@link ./create-header-table-caches.ts} — load
12
+ * existing `header_name_refs`, `header_value_refs`, and `header_sets`
13
+ * rows into id maps. Idempotent re-runs then reuse ids instead of
14
+ * re-issuing an upsert per entry, and new ids are appended as they
15
+ * are inserted.
16
+ * 2. **Stream `pages.responseHeaders` + `resources.responseHeaders`** in
17
+ * id-keyset chunks. Each non-null value is decomposed via
18
+ * {@link decomposeHeaderSet} and written via
19
+ * {@link ./upsert-one-header-set.ts} — the same per-set primitive the
20
+ * crawler's live write path uses, so migrated and live-crawled
21
+ * archives produce identical header rows.
22
+ *
23
+ * Every write is bulk-batched so the migration stays O(chunks × per-
24
+ * chunk-distinct-decomposed-sets) round-trips against the DB. Idempotency
25
+ * across full re-runs is guaranteed by the `INSERT OR IGNORE`s and the
26
+ * `setIdsProcessedThisRun` guard inside the per-set upsert.
27
+ * @param trx - Knex instance or transaction connected to the archive DB.
28
+ * @param onProgress - Optional sink for periodic progress lines (one per
29
+ * ~5% of each source table scanned); see {@link ../create-progress-reporter.ts}.
30
+ * @example
31
+ * await knex.transaction(async (trx) => {
32
+ * await populateHeaderTables(trx);
33
+ * });
34
+ */
35
+ export declare function populateHeaderTables(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,80 @@
1
+ import { createProgressReporter } from '../create-progress-reporter.js';
2
+ import { createHeaderTableCaches } from './create-header-table-caches.js';
3
+ import { decomposeHeaderSet } from './decompose-header-set.js';
4
+ import { upsertOneHeaderSet } from './upsert-one-header-set.js';
5
+ /**
6
+ * Rows scanned per SELECT chunk against `pages.responseHeaders` /
7
+ * `resources.responseHeaders`. Keyset-paginated on `id` to avoid loading
8
+ * a 470k-row `responseHeaders` column into a single query result.
9
+ */
10
+ const READ_CHUNK_SIZE = 500;
11
+ /**
12
+ * Populates the five header decomposition tables (`header_name_refs`,
13
+ * `header_value_refs`, `header_sets`, `header_set_entries`,
14
+ * `header_flags`) from every `pages.responseHeaders` and
15
+ * `resources.responseHeaders` JSON blob (issue #191).
16
+ *
17
+ * Strategy:
18
+ *
19
+ * 1. **Warm caches** via {@link ./create-header-table-caches.ts} — load
20
+ * existing `header_name_refs`, `header_value_refs`, and `header_sets`
21
+ * rows into id maps. Idempotent re-runs then reuse ids instead of
22
+ * re-issuing an upsert per entry, and new ids are appended as they
23
+ * are inserted.
24
+ * 2. **Stream `pages.responseHeaders` + `resources.responseHeaders`** in
25
+ * id-keyset chunks. Each non-null value is decomposed via
26
+ * {@link decomposeHeaderSet} and written via
27
+ * {@link ./upsert-one-header-set.ts} — the same per-set primitive the
28
+ * crawler's live write path uses, so migrated and live-crawled
29
+ * archives produce identical header rows.
30
+ *
31
+ * Every write is bulk-batched so the migration stays O(chunks × per-
32
+ * chunk-distinct-decomposed-sets) round-trips against the DB. Idempotency
33
+ * across full re-runs is guaranteed by the `INSERT OR IGNORE`s and the
34
+ * `setIdsProcessedThisRun` guard inside the per-set upsert.
35
+ * @param trx - Knex instance or transaction connected to the archive DB.
36
+ * @param onProgress - Optional sink for periodic progress lines (one per
37
+ * ~5% of each source table scanned); see {@link ../create-progress-reporter.ts}.
38
+ * @example
39
+ * await knex.transaction(async (trx) => {
40
+ * await populateHeaderTables(trx);
41
+ * });
42
+ */
43
+ export async function populateHeaderTables(trx, onProgress) {
44
+ const caches = await createHeaderTableCaches(trx);
45
+ for (const table of ['pages', 'resources']) {
46
+ const hasTable = await trx.schema.hasTable(table);
47
+ if (!hasTable) {
48
+ continue;
49
+ }
50
+ const hasColumn = await trx.schema.hasColumn(table, 'responseHeaders');
51
+ if (!hasColumn) {
52
+ continue;
53
+ }
54
+ const countRows = await trx(table).count({ n: '*' });
55
+ const total = Number(countRows[0]?.n ?? 0);
56
+ const report = createProgressReporter(`header_tables (${table})`, total, onProgress);
57
+ let processed = 0;
58
+ let cursor = 0;
59
+ while (true) {
60
+ const rows = await trx(table)
61
+ .select('id', 'responseHeaders')
62
+ .where('id', '>', cursor)
63
+ .orderBy('id', 'asc')
64
+ .limit(READ_CHUNK_SIZE);
65
+ if (rows.length === 0) {
66
+ break;
67
+ }
68
+ cursor = rows.at(-1).id;
69
+ processed += rows.length;
70
+ report(processed);
71
+ for (const row of rows) {
72
+ const decomposed = decomposeHeaderSet(row.responseHeaders);
73
+ if (decomposed === null) {
74
+ continue;
75
+ }
76
+ await upsertOneHeaderSet(trx, decomposed, caches);
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,29 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates `json_refs` from every non-null `pages.meta_extras` value
5
+ * (issue #191).
6
+ *
7
+ * Each value is:
8
+ *
9
+ * 1. Hashed with {@link computeContentHash} (32-byte SHA-256; see that
10
+ * function's docs for the algorithm-choice rationale).
11
+ * 2. Compressed with `zstdCompressSync` (`codec='zstd'`) — same encoder
12
+ * used by `page_html_blobs`.
13
+ * 3. Deduplicated by hash — identical raw JSON strings produce one row.
14
+ *
15
+ * `size_raw` records the uncompressed byte length (UTF-8) and
16
+ * `size_stored` records the compressed byte length; consumers can
17
+ * estimate compression savings without decompressing.
18
+ *
19
+ * `INSERT OR IGNORE` on `hash` makes the step idempotent across partial-
20
+ * failure restarts.
21
+ * @param trx - Knex instance or transaction connected to the archive DB.
22
+ * @param onProgress - Optional sink for periodic progress lines (one per
23
+ * ~5% of `pages` scanned); see {@link ../create-progress-reporter.ts}.
24
+ * @example
25
+ * await knex.transaction(async (trx) => {
26
+ * await populateJsonRefs(trx);
27
+ * });
28
+ */
29
+ export declare function populateJsonRefs(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,101 @@
1
+ import { zstdCompressSync } from 'node:zlib';
2
+ import { createProgressReporter } from '../create-progress-reporter.js';
3
+ import { computeContentHash } from './compute-content-hash.js';
4
+ /**
5
+ * Number of `json_refs` rows sent per INSERT. Each row binds 5 params
6
+ * (hash + json_text + codec + size_raw + size_stored). 200 rows = 1000
7
+ * params — comfortable margin under SQLite's default variable limit and
8
+ * bounds any one INSERT's compressed-blob payload total to a size that
9
+ * fits in one WAL frame.
10
+ */
11
+ const INSERT_CHUNK_SIZE = 200;
12
+ /**
13
+ * Rows scanned per source query. Same rationale as the other populators:
14
+ * streaming with keyset pagination on `id` avoids loading a 470k-row
15
+ * `meta_extras` column into a single result set.
16
+ */
17
+ const READ_CHUNK_SIZE = 1000;
18
+ /**
19
+ * Populates `json_refs` from every non-null `pages.meta_extras` value
20
+ * (issue #191).
21
+ *
22
+ * Each value is:
23
+ *
24
+ * 1. Hashed with {@link computeContentHash} (32-byte SHA-256; see that
25
+ * function's docs for the algorithm-choice rationale).
26
+ * 2. Compressed with `zstdCompressSync` (`codec='zstd'`) — same encoder
27
+ * used by `page_html_blobs`.
28
+ * 3. Deduplicated by hash — identical raw JSON strings produce one row.
29
+ *
30
+ * `size_raw` records the uncompressed byte length (UTF-8) and
31
+ * `size_stored` records the compressed byte length; consumers can
32
+ * estimate compression savings without decompressing.
33
+ *
34
+ * `INSERT OR IGNORE` on `hash` makes the step idempotent across partial-
35
+ * failure restarts.
36
+ * @param trx - Knex instance or transaction connected to the archive DB.
37
+ * @param onProgress - Optional sink for periodic progress lines (one per
38
+ * ~5% of `pages` scanned); see {@link ../create-progress-reporter.ts}.
39
+ * @example
40
+ * await knex.transaction(async (trx) => {
41
+ * await populateJsonRefs(trx);
42
+ * });
43
+ */
44
+ export async function populateJsonRefs(trx, onProgress) {
45
+ const hasPages = await trx.schema.hasTable('pages');
46
+ if (!hasPages) {
47
+ return;
48
+ }
49
+ const hasMetaExtras = await trx.schema.hasColumn('pages', 'meta_extras');
50
+ if (!hasMetaExtras) {
51
+ return;
52
+ }
53
+ const seen = new Set();
54
+ const pending = [];
55
+ const countRows = await trx('pages').count({ n: '*' });
56
+ const total = Number(countRows[0]?.n ?? 0);
57
+ const report = createProgressReporter('json_refs (pages)', total, onProgress);
58
+ let processed = 0;
59
+ let cursor = 0;
60
+ while (true) {
61
+ const rows = await trx('pages')
62
+ .select('id', 'meta_extras as value')
63
+ .where('id', '>', cursor)
64
+ .orderBy('id', 'asc')
65
+ .limit(READ_CHUNK_SIZE);
66
+ if (rows.length === 0) {
67
+ break;
68
+ }
69
+ cursor = rows.at(-1).id;
70
+ processed += rows.length;
71
+ report(processed);
72
+ for (const row of rows) {
73
+ const raw = row.value;
74
+ if (raw == null || raw === '') {
75
+ continue;
76
+ }
77
+ const rawBytes = Buffer.from(raw, 'utf8');
78
+ const hash = computeContentHash(rawBytes);
79
+ const hex = hash.toString('hex');
80
+ if (seen.has(hex)) {
81
+ continue;
82
+ }
83
+ seen.add(hex);
84
+ const compressed = zstdCompressSync(rawBytes);
85
+ pending.push({
86
+ hash,
87
+ json_text: compressed,
88
+ codec: 'zstd',
89
+ size_raw: rawBytes.byteLength,
90
+ size_stored: compressed.byteLength,
91
+ });
92
+ if (pending.length >= INSERT_CHUNK_SIZE) {
93
+ await trx('json_refs').insert(pending).onConflict('hash').ignore();
94
+ pending.length = 0;
95
+ }
96
+ }
97
+ }
98
+ if (pending.length > 0) {
99
+ await trx('json_refs').insert(pending).onConflict('hash').ignore();
100
+ }
101
+ }
@@ -0,0 +1,51 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Runs the six 0.13 ref-table populates (issue #191) in this fixed
5
+ * order against an already-connected archive:
6
+ *
7
+ * 1. `content_type_refs`
8
+ * 2. `url_refs`
9
+ * 3. `text_refs`
10
+ * 4. `json_refs`
11
+ * 5. `blob_refs`
12
+ * 6. Header tables (name / value / set / entries / flags).
13
+ *
14
+ * The order is an execution-order invariant, not arbitrary: the entity
15
+ * populates that run afterwards (`populateEntityTables`) JOIN against
16
+ * `content_type_refs` when filling `content_items` / `resource_items`,
17
+ * and look up `url_refs.id` for every URL column, so both dictionaries
18
+ * must be complete first. Within this function the ordering is:
19
+ * dictionary tables (1–5) first, header tables (6) last — the header
20
+ * tables' entries reference name / value refs, but those are inserted
21
+ * by `populateHeaderTables` itself, so no barrier between sub-populates
22
+ * is required.
23
+ *
24
+ * Every sub-populate is independently idempotent via `INSERT OR IGNORE`
25
+ * on its natural key. Running this orchestrator twice on the same archive
26
+ * produces the same rows — no phase marker table is used. This function
27
+ * does not open its own transaction so the caller controls the boundary;
28
+ * the whole invocation is expected to run inside one writer transaction
29
+ * with `.bak` protection at the caller level.
30
+ *
31
+ * `scripts/migrate-to-0.13.mjs` does NOT call this orchestrator directly
32
+ * — it calls the same six sub-populates itself, each in its own
33
+ * transaction, so a killed multi-hour migration only re-does the one
34
+ * table in flight on resume rather than the whole six-table batch. Use
35
+ * this function directly when that per-table checkpointing is not
36
+ * needed and a single all-or-nothing transaction is preferred.
37
+ * @param trx - Knex instance or transaction connected to the archive DB.
38
+ * @param onProgress - Optional sink threaded to every sub-populate for
39
+ * periodic progress lines; see {@link ../create-progress-reporter.ts}.
40
+ * @example
41
+ * // Single-transaction use: connect via Archive, wrap in a
42
+ * // transaction, run every sub-step, then rely on the caller's `.bak`
43
+ * // safety net if any step throws.
44
+ * const archive = await Archive.open(archivePath);
45
+ * const knex = archive.getKnex();
46
+ * await knex.transaction(async (trx) => {
47
+ * await populateRefTables(trx);
48
+ * });
49
+ * await archive.write();
50
+ */
51
+ export declare function populateRefTables(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,62 @@
1
+ import { populateBlobRefs } from './populate-blob-refs.js';
2
+ import { populateContentTypeRefs } from './populate-content-type-refs.js';
3
+ import { populateHeaderTables } from './populate-header-tables.js';
4
+ import { populateJsonRefs } from './populate-json-refs.js';
5
+ import { populateTextRefs } from './populate-text-refs.js';
6
+ import { populateUrlRefs } from './populate-url-refs.js';
7
+ /**
8
+ * Runs the six 0.13 ref-table populates (issue #191) in this fixed
9
+ * order against an already-connected archive:
10
+ *
11
+ * 1. `content_type_refs`
12
+ * 2. `url_refs`
13
+ * 3. `text_refs`
14
+ * 4. `json_refs`
15
+ * 5. `blob_refs`
16
+ * 6. Header tables (name / value / set / entries / flags).
17
+ *
18
+ * The order is an execution-order invariant, not arbitrary: the entity
19
+ * populates that run afterwards (`populateEntityTables`) JOIN against
20
+ * `content_type_refs` when filling `content_items` / `resource_items`,
21
+ * and look up `url_refs.id` for every URL column, so both dictionaries
22
+ * must be complete first. Within this function the ordering is:
23
+ * dictionary tables (1–5) first, header tables (6) last — the header
24
+ * tables' entries reference name / value refs, but those are inserted
25
+ * by `populateHeaderTables` itself, so no barrier between sub-populates
26
+ * is required.
27
+ *
28
+ * Every sub-populate is independently idempotent via `INSERT OR IGNORE`
29
+ * on its natural key. Running this orchestrator twice on the same archive
30
+ * produces the same rows — no phase marker table is used. This function
31
+ * does not open its own transaction so the caller controls the boundary;
32
+ * the whole invocation is expected to run inside one writer transaction
33
+ * with `.bak` protection at the caller level.
34
+ *
35
+ * `scripts/migrate-to-0.13.mjs` does NOT call this orchestrator directly
36
+ * — it calls the same six sub-populates itself, each in its own
37
+ * transaction, so a killed multi-hour migration only re-does the one
38
+ * table in flight on resume rather than the whole six-table batch. Use
39
+ * this function directly when that per-table checkpointing is not
40
+ * needed and a single all-or-nothing transaction is preferred.
41
+ * @param trx - Knex instance or transaction connected to the archive DB.
42
+ * @param onProgress - Optional sink threaded to every sub-populate for
43
+ * periodic progress lines; see {@link ../create-progress-reporter.ts}.
44
+ * @example
45
+ * // Single-transaction use: connect via Archive, wrap in a
46
+ * // transaction, run every sub-step, then rely on the caller's `.bak`
47
+ * // safety net if any step throws.
48
+ * const archive = await Archive.open(archivePath);
49
+ * const knex = archive.getKnex();
50
+ * await knex.transaction(async (trx) => {
51
+ * await populateRefTables(trx);
52
+ * });
53
+ * await archive.write();
54
+ */
55
+ export async function populateRefTables(trx, onProgress) {
56
+ await populateContentTypeRefs(trx);
57
+ await populateUrlRefs(trx, onProgress);
58
+ await populateTextRefs(trx, onProgress);
59
+ await populateJsonRefs(trx, onProgress);
60
+ await populateBlobRefs(trx, onProgress);
61
+ await populateHeaderTables(trx, onProgress);
62
+ }
@@ -0,0 +1,32 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates `text_refs` from every text-shaped column across `anchors`,
5
+ * `images`, and `pages` (issue #191).
6
+ *
7
+ * Rules:
8
+ *
9
+ * - **Content-hash dedup contract**: identical text produces one row. The
10
+ * hash is derived by {@link computeContentHash} (currently SHA-256,
11
+ * matching `page_html_blobs.hash`; see that function's docs for the
12
+ * algorithm-choice rationale).
13
+ * - **Empty and null are skipped** — an empty `<a>` tag adds no text to
14
+ * the dictionary. Anchors with no text still get an `anchor_edges` row
15
+ * in 0.13, just with `first_text_id = NULL`.
16
+ * - **INSERT OR IGNORE on (hash, text)** — the composite UNIQUE from the
17
+ * 0.13 DDL — makes the step idempotent across partial-failure
18
+ * restarts.
19
+ *
20
+ * Peak memory is bounded by the count of distinct texts (all texts are
21
+ * held in a Map before insert). On the reference archive this Map is
22
+ * about 5 MB of anchor textContent + a few MB of page meta text — well
23
+ * within the migration process budget.
24
+ * @param trx - Knex instance or transaction connected to the archive DB.
25
+ * @param onProgress - Optional sink for periodic progress lines (one per
26
+ * ~5% of each source table scanned); see {@link ../create-progress-reporter.ts}.
27
+ * @example
28
+ * await knex.transaction(async (trx) => {
29
+ * await populateTextRefs(trx);
30
+ * });
31
+ */
32
+ export declare function populateTextRefs(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,133 @@
1
+ import { createProgressReporter } from '../create-progress-reporter.js';
2
+ import { computeContentHash } from './compute-content-hash.js';
3
+ /**
4
+ * Number of `text_refs` rows sent per `INSERT ... VALUES (...)` statement.
5
+ * Each row binds 2 params (hash + text), so 500 rows = 1000 params — well
6
+ * under SQLite's default `SQLITE_MAX_VARIABLE_NUMBER`.
7
+ */
8
+ const INSERT_CHUNK_SIZE = 500;
9
+ /**
10
+ * Rows scanned per keyset-paginated `SELECT` chunk. One SELECT reads all
11
+ * text columns for the source table's chunk simultaneously so the pages
12
+ * table is scanned exactly once per populate call, not N-times-once-per-
13
+ * text-column.
14
+ */
15
+ const READ_CHUNK_SIZE = 5000;
16
+ /**
17
+ * Source table + its text-shaped columns. Groups by table so each table
18
+ * is scanned exactly once with a single SELECT that covers every
19
+ * relevant column — a per-column scan would run 8 separate `pages`
20
+ * scans and multiply migration wall-clock accordingly.
21
+ *
22
+ * `dom_path` is intentionally absent: dom_path strings are derived from
23
+ * the stored HTML blob, not from any column of the current write-model,
24
+ * so this scan has nothing to read. Upserting dom_path strings into
25
+ * `text_refs` is the job of the image-items populate
26
+ * (`populate-entity-tables/populate-image-items.ts`), not this pass.
27
+ */
28
+ const TEXT_SOURCES = [
29
+ { table: 'anchors', columns: ['textContent'] },
30
+ { table: 'images', columns: ['alt'] },
31
+ {
32
+ table: 'pages',
33
+ columns: [
34
+ 'title',
35
+ 'description',
36
+ 'keywords',
37
+ 'robots_raw',
38
+ 'og_title',
39
+ 'og_description',
40
+ 'twitter_title',
41
+ 'twitter_description',
42
+ ],
43
+ },
44
+ ];
45
+ /**
46
+ * Populates `text_refs` from every text-shaped column across `anchors`,
47
+ * `images`, and `pages` (issue #191).
48
+ *
49
+ * Rules:
50
+ *
51
+ * - **Content-hash dedup contract**: identical text produces one row. The
52
+ * hash is derived by {@link computeContentHash} (currently SHA-256,
53
+ * matching `page_html_blobs.hash`; see that function's docs for the
54
+ * algorithm-choice rationale).
55
+ * - **Empty and null are skipped** — an empty `<a>` tag adds no text to
56
+ * the dictionary. Anchors with no text still get an `anchor_edges` row
57
+ * in 0.13, just with `first_text_id = NULL`.
58
+ * - **INSERT OR IGNORE on (hash, text)** — the composite UNIQUE from the
59
+ * 0.13 DDL — makes the step idempotent across partial-failure
60
+ * restarts.
61
+ *
62
+ * Peak memory is bounded by the count of distinct texts (all texts are
63
+ * held in a Map before insert). On the reference archive this Map is
64
+ * about 5 MB of anchor textContent + a few MB of page meta text — well
65
+ * within the migration process budget.
66
+ * @param trx - Knex instance or transaction connected to the archive DB.
67
+ * @param onProgress - Optional sink for periodic progress lines (one per
68
+ * ~5% of each source table scanned); see {@link ../create-progress-reporter.ts}.
69
+ * @example
70
+ * await knex.transaction(async (trx) => {
71
+ * await populateTextRefs(trx);
72
+ * });
73
+ */
74
+ export async function populateTextRefs(trx, onProgress) {
75
+ const seen = new Map();
76
+ for (const source of TEXT_SOURCES) {
77
+ const hasTable = await trx.schema.hasTable(source.table);
78
+ if (!hasTable) {
79
+ continue;
80
+ }
81
+ const presentColumns = [];
82
+ for (const column of source.columns) {
83
+ if (await trx.schema.hasColumn(source.table, column)) {
84
+ presentColumns.push(column);
85
+ }
86
+ }
87
+ if (presentColumns.length === 0) {
88
+ continue;
89
+ }
90
+ const countRows = await trx(source.table).count({ n: '*' });
91
+ const total = Number(countRows[0]?.n ?? 0);
92
+ const report = createProgressReporter(`text_refs (${source.table})`, total, onProgress);
93
+ let processed = 0;
94
+ let cursor = 0;
95
+ while (true) {
96
+ const rows = await trx(source.table)
97
+ .select('id', ...presentColumns)
98
+ .where('id', '>', cursor)
99
+ .orderBy('id', 'asc')
100
+ .limit(READ_CHUNK_SIZE);
101
+ if (rows.length === 0) {
102
+ break;
103
+ }
104
+ cursor = rows.at(-1).id;
105
+ processed += rows.length;
106
+ report(processed);
107
+ for (const row of rows) {
108
+ for (const column of presentColumns) {
109
+ const value = row[column];
110
+ if (typeof value !== 'string' || value === '') {
111
+ continue;
112
+ }
113
+ const hash = computeContentHash(value);
114
+ const key = hash.toString('hex');
115
+ if (!seen.has(key)) {
116
+ seen.set(key, value);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ if (seen.size === 0) {
123
+ return;
124
+ }
125
+ const inserts = [];
126
+ for (const [hex, text] of seen) {
127
+ inserts.push({ hash: Buffer.from(hex, 'hex'), text });
128
+ }
129
+ for (let index = 0; index < inserts.length; index += INSERT_CHUNK_SIZE) {
130
+ const chunk = inserts.slice(index, index + INSERT_CHUNK_SIZE);
131
+ await trx('text_refs').insert(chunk).onConflict(['hash', 'text']).ignore();
132
+ }
133
+ }
@@ -0,0 +1,28 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates `url_refs` from every URL-shaped column across `pages`,
5
+ * `resources`, and `images` (issue #191).
6
+ *
7
+ * Runs two passes per source table:
8
+ *
9
+ * 1. **Collect distinct URLs** into an in-process `Set<string>`, streaming
10
+ * rows from each source table by keyset pagination on `id`. All the
11
+ * table's URL columns are read in a single SELECT so the pages scan
12
+ * is O(rows), not O(rows × columns). Peak memory is bounded by the
13
+ * count of distinct URLs, not the row count.
14
+ * 2. **Bulk-insert** into `url_refs` in chunks of {@link INSERT_CHUNK_SIZE},
15
+ * with the decomposed columns (`scheme` / `host` / `port` / `path` /
16
+ * `query_hash` / `fragment`) derived in JS by {@link decomposeUrl}.
17
+ *
18
+ * `INSERT OR IGNORE` on `url_refs.url` makes the step idempotent —
19
+ * repeated invocations after partial failure only add new URLs.
20
+ * @param trx - Knex instance or transaction connected to the archive DB.
21
+ * @param onProgress - Optional sink for periodic progress lines (one per
22
+ * ~5% of each source table scanned); see {@link ../create-progress-reporter.ts}.
23
+ * @example
24
+ * await knex.transaction(async (trx) => {
25
+ * await populateUrlRefs(trx);
26
+ * });
27
+ */
28
+ export declare function populateUrlRefs(trx: Knex, onProgress?: ProgressCallback): Promise<void>;