@nitpicker/crawler 0.11.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 (387) 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 +175 -13
  7. package/lib/archive/archive.js +198 -14
  8. package/lib/archive/cache/compute-archive-cache-key.d.ts +39 -0
  9. package/lib/archive/cache/compute-archive-cache-key.js +95 -0
  10. package/lib/archive/cache/extract-archive-to-cache.d.ts +43 -0
  11. package/lib/archive/cache/extract-archive-to-cache.js +309 -0
  12. package/lib/archive/cache/get-archive-cache-root.d.ts +20 -0
  13. package/lib/archive/cache/get-archive-cache-root.js +53 -0
  14. package/lib/archive/cache/is-archive-cache-disabled.d.ts +24 -0
  15. package/lib/archive/cache/is-archive-cache-disabled.js +34 -0
  16. package/lib/archive/cache/resolve-archive-cache-dir.d.ts +26 -0
  17. package/lib/archive/cache/resolve-archive-cache-dir.js +32 -0
  18. package/lib/archive/create-adjunct-tables.d.ts +43 -0
  19. package/lib/archive/create-adjunct-tables.js +213 -0
  20. package/lib/archive/create-entity-tables.d.ts +173 -0
  21. package/lib/archive/create-entity-tables.js +318 -0
  22. package/lib/archive/create-progress-reporter.d.ts +30 -0
  23. package/lib/archive/create-progress-reporter.js +38 -0
  24. package/lib/archive/create-ref-tables.d.ts +35 -0
  25. package/lib/archive/create-ref-tables.js +188 -0
  26. package/lib/archive/database.d.ts +130 -182
  27. package/lib/archive/database.js +524 -1777
  28. package/lib/archive/db-ops/_shared/clear-write-ref-caches.d.ts +27 -0
  29. package/lib/archive/db-ops/_shared/clear-write-ref-caches.js +34 -0
  30. package/lib/archive/db-ops/_shared/create-write-ref-caches.d.ts +17 -0
  31. package/lib/archive/db-ops/_shared/create-write-ref-caches.js +26 -0
  32. package/lib/archive/db-ops/_shared/decode-json-ref.d.ts +17 -0
  33. package/lib/archive/db-ops/_shared/decode-json-ref.js +31 -0
  34. package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.d.ts +20 -0
  35. package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.js +53 -0
  36. package/lib/archive/db-ops/_shared/resolve-content-item-id.d.ts +61 -0
  37. package/lib/archive/db-ops/_shared/resolve-content-item-id.js +111 -0
  38. package/lib/archive/db-ops/_shared/resolve-url-or-blob.d.ts +23 -0
  39. package/lib/archive/db-ops/_shared/resolve-url-or-blob.js +29 -0
  40. package/lib/archive/db-ops/_shared/retry-setting.d.ts +16 -0
  41. package/lib/archive/db-ops/_shared/retry-setting.js +18 -0
  42. package/lib/archive/db-ops/_shared/safe-parse-json.d.ts +11 -0
  43. package/lib/archive/db-ops/_shared/safe-parse-json.js +18 -0
  44. package/lib/archive/db-ops/_shared/types.d.ts +53 -0
  45. package/lib/archive/db-ops/_shared/types.js +1 -0
  46. package/lib/archive/db-ops/_shared/upsert-blob-ref.d.ts +25 -0
  47. package/lib/archive/db-ops/_shared/upsert-blob-ref.js +48 -0
  48. package/lib/archive/db-ops/_shared/upsert-content-type-ref.d.ts +30 -0
  49. package/lib/archive/db-ops/_shared/upsert-content-type-ref.js +45 -0
  50. package/lib/archive/db-ops/_shared/upsert-json-ref.d.ts +22 -0
  51. package/lib/archive/db-ops/_shared/upsert-json-ref.js +41 -0
  52. package/lib/archive/db-ops/_shared/upsert-response-headers.d.ts +35 -0
  53. package/lib/archive/db-ops/_shared/upsert-response-headers.js +49 -0
  54. package/lib/archive/db-ops/_shared/upsert-url-ref.d.ts +39 -0
  55. package/lib/archive/db-ops/_shared/upsert-url-ref.js +62 -0
  56. package/lib/archive/db-ops/analysis/replace-analysis-violations.d.ts +28 -0
  57. package/lib/archive/db-ops/analysis/replace-analysis-violations.js +152 -0
  58. package/lib/archive/db-ops/anchors/get-anchors-on-page.d.ts +10 -0
  59. package/lib/archive/db-ops/anchors/get-anchors-on-page.js +21 -0
  60. package/lib/archive/db-ops/config/get-base-url.d.ts +8 -0
  61. package/lib/archive/db-ops/config/get-base-url.js +14 -0
  62. package/lib/archive/db-ops/config/get-config.d.ts +10 -0
  63. package/lib/archive/db-ops/config/get-config.js +27 -0
  64. package/lib/archive/db-ops/config/get-name.d.ts +8 -0
  65. package/lib/archive/db-ops/config/get-name.js +14 -0
  66. package/lib/archive/db-ops/config/info-column-allowlist.d.ts +7 -0
  67. package/lib/archive/db-ops/config/info-column-allowlist.js +26 -0
  68. package/lib/archive/db-ops/config/info-json-columns.d.ts +5 -0
  69. package/lib/archive/db-ops/config/info-json-columns.js +10 -0
  70. package/lib/archive/db-ops/config/set-config.d.ts +12 -0
  71. package/lib/archive/db-ops/config/set-config.js +21 -0
  72. package/lib/archive/db-ops/config/update-config.d.ts +17 -0
  73. package/lib/archive/db-ops/config/update-config.js +36 -0
  74. package/lib/archive/db-ops/errors/insert-crawl-error.d.ts +15 -0
  75. package/lib/archive/db-ops/errors/insert-crawl-error.js +21 -0
  76. package/lib/archive/db-ops/errors/insert-page-error.d.ts +21 -0
  77. package/lib/archive/db-ops/errors/insert-page-error.js +28 -0
  78. package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.d.ts +22 -0
  79. package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.js +141 -0
  80. package/lib/archive/db-ops/html/get-html-of-page-by-id.d.ts +18 -0
  81. package/lib/archive/db-ops/html/get-html-of-page-by-id.js +29 -0
  82. package/lib/archive/db-ops/inventory/record-inventory-run.d.ts +21 -0
  83. package/lib/archive/db-ops/inventory/record-inventory-run.js +38 -0
  84. package/lib/archive/db-ops/lifecycle/checkpoint.d.ts +8 -0
  85. package/lib/archive/db-ops/lifecycle/checkpoint.js +9 -0
  86. package/lib/archive/db-ops/lifecycle/destroy.d.ts +6 -0
  87. package/lib/archive/db-ops/lifecycle/destroy.js +7 -0
  88. package/lib/archive/db-ops/lifecycle/init.d.ts +22 -0
  89. package/lib/archive/db-ops/lifecycle/init.js +42 -0
  90. package/lib/archive/db-ops/meta/get-jsonld-of-page.d.ts +13 -0
  91. package/lib/archive/db-ops/meta/get-jsonld-of-page.js +27 -0
  92. package/lib/archive/db-ops/meta/get-tags-of-page.d.ts +12 -0
  93. package/lib/archive/db-ops/meta/get-tags-of-page.js +28 -0
  94. package/lib/archive/db-ops/pages/order/set-url-order.d.ts +8 -0
  95. package/lib/archive/db-ops/pages/order/set-url-order.js +32 -0
  96. package/lib/archive/db-ops/pages/read/build-page-query.d.ts +18 -0
  97. package/lib/archive/db-ops/pages/read/build-page-query.js +40 -0
  98. package/lib/archive/db-ops/pages/read/get-crawling-state.d.ts +70 -0
  99. package/lib/archive/db-ops/pages/read/get-crawling-state.js +98 -0
  100. package/lib/archive/db-ops/pages/read/get-existing-page-urls.d.ts +15 -0
  101. package/lib/archive/db-ops/pages/read/get-existing-page-urls.js +30 -0
  102. package/lib/archive/db-ops/pages/read/get-page-count.d.ts +12 -0
  103. package/lib/archive/db-ops/pages/read/get-page-count.js +21 -0
  104. package/lib/archive/db-ops/pages/read/get-page-source-by-url.d.ts +24 -0
  105. package/lib/archive/db-ops/pages/read/get-page-source-by-url.js +28 -0
  106. package/lib/archive/db-ops/pages/read/get-pages-with-rels.d.ts +38 -0
  107. package/lib/archive/db-ops/pages/read/get-pages-with-rels.js +107 -0
  108. package/lib/archive/db-ops/pages/read/get-pages.d.ts +11 -0
  109. package/lib/archive/db-ops/pages/read/get-pages.js +51 -0
  110. package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.d.ts +18 -0
  111. package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.js +25 -0
  112. package/lib/archive/db-ops/pages/read/reconstruct-page-rows.d.ts +31 -0
  113. package/lib/archive/db-ops/pages/read/reconstruct-page-rows.js +32 -0
  114. package/lib/archive/db-ops/pages/reset/repromote-external-pages.d.ts +24 -0
  115. package/lib/archive/db-ops/pages/reset/repromote-external-pages.js +93 -0
  116. package/lib/archive/db-ops/pages/reset/reset-failed-pages.d.ts +47 -0
  117. package/lib/archive/db-ops/pages/reset/reset-failed-pages.js +124 -0
  118. package/lib/archive/db-ops/pages/write/insert-inventory-seeds.d.ts +37 -0
  119. package/lib/archive/db-ops/pages/write/insert-inventory-seeds.js +72 -0
  120. package/lib/archive/db-ops/pages/write/insert-jsonld.d.ts +17 -0
  121. package/lib/archive/db-ops/pages/write/insert-jsonld.js +49 -0
  122. package/lib/archive/db-ops/pages/write/insert-page.d.ts +36 -0
  123. package/lib/archive/db-ops/pages/write/insert-page.js +208 -0
  124. package/lib/archive/db-ops/pages/write/insert-tags.d.ts +16 -0
  125. package/lib/archive/db-ops/pages/write/insert-tags.js +34 -0
  126. package/lib/archive/db-ops/pages/write/link-redirect-sources.d.ts +36 -0
  127. package/lib/archive/db-ops/pages/write/link-redirect-sources.js +93 -0
  128. package/lib/archive/db-ops/pages/write/record-redirect.d.ts +35 -0
  129. package/lib/archive/db-ops/pages/write/record-redirect.js +100 -0
  130. package/lib/archive/db-ops/pages/write/set-skipped-page.d.ts +13 -0
  131. package/lib/archive/db-ops/pages/write/set-skipped-page.js +22 -0
  132. package/lib/archive/db-ops/pages/write/update-page.d.ts +29 -0
  133. package/lib/archive/db-ops/pages/write/update-page.js +334 -0
  134. package/lib/archive/db-ops/pages/write/write-page-html-blob.d.ts +19 -0
  135. package/lib/archive/db-ops/pages/write/write-page-html-blob.js +41 -0
  136. package/lib/archive/db-ops/referrers/get-redirects-for-pages.d.ts +9 -0
  137. package/lib/archive/db-ops/referrers/get-redirects-for-pages.js +15 -0
  138. package/lib/archive/db-ops/referrers/get-referrers-of-page.d.ts +17 -0
  139. package/lib/archive/db-ops/referrers/get-referrers-of-page.js +32 -0
  140. package/lib/archive/db-ops/referrers/get-referrers-of-resource.d.ts +8 -0
  141. package/lib/archive/db-ops/referrers/get-referrers-of-resource.js +15 -0
  142. package/lib/archive/db-ops/resources/build-resource-query.d.ts +25 -0
  143. package/lib/archive/db-ops/resources/build-resource-query.js +29 -0
  144. package/lib/archive/db-ops/resources/get-existing-resource-urls.d.ts +9 -0
  145. package/lib/archive/db-ops/resources/get-existing-resource-urls.js +24 -0
  146. package/lib/archive/db-ops/resources/get-resource-by-url.d.ts +13 -0
  147. package/lib/archive/db-ops/resources/get-resource-by-url.js +22 -0
  148. package/lib/archive/db-ops/resources/get-resource-url-list.d.ts +9 -0
  149. package/lib/archive/db-ops/resources/get-resource-url-list.js +13 -0
  150. package/lib/archive/db-ops/resources/get-resources.d.ts +8 -0
  151. package/lib/archive/db-ops/resources/get-resources.js +11 -0
  152. package/lib/archive/db-ops/resources/insert-inventory-resources.d.ts +24 -0
  153. package/lib/archive/db-ops/resources/insert-inventory-resources.js +64 -0
  154. package/lib/archive/db-ops/resources/insert-resource-referrers.d.ts +15 -0
  155. package/lib/archive/db-ops/resources/insert-resource-referrers.js +54 -0
  156. package/lib/archive/db-ops/resources/insert-resource.d.ts +34 -0
  157. package/lib/archive/db-ops/resources/insert-resource.js +73 -0
  158. package/lib/archive/db-ops/resources/reconstruct-resource-rows.d.ts +26 -0
  159. package/lib/archive/db-ops/resources/reconstruct-resource-rows.js +30 -0
  160. package/lib/archive/decode-html-blob.d.ts +18 -0
  161. package/lib/archive/decode-html-blob.js +31 -0
  162. package/lib/archive/derive-lineage-from-parent.d.ts +37 -0
  163. package/lib/archive/derive-lineage-from-parent.js +42 -0
  164. package/lib/archive/drop-legacy-tables.d.ts +45 -0
  165. package/lib/archive/drop-legacy-tables.js +56 -0
  166. package/lib/archive/filesystem/rename.js +1 -1
  167. package/lib/archive/get-failed-page-messages.d.ts +44 -0
  168. package/lib/archive/get-failed-page-messages.js +132 -0
  169. package/lib/archive/init-schema.d.ts +35 -39
  170. package/lib/archive/init-schema.js +111 -320
  171. package/lib/archive/is-inventory-source.d.ts +21 -0
  172. package/lib/archive/is-inventory-source.js +22 -0
  173. package/lib/archive/limited-page-ids.d.ts +2 -1
  174. package/lib/archive/limited-page-ids.js +5 -4
  175. package/lib/archive/meta/assert-compatible-version.d.ts +24 -3
  176. package/lib/archive/meta/assert-compatible-version.js +24 -3
  177. package/lib/archive/meta/types.d.ts +87 -1
  178. package/lib/archive/meta/types.js +34 -2
  179. package/lib/archive/migrate-entity-tables.d.ts +45 -0
  180. package/lib/archive/migrate-entity-tables.js +56 -0
  181. package/lib/archive/migrate-ref-tables.d.ts +25 -0
  182. package/lib/archive/migrate-ref-tables.js +38 -0
  183. package/lib/archive/page-meta-column-maps.d.ts +32 -0
  184. package/lib/archive/page-meta-column-maps.js +43 -0
  185. package/lib/archive/page.d.ts +6 -6
  186. package/lib/archive/page.js +5 -5
  187. package/lib/archive/peek-archive-lock.d.ts +2 -2
  188. package/lib/archive/peek-archive-lock.js +2 -2
  189. package/lib/archive/populate-entity-tables/collapse-anchor-rows.d.ts +41 -0
  190. package/lib/archive/populate-entity-tables/collapse-anchor-rows.js +87 -0
  191. package/lib/archive/populate-entity-tables/derive-dom-path.d.ts +35 -0
  192. package/lib/archive/populate-entity-tables/derive-dom-path.js +72 -0
  193. package/lib/archive/populate-entity-tables/is-blob-ref-value.d.ts +16 -0
  194. package/lib/archive/populate-entity-tables/is-blob-ref-value.js +19 -0
  195. package/lib/archive/populate-entity-tables/match-images-to-dom-paths.d.ts +66 -0
  196. package/lib/archive/populate-entity-tables/match-images-to-dom-paths.js +96 -0
  197. package/lib/archive/populate-entity-tables/populate-anchor-edges.d.ts +33 -0
  198. package/lib/archive/populate-entity-tables/populate-anchor-edges.js +153 -0
  199. package/lib/archive/populate-entity-tables/populate-content-items.d.ts +40 -0
  200. package/lib/archive/populate-entity-tables/populate-content-items.js +141 -0
  201. package/lib/archive/populate-entity-tables/populate-entities.d.ts +81 -0
  202. package/lib/archive/populate-entity-tables/populate-entities.js +111 -0
  203. package/lib/archive/populate-entity-tables/populate-image-items.d.ts +91 -0
  204. package/lib/archive/populate-entity-tables/populate-image-items.js +223 -0
  205. package/lib/archive/populate-entity-tables/populate-page-meta.d.ts +33 -0
  206. package/lib/archive/populate-entity-tables/populate-page-meta.js +267 -0
  207. package/lib/archive/populate-entity-tables/populate-resource-items.d.ts +22 -0
  208. package/lib/archive/populate-entity-tables/populate-resource-items.js +114 -0
  209. package/lib/archive/populate-entity-tables/populate-resource-ref-edges.d.ts +31 -0
  210. package/lib/archive/populate-entity-tables/populate-resource-ref-edges.js +33 -0
  211. package/lib/archive/populate-entity-tables/resolve-blob-refs.d.ts +31 -0
  212. package/lib/archive/populate-entity-tables/resolve-blob-refs.js +100 -0
  213. package/lib/archive/populate-entity-tables/resolve-content-type-refs.d.ts +22 -0
  214. package/lib/archive/populate-entity-tables/resolve-content-type-refs.js +27 -0
  215. package/lib/archive/populate-entity-tables/resolve-header-sets.d.ts +49 -0
  216. package/lib/archive/populate-entity-tables/resolve-header-sets.js +122 -0
  217. package/lib/archive/populate-entity-tables/resolve-json-refs.d.ts +25 -0
  218. package/lib/archive/populate-entity-tables/resolve-json-refs.js +67 -0
  219. package/lib/archive/populate-entity-tables/resolve-text-refs.d.ts +30 -0
  220. package/lib/archive/populate-entity-tables/resolve-text-refs.js +61 -0
  221. package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.d.ts +21 -0
  222. package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.js +27 -0
  223. package/lib/archive/populate-entity-tables/resolve-url-refs.d.ts +33 -0
  224. package/lib/archive/populate-entity-tables/resolve-url-refs.js +60 -0
  225. package/lib/archive/populate-entity-tables/test-utils/count-rows.d.ts +17 -0
  226. package/lib/archive/populate-entity-tables/test-utils/count-rows.js +20 -0
  227. package/lib/archive/populate-entity-tables/test-utils/seed-content-items.d.ts +25 -0
  228. package/lib/archive/populate-entity-tables/test-utils/seed-content-items.js +42 -0
  229. package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.d.ts +23 -0
  230. package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.js +178 -0
  231. package/lib/archive/populate-entity-tables/types.d.ts +157 -0
  232. package/lib/archive/populate-entity-tables/types.js +12 -0
  233. package/lib/archive/populate-entity-tables/upsert-text-refs.d.ts +38 -0
  234. package/lib/archive/populate-entity-tables/upsert-text-refs.js +78 -0
  235. package/lib/archive/populate-ref-tables/classify-content-type.d.ts +16 -0
  236. package/lib/archive/populate-ref-tables/classify-content-type.js +52 -0
  237. package/lib/archive/populate-ref-tables/compute-content-hash.d.ts +22 -0
  238. package/lib/archive/populate-ref-tables/compute-content-hash.js +26 -0
  239. package/lib/archive/populate-ref-tables/compute-header-flags.d.ts +16 -0
  240. package/lib/archive/populate-ref-tables/compute-header-flags.js +70 -0
  241. package/lib/archive/populate-ref-tables/content-type-rules.d.ts +38 -0
  242. package/lib/archive/populate-ref-tables/content-type-rules.js +133 -0
  243. package/lib/archive/populate-ref-tables/create-header-table-caches.d.ts +25 -0
  244. package/lib/archive/populate-ref-tables/create-header-table-caches.js +49 -0
  245. package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.d.ts +15 -0
  246. package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.js +15 -0
  247. package/lib/archive/populate-ref-tables/decode-data-uri.d.ts +21 -0
  248. package/lib/archive/populate-ref-tables/decode-data-uri.js +126 -0
  249. package/lib/archive/populate-ref-tables/decompose-header-set.d.ts +29 -0
  250. package/lib/archive/populate-ref-tables/decompose-header-set.js +157 -0
  251. package/lib/archive/populate-ref-tables/decompose-url.d.ts +25 -0
  252. package/lib/archive/populate-ref-tables/decompose-url.js +70 -0
  253. package/lib/archive/populate-ref-tables/header-stability.d.ts +19 -0
  254. package/lib/archive/populate-ref-tables/header-stability.js +22 -0
  255. package/lib/archive/populate-ref-tables/header-value-cache-key.d.ts +17 -0
  256. package/lib/archive/populate-ref-tables/header-value-cache-key.js +19 -0
  257. package/lib/archive/populate-ref-tables/normalize-mime.d.ts +24 -0
  258. package/lib/archive/populate-ref-tables/normalize-mime.js +36 -0
  259. package/lib/archive/populate-ref-tables/populate-blob-refs.d.ts +38 -0
  260. package/lib/archive/populate-ref-tables/populate-blob-refs.js +134 -0
  261. package/lib/archive/populate-ref-tables/populate-content-type-refs.d.ts +27 -0
  262. package/lib/archive/populate-ref-tables/populate-content-type-refs.js +70 -0
  263. package/lib/archive/populate-ref-tables/populate-header-tables.d.ts +35 -0
  264. package/lib/archive/populate-ref-tables/populate-header-tables.js +80 -0
  265. package/lib/archive/populate-ref-tables/populate-json-refs.d.ts +29 -0
  266. package/lib/archive/populate-ref-tables/populate-json-refs.js +101 -0
  267. package/lib/archive/populate-ref-tables/populate-refs.d.ts +51 -0
  268. package/lib/archive/populate-ref-tables/populate-refs.js +62 -0
  269. package/lib/archive/populate-ref-tables/populate-text-refs.d.ts +32 -0
  270. package/lib/archive/populate-ref-tables/populate-text-refs.js +133 -0
  271. package/lib/archive/populate-ref-tables/populate-url-refs.d.ts +28 -0
  272. package/lib/archive/populate-ref-tables/populate-url-refs.js +148 -0
  273. package/lib/archive/populate-ref-tables/test-utils/count-rows.d.ts +15 -0
  274. package/lib/archive/populate-ref-tables/test-utils/count-rows.js +17 -0
  275. package/lib/archive/populate-ref-tables/types.d.ts +197 -0
  276. package/lib/archive/populate-ref-tables/types.js +7 -0
  277. package/lib/archive/populate-ref-tables/upsert-one-header-set.d.ts +34 -0
  278. package/lib/archive/populate-ref-tables/upsert-one-header-set.js +208 -0
  279. package/lib/archive/populate-ref-tables/volatile-header-names.d.ts +20 -0
  280. package/lib/archive/populate-ref-tables/volatile-header-names.js +33 -0
  281. package/lib/archive/redirect-table.d.ts +4 -2
  282. package/lib/archive/redirect-table.js +15 -10
  283. package/lib/archive/resolve-redirect-chain.d.ts +3 -3
  284. package/lib/archive/resolve-redirect-chain.js +2 -2
  285. package/lib/archive/resource.d.ts +1 -1
  286. package/lib/archive/retarget-legacy-fk-tables.d.ts +47 -0
  287. package/lib/archive/retarget-legacy-fk-tables.js +107 -0
  288. package/lib/archive/test-utils/fk-parent-tables.d.ts +15 -0
  289. package/lib/archive/test-utils/fk-parent-tables.js +19 -0
  290. package/lib/archive/test-utils/seed-content-item.d.ts +35 -0
  291. package/lib/archive/test-utils/seed-content-item.js +42 -0
  292. package/lib/archive/test-utils/setup-legacy-fk-db.d.ts +33 -0
  293. package/lib/archive/test-utils/setup-legacy-fk-db.js +270 -0
  294. package/lib/archive/types.d.ts +151 -15
  295. package/lib/archive/verify-migration/capture-rejection.d.ts +24 -0
  296. package/lib/archive/verify-migration/capture-rejection.js +31 -0
  297. package/lib/archive/verify-migration/check-anchor-edges-count.d.ts +34 -0
  298. package/lib/archive/verify-migration/check-anchor-edges-count.js +72 -0
  299. package/lib/archive/verify-migration/check-anchor-edges-sum.d.ts +13 -0
  300. package/lib/archive/verify-migration/check-anchor-edges-sum.js +27 -0
  301. package/lib/archive/verify-migration/check-content-items-count.d.ts +16 -0
  302. package/lib/archive/verify-migration/check-content-items-count.js +30 -0
  303. package/lib/archive/verify-migration/check-content-type-preservation.d.ts +22 -0
  304. package/lib/archive/verify-migration/check-content-type-preservation.js +40 -0
  305. package/lib/archive/verify-migration/check-foreign-key-integrity.d.ts +31 -0
  306. package/lib/archive/verify-migration/check-foreign-key-integrity.js +47 -0
  307. package/lib/archive/verify-migration/check-image-items-count.d.ts +12 -0
  308. package/lib/archive/verify-migration/check-image-items-count.js +26 -0
  309. package/lib/archive/verify-migration/check-page-meta-count.d.ts +15 -0
  310. package/lib/archive/verify-migration/check-page-meta-count.js +31 -0
  311. package/lib/archive/verify-migration/check-reader-parity.d.ts +23 -0
  312. package/lib/archive/verify-migration/check-reader-parity.js +211 -0
  313. package/lib/archive/verify-migration/check-resource-items-count.d.ts +17 -0
  314. package/lib/archive/verify-migration/check-resource-items-count.js +33 -0
  315. package/lib/archive/verify-migration/check-url-round-trip.d.ts +43 -0
  316. package/lib/archive/verify-migration/check-url-round-trip.js +112 -0
  317. package/lib/archive/verify-migration/types.d.ts +70 -0
  318. package/lib/archive/verify-migration/types.js +63 -0
  319. package/lib/archive/verify-migration/verify-migration.d.ts +41 -0
  320. package/lib/archive/verify-migration/verify-migration.js +120 -0
  321. package/lib/classify-error-kind.d.ts +19 -0
  322. package/lib/classify-error-kind.js +122 -0
  323. package/lib/crawler/build-js-redirect-edge.d.ts +68 -0
  324. package/lib/crawler/build-js-redirect-edge.js +57 -0
  325. package/lib/crawler/build-redirect-event.d.ts +24 -0
  326. package/lib/crawler/build-redirect-event.js +28 -0
  327. package/lib/crawler/capture-image-dom-paths.d.ts +33 -0
  328. package/lib/crawler/capture-image-dom-paths.js +39 -0
  329. package/lib/crawler/clear-dns-burned-host-cache.d.ts +6 -0
  330. package/lib/crawler/clear-dns-burned-host-cache.js +11 -0
  331. package/lib/crawler/collect-image-dom-paths.d.ts +23 -0
  332. package/lib/crawler/collect-image-dom-paths.js +64 -0
  333. package/lib/crawler/crawler.d.ts +22 -1
  334. package/lib/crawler/crawler.js +679 -117
  335. package/lib/crawler/derive-js-redirect-target.d.ts +68 -0
  336. package/lib/crawler/derive-js-redirect-target.js +129 -0
  337. package/lib/crawler/derive-resource-source.d.ts +25 -15
  338. package/lib/crawler/derive-resource-source.js +28 -17
  339. package/lib/crawler/dns-burned-host-cache.d.ts +26 -0
  340. package/lib/crawler/dns-burned-host-cache.js +25 -0
  341. package/lib/crawler/dns-burned-host-short-circuit-counter.d.ts +13 -0
  342. package/lib/crawler/dns-burned-host-short-circuit-counter.js +11 -0
  343. package/lib/crawler/fetch-destination.d.ts +12 -4
  344. package/lib/crawler/fetch-destination.js +94 -16
  345. package/lib/crawler/inject-scope-auth.d.ts +1 -1
  346. package/lib/crawler/inject-scope-auth.js +1 -1
  347. package/lib/crawler/is-js-redirect-error-shape.d.ts +40 -0
  348. package/lib/crawler/is-js-redirect-error-shape.js +53 -0
  349. package/lib/crawler/is-puppeteer-fallback-candidate.d.ts +16 -0
  350. package/lib/crawler/is-puppeteer-fallback-candidate.js +63 -0
  351. package/lib/crawler/link-list.d.ts +21 -1
  352. package/lib/crawler/link-list.js +23 -3
  353. package/lib/crawler/normalize-content-type.d.ts +1 -1
  354. package/lib/crawler/normalize-content-type.js +1 -1
  355. package/lib/crawler/plan-sub-resource-emits.d.ts +63 -0
  356. package/lib/crawler/plan-sub-resource-emits.js +44 -0
  357. package/lib/crawler/preload-short-circuit-error.d.ts +22 -0
  358. package/lib/crawler/preload-short-circuit-error.js +25 -0
  359. package/lib/crawler/should-burn-host.d.ts +78 -0
  360. package/lib/crawler/should-burn-host.js +61 -0
  361. package/lib/crawler/should-get-fallback-on-head-failure.d.ts +38 -0
  362. package/lib/crawler/should-get-fallback-on-head-failure.js +46 -0
  363. package/lib/crawler/types.d.ts +108 -1
  364. package/lib/crawler-orchestrator.d.ts +22 -3
  365. package/lib/crawler-orchestrator.js +312 -73
  366. package/lib/crawler.d.ts +15 -2
  367. package/lib/crawler.js +24 -1
  368. package/lib/permanent-error-kinds.d.ts +43 -0
  369. package/lib/permanent-error-kinds.js +48 -0
  370. package/lib/types.d.ts +84 -0
  371. package/lib/utils/compute-file-sha256.d.ts +24 -0
  372. package/lib/utils/compute-file-sha256.js +56 -0
  373. package/lib/utils/error/emit-error-with-retry.d.ts +40 -0
  374. package/lib/utils/error/emit-error-with-retry.js +44 -0
  375. package/lib/utils/error/emit-error.d.ts +39 -0
  376. package/lib/utils/error/emit-error.js +41 -0
  377. package/package.json +12 -12
  378. package/lib/archive/migrate-crawl-errors.d.ts +0 -20
  379. package/lib/archive/migrate-crawl-errors.js +0 -38
  380. package/lib/archive/migrate-html-blob-tables.d.ts +0 -24
  381. package/lib/archive/migrate-html-blob-tables.js +0 -53
  382. package/lib/archive/migrate-page-errors.d.ts +0 -16
  383. package/lib/archive/migrate-page-errors.js +0 -35
  384. package/lib/archive/migrate-pages-resources-source.d.ts +0 -16
  385. package/lib/archive/migrate-pages-resources-source.js +0 -46
  386. package/lib/utils/error/error-emitter.d.ts +0 -18
  387. package/lib/utils/error/error-emitter.js +0 -29
@@ -0,0 +1,33 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates `page_meta` from `pages WHERE scraped = 1` (issue #193).
5
+ *
6
+ * Pages that were never scraped contribute no meta rows — they have no rendered title,
7
+ * description, or JSON-LD to preserve, so filtering at the SELECT keeps
8
+ * the reader working set narrow and matches the migration acceptance check
9
+ * `count(*) FROM page_meta = count(*) FROM pages WHERE scraped = 1`.
10
+ *
11
+ * Per chunk:
12
+ *
13
+ * 1. **Keyset-paginate** `pages.id > cursor AND scraped = 1`.
14
+ * 2. **Batch-resolve** all text / URL / JSON ref ids for every value in
15
+ * the chunk — three resolvers, one round-trip per ref table.
16
+ * 3. **Bulk INSERT** with `page_id = pages.id`. `page_id` is both PK and
17
+ * FK on `content_items(id)`; `populateContentItems` must have already
18
+ * inserted the corresponding `content_items` row for the FK to be
19
+ * valid at COMMIT time.
20
+ *
21
+ * `INSERT OR IGNORE` on the `page_id` PK makes the step idempotent so
22
+ * partial-failure re-runs are safe.
23
+ * @param trx - Knex instance or transaction connected to the archive DB.
24
+ * @param onProgress - Optional sink for periodic progress lines (one per
25
+ * ~5% of `pages WHERE scraped = 1` scanned); see
26
+ * {@link ../create-progress-reporter.ts}.
27
+ * @example
28
+ * await knex.transaction(async (trx) => {
29
+ * await populateContentItems(trx);
30
+ * await populatePageMeta(trx);
31
+ * });
32
+ */
33
+ export declare function populatePageMeta(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,267 @@
1
+ import { createProgressReporter } from '../create-progress-reporter.js';
2
+ import { PAGE_META_COLUMN_MAPS } from '../page-meta-column-maps.js';
3
+ import { DATA_URI_URL_REFS_LIMIT } from '../populate-ref-tables/data-uri-url-refs-limit.js';
4
+ import { resolveJsonRefs } from './resolve-json-refs.js';
5
+ import { resolveTextRefs } from './resolve-text-refs.js';
6
+ import { resolveUrlRefs } from './resolve-url-refs.js';
7
+ /**
8
+ * Rows scanned per keyset-paginated `SELECT` chunk against
9
+ * `pages WHERE scraped = 1`. The row width here is dominated by long
10
+ * text columns (`meta_extras` JSON, `description`, `twitter_description`)
11
+ * so 400 rows caps peak chunk memory at ≈ 40 MB on the reference
12
+ * archive.
13
+ */
14
+ const READ_CHUNK_SIZE = 400;
15
+ /**
16
+ * Rows sent per `INSERT INTO page_meta ... VALUES (...)` statement. Each
17
+ * row binds 47 params (see the column list below), so 200 rows =
18
+ * 9 400 params — safely under SQLite's default variable limit.
19
+ */
20
+ const INSERT_CHUNK_SIZE = 200;
21
+ /**
22
+ * Populates `page_meta` from `pages WHERE scraped = 1` (issue #193).
23
+ *
24
+ * Pages that were never scraped contribute no meta rows — they have no rendered title,
25
+ * description, or JSON-LD to preserve, so filtering at the SELECT keeps
26
+ * the reader working set narrow and matches the migration acceptance check
27
+ * `count(*) FROM page_meta = count(*) FROM pages WHERE scraped = 1`.
28
+ *
29
+ * Per chunk:
30
+ *
31
+ * 1. **Keyset-paginate** `pages.id > cursor AND scraped = 1`.
32
+ * 2. **Batch-resolve** all text / URL / JSON ref ids for every value in
33
+ * the chunk — three resolvers, one round-trip per ref table.
34
+ * 3. **Bulk INSERT** with `page_id = pages.id`. `page_id` is both PK and
35
+ * FK on `content_items(id)`; `populateContentItems` must have already
36
+ * inserted the corresponding `content_items` row for the FK to be
37
+ * valid at COMMIT time.
38
+ *
39
+ * `INSERT OR IGNORE` on the `page_id` PK makes the step idempotent so
40
+ * partial-failure re-runs are safe.
41
+ * @param trx - Knex instance or transaction connected to the archive DB.
42
+ * @param onProgress - Optional sink for periodic progress lines (one per
43
+ * ~5% of `pages WHERE scraped = 1` scanned); see
44
+ * {@link ../create-progress-reporter.ts}.
45
+ * @example
46
+ * await knex.transaction(async (trx) => {
47
+ * await populateContentItems(trx);
48
+ * await populatePageMeta(trx);
49
+ * });
50
+ */
51
+ export async function populatePageMeta(trx, onProgress) {
52
+ const textColumns = PAGE_META_COLUMN_MAPS.text.map((entry) => entry.source);
53
+ const urlColumns = PAGE_META_COLUMN_MAPS.url.map((entry) => entry.source);
54
+ const plainColumns = [
55
+ 'id',
56
+ 'lang',
57
+ 'dir',
58
+ 'charset',
59
+ 'baseHref',
60
+ 'viewport_raw',
61
+ 'themeColor',
62
+ 'applicationName',
63
+ 'author',
64
+ 'generator',
65
+ 'publisher',
66
+ 'robots_noindex',
67
+ 'robots_nofollow',
68
+ 'robots_noarchive',
69
+ 'robots_noimageindex',
70
+ 'googlebot',
71
+ 'og_type',
72
+ 'og_site_name',
73
+ 'og_image_alt',
74
+ 'og_image_width',
75
+ 'og_image_height',
76
+ 'og_locale',
77
+ 'og_article_published_time',
78
+ 'og_article_modified_time',
79
+ 'twitter_card',
80
+ 'twitter_site',
81
+ 'twitter_creator',
82
+ 'fb_app_id',
83
+ 'verification_google',
84
+ 'formatDetection_telephone',
85
+ 'tag_count',
86
+ 'jsonld_count',
87
+ 'tags_providers_csv',
88
+ 'meta_extras',
89
+ ];
90
+ const countRows = await trx('pages').where('scraped', true).count({ n: '*' });
91
+ const total = Number(countRows[0]?.n ?? 0);
92
+ const report = createProgressReporter('page_meta (pages)', total, onProgress);
93
+ let processed = 0;
94
+ let cursor = 0;
95
+ while (true) {
96
+ const rows = await trx('pages')
97
+ .select(...plainColumns, ...textColumns, ...urlColumns)
98
+ .where('id', '>', cursor)
99
+ .andWhere('scraped', true)
100
+ .orderBy('id', 'asc')
101
+ .limit(READ_CHUNK_SIZE);
102
+ if (rows.length === 0) {
103
+ break;
104
+ }
105
+ cursor = rows.at(-1).id;
106
+ processed += rows.length;
107
+ report(processed);
108
+ const texts = new Set();
109
+ const urls = new Set();
110
+ const jsonStrings = new Set();
111
+ for (const row of rows) {
112
+ for (const column of textColumns) {
113
+ const value = row[column];
114
+ if (typeof value === 'string' && value !== '') {
115
+ texts.add(value);
116
+ }
117
+ }
118
+ for (const column of urlColumns) {
119
+ const value = row[column];
120
+ if (typeof value === 'string' && value !== '' && !isLargeDataUri(value)) {
121
+ urls.add(value);
122
+ }
123
+ }
124
+ const metaExtras = row.meta_extras;
125
+ if (typeof metaExtras === 'string' && metaExtras !== '') {
126
+ jsonStrings.add(metaExtras);
127
+ }
128
+ }
129
+ const textIds = await resolveTextRefs(trx, texts);
130
+ const urlIds = await resolveUrlRefs(trx, urls);
131
+ const jsonIds = await resolveJsonRefs(trx, jsonStrings);
132
+ const inserts = rows.map((row) => {
133
+ const rowId = row.id;
134
+ const insert = {
135
+ page_id: rowId,
136
+ lang: row.lang ?? null,
137
+ dir: row.dir ?? null,
138
+ charset: row.charset ?? null,
139
+ base_href: row.baseHref ?? null,
140
+ viewport_raw: row.viewport_raw ?? null,
141
+ theme_color: row.themeColor ?? null,
142
+ application_name: row.applicationName ?? null,
143
+ author: row.author ?? null,
144
+ generator: row.generator ?? null,
145
+ publisher: row.publisher ?? null,
146
+ robots_noindex: row.robots_noindex ?? null,
147
+ robots_nofollow: row.robots_nofollow ?? null,
148
+ robots_noarchive: row.robots_noarchive ?? null,
149
+ robots_noimageindex: row.robots_noimageindex ?? null,
150
+ googlebot: row.googlebot ?? null,
151
+ og_type: row.og_type ?? null,
152
+ og_site_name: row.og_site_name ?? null,
153
+ og_image_alt: row.og_image_alt ?? null,
154
+ og_image_width: row.og_image_width ?? null,
155
+ og_image_height: row.og_image_height ?? null,
156
+ og_locale: row.og_locale ?? null,
157
+ og_article_published_time: row.og_article_published_time ?? null,
158
+ og_article_modified_time: row.og_article_modified_time ?? null,
159
+ twitter_card: row.twitter_card ?? null,
160
+ twitter_site: row.twitter_site ?? null,
161
+ twitter_creator: row.twitter_creator ?? null,
162
+ fb_app_id: row.fb_app_id ?? null,
163
+ verification_google: row.verification_google ?? null,
164
+ format_detection_telephone: row.formatDetection_telephone ?? null,
165
+ tag_count: row.tag_count ?? null,
166
+ jsonld_count: row.jsonld_count ?? null,
167
+ tags_providers_csv: row.tags_providers_csv ?? null,
168
+ meta_extras_json_id: resolveOptionalJsonId(row.meta_extras, jsonIds, rowId),
169
+ };
170
+ for (const { source, target } of PAGE_META_COLUMN_MAPS.text) {
171
+ insert[target] = resolveOptionalTextId(row[source], textIds, rowId, source);
172
+ }
173
+ for (const { source, target } of PAGE_META_COLUMN_MAPS.url) {
174
+ insert[target] = resolveOptionalUrlId(row[source], urlIds, rowId, source);
175
+ }
176
+ return insert;
177
+ });
178
+ for (let index = 0; index < inserts.length; index += INSERT_CHUNK_SIZE) {
179
+ const chunk = inserts.slice(index, index + INSERT_CHUNK_SIZE);
180
+ await trx('page_meta').insert(chunk).onConflict('page_id').ignore();
181
+ }
182
+ }
183
+ }
184
+ /**
185
+ * Returns `true` when `value` is a `data:` URI larger than the routing
186
+ * threshold — i.e. one that the `url_refs` populate
187
+ * (`populate-ref-tables/populate-url-refs.ts`) sent to `blob_refs` instead
188
+ * of `url_refs`. `page_meta` deliberately has no `*_blob_id` companion
189
+ * columns for its URL slots, so we skip these values from
190
+ * the `url_refs` lookup rather than issue a doomed `WHERE url IN (?)`
191
+ * that would burn a chunk slot per multi-KB URI. The resulting
192
+ * `*_url_id` is null with a `console.warn` breadcrumb; the operator
193
+ * can then decide whether the archive needs a schema extension or the
194
+ * raw data warrants normalisation.
195
+ * @param value - Raw URL column value.
196
+ */
197
+ function isLargeDataUri(value) {
198
+ return value.startsWith('data:') && value.length > DATA_URI_URL_REFS_LIMIT;
199
+ }
200
+ /**
201
+ * Resolves `text_refs.id` for a `page_meta.<name>_text_id` slot or
202
+ * throws when a non-empty source value has no matching `text_refs` row
203
+ * (parity with `populateContentItems`' `url_id` throw — silent NULL
204
+ * corruption would still let the count-based acceptance invariant pass
205
+ * while individual `page_meta` rows lose their meta text).
206
+ * @param value - Raw column value from the source `pages` row.
207
+ * @param textIds - `text → text_refs.id` map batch-resolved for the
208
+ * current chunk (see {@link ./resolve-text-refs.ts}).
209
+ * @param pageId - Owning page id (for the error message).
210
+ * @param column - Source column name (for the error message).
211
+ */
212
+ function resolveOptionalTextId(value, textIds, pageId, column) {
213
+ if (typeof value !== 'string' || value === '') {
214
+ return null;
215
+ }
216
+ const id = textIds.get(value);
217
+ if (id === undefined) {
218
+ throw new Error(`populatePageMeta: text_refs.id not resolved for page id=${pageId} column=${column} — populateTextRefs must run first`);
219
+ }
220
+ return id;
221
+ }
222
+ /**
223
+ * Resolves `url_refs.id` for a `page_meta.<name>_url_id` slot, throws
224
+ * on a missing lookup for a regular URL, and returns `null` (with a
225
+ * warning) for large data URIs that the `url_refs` populate routed to
226
+ * `blob_refs` — those cannot land in `page_meta` because the schema has
227
+ * no `*_blob_id` companion columns.
228
+ * @param value - Raw column value from the source `pages` row.
229
+ * @param urlIds - `url → url_refs.id` map batch-resolved for the
230
+ * current chunk (see {@link ./resolve-url-refs.ts}).
231
+ * @param pageId - Owning page id (for the error message).
232
+ * @param column - Source column name (for the error message).
233
+ */
234
+ function resolveOptionalUrlId(value, urlIds, pageId, column) {
235
+ if (typeof value !== 'string' || value === '') {
236
+ return null;
237
+ }
238
+ if (isLargeDataUri(value)) {
239
+ // eslint-disable-next-line no-console
240
+ console.warn(`populatePageMeta: dropping large data URI in page id=${pageId} column=${column} (page_meta has no *_blob_id companion for URL columns)`);
241
+ return null;
242
+ }
243
+ const id = urlIds.get(value);
244
+ if (id === undefined) {
245
+ throw new Error(`populatePageMeta: url_refs.id not resolved for page id=${pageId} column=${column} — populateUrlRefs must run first`);
246
+ }
247
+ return id;
248
+ }
249
+ /**
250
+ * Resolves `json_refs.id` for `page_meta.meta_extras_json_id` or throws
251
+ * when the source `meta_extras` string has no matching `json_refs` row
252
+ * (parity with the text/url branches above).
253
+ * @param value - Raw `meta_extras` value from the source `pages` row.
254
+ * @param jsonIds - `JSON string → json_refs.id` map batch-resolved for
255
+ * the current chunk (see {@link ./resolve-json-refs.ts}).
256
+ * @param pageId - Owning page id (for the error message).
257
+ */
258
+ function resolveOptionalJsonId(value, jsonIds, pageId) {
259
+ if (typeof value !== 'string' || value === '') {
260
+ return null;
261
+ }
262
+ const id = jsonIds.get(value);
263
+ if (id === undefined) {
264
+ throw new Error(`populatePageMeta: json_refs.id not resolved for page id=${pageId} column=meta_extras — populateJsonRefs must run first`);
265
+ }
266
+ return id;
267
+ }
@@ -0,0 +1,22 @@
1
+ import type { ProgressCallback } from '../create-progress-reporter.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Populates `resource_items` from `resources` (issue #193).
5
+ *
6
+ * Structurally analogous to {@link ./populate-content-items.ts}: for each
7
+ * `resources` chunk, batch-resolve `url_refs.id`, `content_type_refs.id`,
8
+ * and `header_sets.id`, then bulk-INSERT with explicit `id = resources.id`.
9
+ * Reusing the legacy PK preserves the `resources-referrers.resourceId`
10
+ * FK reference (which `populateResourceRefEdges` later carries over as
11
+ * `resource_ref_edges.resource_id`) without any per-row UPDATE.
12
+ *
13
+ * `INSERT OR IGNORE` on `id` makes the step idempotent.
14
+ * @param trx - Knex instance or transaction connected to the archive DB.
15
+ * @param onProgress - Optional sink for periodic progress lines (one per
16
+ * ~5% of `resources` scanned); see {@link ../create-progress-reporter.ts}.
17
+ * @example
18
+ * await knex.transaction(async (trx) => {
19
+ * await populateResourceItems(trx);
20
+ * });
21
+ */
22
+ export declare function populateResourceItems(trx: Knex, onProgress?: ProgressCallback): Promise<void>;
@@ -0,0 +1,114 @@
1
+ import { createProgressReporter } from '../create-progress-reporter.js';
2
+ import { isBlobRefValue } from './is-blob-ref-value.js';
3
+ import { resolveBlobRefs } from './resolve-blob-refs.js';
4
+ import { loadContentTypeRefs } from './resolve-content-type-refs.js';
5
+ import { resolveHeaderSets } from './resolve-header-sets.js';
6
+ import { resolveUrlOrBlobFromMaps } from './resolve-url-or-blob-from-maps.js';
7
+ import { resolveUrlRefs } from './resolve-url-refs.js';
8
+ /**
9
+ * Rows scanned per keyset-paginated `SELECT` chunk against `resources`.
10
+ * `resources` rows are narrow (no meta columns) so 800 rows fits
11
+ * comfortably in a chunk without stressing memory. Bumping this higher
12
+ * would help throughput but risks pushing large `responseHeaders` JSON
13
+ * blobs past a healthy per-result-set size on archives with per-row
14
+ * multi-KB header payloads.
15
+ */
16
+ const READ_CHUNK_SIZE = 800;
17
+ /**
18
+ * Rows sent per `INSERT INTO resource_items ... VALUES (...)` statement.
19
+ * Each row binds 11 params (id + 10 columns), so 500 rows = 5 500 params
20
+ * — well under SQLite's default variable limit.
21
+ */
22
+ const INSERT_CHUNK_SIZE = 500;
23
+ /**
24
+ * Populates `resource_items` from `resources` (issue #193).
25
+ *
26
+ * Structurally analogous to {@link ./populate-content-items.ts}: for each
27
+ * `resources` chunk, batch-resolve `url_refs.id`, `content_type_refs.id`,
28
+ * and `header_sets.id`, then bulk-INSERT with explicit `id = resources.id`.
29
+ * Reusing the legacy PK preserves the `resources-referrers.resourceId`
30
+ * FK reference (which `populateResourceRefEdges` later carries over as
31
+ * `resource_ref_edges.resource_id`) without any per-row UPDATE.
32
+ *
33
+ * `INSERT OR IGNORE` on `id` makes the step idempotent.
34
+ * @param trx - Knex instance or transaction connected to the archive DB.
35
+ * @param onProgress - Optional sink for periodic progress lines (one per
36
+ * ~5% of `resources` scanned); see {@link ../create-progress-reporter.ts}.
37
+ * @example
38
+ * await knex.transaction(async (trx) => {
39
+ * await populateResourceItems(trx);
40
+ * });
41
+ */
42
+ export async function populateResourceItems(trx, onProgress) {
43
+ const contentTypeIds = await loadContentTypeRefs(trx);
44
+ const countRows = await trx('resources').count({ n: '*' });
45
+ const total = Number(countRows[0]?.n ?? 0);
46
+ const report = createProgressReporter('resource_items (resources)', total, onProgress);
47
+ let processed = 0;
48
+ let cursor = 0;
49
+ while (true) {
50
+ const rows = await trx('resources')
51
+ .select('id', 'url', 'isExternal', 'status', 'statusText', 'contentType', 'contentLength', 'responseHeaders', 'compress', 'cdn', 'source')
52
+ .where('id', '>', cursor)
53
+ .orderBy('id', 'asc')
54
+ .limit(READ_CHUNK_SIZE);
55
+ if (rows.length === 0) {
56
+ break;
57
+ }
58
+ cursor = rows.at(-1).id;
59
+ processed += rows.length;
60
+ report(processed);
61
+ const urls = new Set();
62
+ const dataUris = new Set();
63
+ const headerJsonStrings = new Set();
64
+ for (const row of rows) {
65
+ if (isBlobRefValue(row.url)) {
66
+ dataUris.add(row.url);
67
+ }
68
+ else {
69
+ urls.add(row.url);
70
+ }
71
+ if (typeof row.responseHeaders === 'string' && row.responseHeaders !== '') {
72
+ headerJsonStrings.add(row.responseHeaders);
73
+ }
74
+ }
75
+ const urlIds = await resolveUrlRefs(trx, urls);
76
+ const blobIds = await resolveBlobRefs(trx, dataUris);
77
+ const headerSetIds = await resolveHeaderSets(trx, headerJsonStrings);
78
+ const inserts = rows.map((row) => {
79
+ const slot = resolveUrlOrBlobFromMaps(row.url, urlIds, blobIds);
80
+ if (slot.url === null && slot.blob === null) {
81
+ throw new Error(`populateResourceItems: neither url_refs.id nor blob_refs.id resolved for resource id=${row.id} url=${row.url.slice(0, 80)} — populateUrlRefs/populateBlobRefs must run first`);
82
+ }
83
+ let contentTypeId = null;
84
+ if (row.contentType != null && row.contentType !== '') {
85
+ const resolved = contentTypeIds.get(row.contentType);
86
+ if (resolved === undefined) {
87
+ throw new Error(`populateResourceItems: content_type_refs.id not resolved for resource id=${row.id} contentType=${row.contentType} — populateContentTypeRefs must run first`);
88
+ }
89
+ contentTypeId = resolved;
90
+ }
91
+ const headerSetId = typeof row.responseHeaders === 'string' && row.responseHeaders !== ''
92
+ ? (headerSetIds.get(row.responseHeaders) ?? null)
93
+ : null;
94
+ return {
95
+ id: row.id,
96
+ url_id: slot.url,
97
+ url_blob_id: slot.blob,
98
+ is_external: row.isExternal == null ? 0 : row.isExternal ? 1 : 0,
99
+ status: row.status ?? null,
100
+ status_text: row.statusText ?? null,
101
+ content_type_id: contentTypeId,
102
+ content_length: row.contentLength ?? null,
103
+ header_set_id: headerSetId,
104
+ compress: row.compress ?? null,
105
+ cdn: row.cdn ?? null,
106
+ source: row.source,
107
+ };
108
+ });
109
+ for (let index = 0; index < inserts.length; index += INSERT_CHUNK_SIZE) {
110
+ const chunk = inserts.slice(index, index + INSERT_CHUNK_SIZE);
111
+ await trx('resource_items').insert(chunk).onConflict('id').ignore();
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,31 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Populates `resource_ref_edges` from `resources-referrers`
4
+ * (issue #193).
5
+ *
6
+ * The transformation is a **direct SQL `INSERT ... SELECT`** — no ref
7
+ * lookups, no per-row JS work. Legacy `resources-referrers` already
8
+ * enforces `UNIQUE(resourceId, pageId)` (see `init-schema.ts`), so every
9
+ * source row maps 1:1 to a distinct `resource_ref_edges` PK; every
10
+ * `count` starts at `1` because the legacy shape observed each
11
+ * (resource, page) pair exactly once.
12
+ *
13
+ * `INSERT OR IGNORE` on the `(resource_id, page_id)` PK is redundant
14
+ * with the legacy unique constraint on the source but present anyway to
15
+ * make partial-failure re-runs safe.
16
+ *
17
+ * The PKs on both `resource_items.id` and `content_items.id` were
18
+ * preserved from `resources.id` / `pages.id`, so no per-row translation
19
+ * is required — the FKs `resource_items(id)` and `content_items(id)`
20
+ * declared in `resource_ref_edges` are already satisfied for every
21
+ * source row by `populateContentItems` / `populateResourceItems`, which
22
+ * run before this function in `populateEntityTables`.
23
+ * @param trx - Knex instance or transaction connected to the archive DB.
24
+ * @example
25
+ * await knex.transaction(async (trx) => {
26
+ * await populateResourceItems(trx);
27
+ * await populateContentItems(trx);
28
+ * await populateResourceRefEdges(trx);
29
+ * });
30
+ */
31
+ export declare function populateResourceRefEdges(trx: Knex): Promise<void>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Populates `resource_ref_edges` from `resources-referrers`
3
+ * (issue #193).
4
+ *
5
+ * The transformation is a **direct SQL `INSERT ... SELECT`** — no ref
6
+ * lookups, no per-row JS work. Legacy `resources-referrers` already
7
+ * enforces `UNIQUE(resourceId, pageId)` (see `init-schema.ts`), so every
8
+ * source row maps 1:1 to a distinct `resource_ref_edges` PK; every
9
+ * `count` starts at `1` because the legacy shape observed each
10
+ * (resource, page) pair exactly once.
11
+ *
12
+ * `INSERT OR IGNORE` on the `(resource_id, page_id)` PK is redundant
13
+ * with the legacy unique constraint on the source but present anyway to
14
+ * make partial-failure re-runs safe.
15
+ *
16
+ * The PKs on both `resource_items.id` and `content_items.id` were
17
+ * preserved from `resources.id` / `pages.id`, so no per-row translation
18
+ * is required — the FKs `resource_items(id)` and `content_items(id)`
19
+ * declared in `resource_ref_edges` are already satisfied for every
20
+ * source row by `populateContentItems` / `populateResourceItems`, which
21
+ * run before this function in `populateEntityTables`.
22
+ * @param trx - Knex instance or transaction connected to the archive DB.
23
+ * @example
24
+ * await knex.transaction(async (trx) => {
25
+ * await populateResourceItems(trx);
26
+ * await populateContentItems(trx);
27
+ * await populateResourceRefEdges(trx);
28
+ * });
29
+ */
30
+ export async function populateResourceRefEdges(trx) {
31
+ await trx.raw(`INSERT OR IGNORE INTO resource_ref_edges (resource_id, page_id, count)
32
+ SELECT resourceId, pageId, 1 FROM "resources-referrers"`);
33
+ }
@@ -0,0 +1,31 @@
1
+ import type { BlobRefIdMap } from './types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Batch-resolves `blob_refs.id` for a set of large data-URI values
5
+ * (issue #193).
6
+ *
7
+ * The routing rule matches {@link ../populate-ref-tables/populate-blob-refs.ts}:
8
+ * only `data:` URIs longer than {@link DATA_URI_URL_REFS_LIMIT} bytes
9
+ * land in `blob_refs`; smaller data URIs (and every regular URL) live
10
+ * in `url_refs` instead. Callers pass URL-column values verbatim; this
11
+ * function filters out anything that does not match the routing rule
12
+ * before hashing.
13
+ *
14
+ * Malformed data URIs that fail {@link ../populate-ref-tables/decode-data-uri.ts}
15
+ * are skipped silently — `populateBlobRefs` also skipped them (with a
16
+ * warning), so no matching row exists to resolve.
17
+ *
18
+ * Duplicate values in `values` are deduped internally so an image whose
19
+ * `src` and `currentSrc` share the same data URI only counts once.
20
+ * @param trx - Knex instance or transaction connected to the archive DB.
21
+ * @param values - Iterable of raw URL-column values that may or may not
22
+ * be large data URIs.
23
+ * @returns Map keyed by the raw URI string; missing entries indicate
24
+ * the value is not stored in `blob_refs` (either not a data URI at
25
+ * all, below the size threshold, malformed, or absent from the
26
+ * dictionary).
27
+ * @example
28
+ * const idMap = await resolveBlobRefs(trx, [longDataUri, 'https://…']);
29
+ * const blobId = idMap.get(longDataUri); // number | undefined
30
+ */
31
+ export declare function resolveBlobRefs(trx: Knex, values: Iterable<string>): Promise<BlobRefIdMap>;
@@ -0,0 +1,100 @@
1
+ import { computeContentHash } from '../populate-ref-tables/compute-content-hash.js';
2
+ import { DATA_URI_URL_REFS_LIMIT } from '../populate-ref-tables/data-uri-url-refs-limit.js';
3
+ import { decodeDataUri } from '../populate-ref-tables/decode-data-uri.js';
4
+ /**
5
+ * Rows sent per `SELECT ... WHERE hash IN (?, ...)` chunk. `blob_refs`
6
+ * cardinality is tiny in the reference archive (≈ 429 rows) so 200 per
7
+ * chunk covers most realistic uses in a single query.
8
+ */
9
+ const LOOKUP_CHUNK_SIZE = 200;
10
+ /**
11
+ * Batch-resolves `blob_refs.id` for a set of large data-URI values
12
+ * (issue #193).
13
+ *
14
+ * The routing rule matches {@link ../populate-ref-tables/populate-blob-refs.ts}:
15
+ * only `data:` URIs longer than {@link DATA_URI_URL_REFS_LIMIT} bytes
16
+ * land in `blob_refs`; smaller data URIs (and every regular URL) live
17
+ * in `url_refs` instead. Callers pass URL-column values verbatim; this
18
+ * function filters out anything that does not match the routing rule
19
+ * before hashing.
20
+ *
21
+ * Malformed data URIs that fail {@link ../populate-ref-tables/decode-data-uri.ts}
22
+ * are skipped silently — `populateBlobRefs` also skipped them (with a
23
+ * warning), so no matching row exists to resolve.
24
+ *
25
+ * Duplicate values in `values` are deduped internally so an image whose
26
+ * `src` and `currentSrc` share the same data URI only counts once.
27
+ * @param trx - Knex instance or transaction connected to the archive DB.
28
+ * @param values - Iterable of raw URL-column values that may or may not
29
+ * be large data URIs.
30
+ * @returns Map keyed by the raw URI string; missing entries indicate
31
+ * the value is not stored in `blob_refs` (either not a data URI at
32
+ * all, below the size threshold, malformed, or absent from the
33
+ * dictionary).
34
+ * @example
35
+ * const idMap = await resolveBlobRefs(trx, [longDataUri, 'https://…']);
36
+ * const blobId = idMap.get(longDataUri); // number | undefined
37
+ */
38
+ export async function resolveBlobRefs(trx, values) {
39
+ const distinct = new Set();
40
+ for (const value of values) {
41
+ if (typeof value !== 'string' || value === '') {
42
+ continue;
43
+ }
44
+ if (value.length <= DATA_URI_URL_REFS_LIMIT || !value.startsWith('data:')) {
45
+ continue;
46
+ }
47
+ distinct.add(value);
48
+ }
49
+ if (distinct.size === 0) {
50
+ return new Map();
51
+ }
52
+ const rawValues = [...distinct];
53
+ const hashByValue = new Map();
54
+ // `hashHexToValues` maps `hex(hash) → [raw URI strings that decoded to
55
+ // those bytes]`. Two distinct raw data-URI strings can decode to the
56
+ // same payload bytes (e.g. `data:image/png;base64,XXXX…` and
57
+ // `data:image/svg+xml;base64,XXXX…` when the underlying base64 is
58
+ // identical). `populateBlobRefs` dedups them into one row keyed by the
59
+ // payload hash, so both raw URIs must resolve to that shared id — a
60
+ // last-wins Map keyed by hash would drop the earlier variant, and
61
+ // downstream `image_items` writes would lose the blob reference.
62
+ const hashHexToValues = new Map();
63
+ for (const value of rawValues) {
64
+ const decoded = decodeDataUri(value);
65
+ if (decoded === null) {
66
+ continue;
67
+ }
68
+ const hash = computeContentHash(decoded.bytes);
69
+ hashByValue.set(value, hash);
70
+ const hex = hash.toString('hex');
71
+ const bucket = hashHexToValues.get(hex);
72
+ if (bucket === undefined) {
73
+ hashHexToValues.set(hex, [value]);
74
+ }
75
+ else {
76
+ bucket.push(value);
77
+ }
78
+ }
79
+ if (hashByValue.size === 0) {
80
+ return new Map();
81
+ }
82
+ const hashes = [...hashByValue.values()];
83
+ const result = new Map();
84
+ for (let index = 0; index < hashes.length; index += LOOKUP_CHUNK_SIZE) {
85
+ const chunkHashes = hashes.slice(index, index + LOOKUP_CHUNK_SIZE);
86
+ const rows = await trx('blob_refs')
87
+ .select('id', 'hash')
88
+ .whereIn('hash', chunkHashes);
89
+ for (const row of rows) {
90
+ const hex = Buffer.from(row.hash).toString('hex');
91
+ const values = hashHexToValues.get(hex);
92
+ if (values !== undefined) {
93
+ for (const value of values) {
94
+ result.set(value, row.id);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return result;
100
+ }
@@ -0,0 +1,22 @@
1
+ import type { ContentTypeRefIdMap } from './types.js';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Loads the entire `content_type_refs` dictionary into an in-process map
5
+ * keyed by the raw wire value (issue #193).
6
+ *
7
+ * Content-type cardinality is small in practice — the reference archive
8
+ * carries ≈ 400 distinct raw values across `pages` + `resources`, so
9
+ * loading everything into a `Map` costs ≈ 40 KB and eliminates every
10
+ * per-chunk round-trip. This is the same trade-off {@link
11
+ * ../populate-ref-tables/populate-header-tables.ts} makes for `header_name_refs`.
12
+ *
13
+ * Callers should invoke this once at the start of a 0.13 populate
14
+ * step (e.g. `populateContentItems`, `populateResourceItems`) and reuse
15
+ * the map for every chunk.
16
+ * @param trx - Knex instance or transaction connected to the archive DB.
17
+ * @returns Map keyed by `content_type_refs.raw`.
18
+ * @example
19
+ * const contentTypeIds = await loadContentTypeRefs(trx);
20
+ * const id = contentTypeIds.get('text/html; charset=utf-8'); // number | undefined
21
+ */
22
+ export declare function loadContentTypeRefs(trx: Knex): Promise<ContentTypeRefIdMap>;