@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
@@ -15,6 +15,14 @@
15
15
  * downstream consumers (e.g. `find-mismatches`) can compare against the
16
16
  * absolute page URL directly.
17
17
  * @see derive-flat-from-meta.ts
18
+ * @example
19
+ * // A `pages` row projected onto (a subset of) its flat meta columns:
20
+ * const meta: Partial<FlatPageMetaColumns> = {
21
+ * title: 'Home',
22
+ * canonical: 'https://example.com/',
23
+ * robots_noindex: 0,
24
+ * og_type: 'website',
25
+ * };
18
26
  */
19
27
  export interface FlatPageMetaColumns {
20
28
  lang: string | null;
@@ -70,6 +78,12 @@ export interface FlatPageMetaColumns {
70
78
  * `page_tags` / `page_jsonld` for the common "how many?" and "which
71
79
  * providers?" questions.
72
80
  * @see compute-page-denormalized.ts
81
+ * @example
82
+ * const denorm: PageDenormalizedColumns = {
83
+ * tag_count: 3,
84
+ * jsonld_count: 1,
85
+ * tags_providers_csv: 'Google Analytics,Google Tag Manager',
86
+ * };
73
87
  */
74
88
  export interface PageDenormalizedColumns {
75
89
  /** Total Wappalyzer tag entries for the page. */
@@ -86,6 +100,16 @@ export interface PageDenormalizedColumns {
86
100
  * `<script type="speculationrules">` (`kind = 'speculationrules'`) entries.
87
101
  * @see extract-tags-for-archive.ts (sibling for tags) and the table definition
88
102
  * in `archive/init-schema.ts`.
103
+ * @example
104
+ * const row: JsonLdRow = {
105
+ * id: 1,
106
+ * pageId: 42,
107
+ * kind: 'ld+json',
108
+ * type: 'Article',
109
+ * raw: '{"@type":"Article","headline":"Hello"}',
110
+ * parsed: { '@type': 'Article', headline: 'Hello' },
111
+ * parseError: null,
112
+ * };
89
113
  */
90
114
  export interface JsonLdRow {
91
115
  /** Auto-increment primary key. */
@@ -108,6 +132,15 @@ export interface JsonLdRow {
108
132
  *
109
133
  * Mirrors the row shape minus the auto-increment `id`. `parsed` is the raw
110
134
  * JSON value (the database layer JSON-stringifies it before write).
135
+ * @example
136
+ * const insert: JsonLdRowForInsert = {
137
+ * pageId: 42,
138
+ * kind: 'speculationrules',
139
+ * type: null,
140
+ * raw: '{"prerender":[]}',
141
+ * parsed: { prerender: [] },
142
+ * parseError: null,
143
+ * };
111
144
  */
112
145
  export type JsonLdRowForInsert = Omit<JsonLdRow, 'id'>;
113
146
  /**
@@ -115,6 +148,24 @@ export type JsonLdRowForInsert = Omit<JsonLdRow, 'id'>;
115
148
  *
116
149
  * Each row represents one detected Wappalyzer provider × external-id tuple for
117
150
  * one page. A page typically has 1–10 rows.
151
+ * @example
152
+ * const row: TagRow = {
153
+ * id: 1,
154
+ * pageId: 42,
155
+ * provider: 'Google Tag Manager',
156
+ * category: 'Tag managers',
157
+ * externalId: 'GTM-XXXX',
158
+ * version: null,
159
+ * confidence: 100,
160
+ * categories: ['Tag managers'],
161
+ * sources: [
162
+ * {
163
+ * type: 'script-src',
164
+ * src: 'https://www.googletagmanager.com/gtm.js',
165
+ * location: 'head',
166
+ * },
167
+ * ],
168
+ * };
118
169
  */
119
170
  export interface TagRow {
120
171
  /** Auto-increment primary key. */
@@ -147,6 +198,17 @@ export interface TagRow {
147
198
  * Mirrors the row shape minus the auto-increment `id`. `categories` and
148
199
  * `sources` are passed as plain JS arrays (the database layer JSON-stringifies
149
200
  * them before write).
201
+ * @example
202
+ * const insert: TagRowForInsert = {
203
+ * pageId: 42,
204
+ * provider: 'Google Analytics',
205
+ * category: 'Analytics',
206
+ * externalId: 'G-XXXX',
207
+ * version: null,
208
+ * confidence: 100,
209
+ * categories: ['Analytics'],
210
+ * sources: [{ type: 'window-global', globalName: 'gtag' }],
211
+ * };
150
212
  */
151
213
  export type TagRowForInsert = Omit<TagRow, 'id'>;
152
214
  /**
@@ -155,6 +217,12 @@ export type TagRowForInsert = Omit<TagRow, 'id'>;
155
217
  * Keeps the response token-bounded for MCP / LLM consumers; the full `raw`
156
218
  * payload is fetched separately via `get-page-jsonld(url)`.
157
219
  * @see summarize-jsonld.ts
220
+ * @example
221
+ * const summary: JsonLdSummary = {
222
+ * count: 2,
223
+ * types: ['Article', 'BreadcrumbList'],
224
+ * parseErrorCount: 0,
225
+ * };
158
226
  */
159
227
  export interface JsonLdSummary {
160
228
  /** Total entries across `ld+json` and `speculationrules`. */
@@ -167,6 +235,11 @@ export interface JsonLdSummary {
167
235
  /**
168
236
  * Summary of one page's Wappalyzer tags returned by `get-page-detail`.
169
237
  * @see summarize-tags.ts
238
+ * @example
239
+ * const summary: TagsSummary = {
240
+ * count: 2,
241
+ * providerIds: { 'Google Analytics': ['G-XXXX'], YouTube: [] },
242
+ * };
170
243
  */
171
244
  export interface TagsSummary {
172
245
  /** Total tag rows for the page. */
@@ -180,6 +253,8 @@ export interface TagsSummary {
180
253
  *
181
254
  * Used by `get-tag-inventory` to return per-provider page counts across the
182
255
  * whole site.
256
+ * @example
257
+ * const entry: TagInventoryEntry = { provider: 'Google Tag Manager', pageCount: 120 };
183
258
  */
184
259
  export interface TagInventoryEntry {
185
260
  /** Wappalyzer provider name. */
@@ -193,6 +268,17 @@ export interface TagInventoryEntry {
193
268
  *
194
269
  * Catch this at CLI / viewer boundaries to print a friendly message; do not
195
270
  * confuse with generic `Error` thrown by `Database.connect` (lockfile / I/O).
271
+ * @example
272
+ * try {
273
+ * const accessor = await Archive.openCached(filePath);
274
+ * } catch (error) {
275
+ * if (error instanceof IncompatibleArchiveError) {
276
+ * // Message names the migration script(s) to run.
277
+ * console.error(error.message);
278
+ * } else {
279
+ * throw error;
280
+ * }
281
+ * }
196
282
  */
197
283
  export declare class IncompatibleArchiveError extends Error {
198
284
  readonly archiveVersion: string;
@@ -201,7 +287,7 @@ export declare class IncompatibleArchiveError extends Error {
201
287
  * @param archiveVersion - The `info.version` value read from the archive
202
288
  * (or `'unknown'` when the column is missing / null).
203
289
  * @param requiredVersion - The minimum format version this build accepts
204
- * (semver string, e.g. `'0.10.0'`).
290
+ * (semver string, e.g. `'0.13.0'`).
205
291
  */
206
292
  constructor(archiveVersion: string, requiredVersion: string);
207
293
  }
@@ -7,12 +7,24 @@
7
7
  * objects returned by `get-page-detail` consumers.
8
8
  * @module
9
9
  */
10
+ import { compareSemver } from './compare-semver.js';
10
11
  /**
11
12
  * Error thrown by `assert-compatible-version` when the archive's
12
13
  * `info.version` is older than the format version this build accepts.
13
14
  *
14
15
  * Catch this at CLI / viewer boundaries to print a friendly message; do not
15
16
  * confuse with generic `Error` thrown by `Database.connect` (lockfile / I/O).
17
+ * @example
18
+ * try {
19
+ * const accessor = await Archive.openCached(filePath);
20
+ * } catch (error) {
21
+ * if (error instanceof IncompatibleArchiveError) {
22
+ * // Message names the migration script(s) to run.
23
+ * console.error(error.message);
24
+ * } else {
25
+ * throw error;
26
+ * }
27
+ * }
16
28
  */
17
29
  export class IncompatibleArchiveError extends Error {
18
30
  archiveVersion;
@@ -21,13 +33,33 @@ export class IncompatibleArchiveError extends Error {
21
33
  * @param archiveVersion - The `info.version` value read from the archive
22
34
  * (or `'unknown'` when the column is missing / null).
23
35
  * @param requiredVersion - The minimum format version this build accepts
24
- * (semver string, e.g. `'0.10.0'`).
36
+ * (semver string, e.g. `'0.13.0'`).
25
37
  */
26
38
  constructor(archiveVersion, requiredVersion) {
27
39
  super(`Archive uses Nitpicker ${archiveVersion}; this build requires ${requiredVersion} or newer. ` +
28
- `Run \`node scripts/migrate-to-0.10.mjs <path>\` to produce an upgraded copy next to it.`);
40
+ `Run ${suggestMigrationScript(archiveVersion)} to produce an upgraded copy next to it.`);
29
41
  this.archiveVersion = archiveVersion;
30
42
  this.requiredVersion = requiredVersion;
31
43
  this.name = 'IncompatibleArchiveError';
32
44
  }
33
45
  }
46
+ /**
47
+ * Selects the migration script an operator should run to bring
48
+ * `archiveVersion` up to the current {@link IncompatibleArchiveError.requiredVersion}.
49
+ * Chained: pre-0.10 archives run migrate-to-0.10 first, then
50
+ * migrate-to-0.13 — so the message points at BOTH steps in order.
51
+ * 0.10.0-through-0.12.x archives only need migrate-to-0.13.
52
+ *
53
+ * Uses {@link compareSemver} instead of `<` string comparison: `'0.9.0'`
54
+ * lexicographically compares GREATER than `'0.10.0'` (because `'9' > '1'`),
55
+ * which would misroute pre-0.10 archives into the single-step hint and
56
+ * make the resulting migrator invocation fail with a confusing error.
57
+ * @param archiveVersion - Semver read from `info.version`, or `'unknown'`.
58
+ * @returns Bracketed command string for embedding into the error message.
59
+ */
60
+ function suggestMigrationScript(archiveVersion) {
61
+ if (archiveVersion === 'unknown' || compareSemver(archiveVersion, '0.10.0') < 0) {
62
+ return '`node scripts/migrate-to-0.10.mjs <path>` (then `node scripts/migrate-to-0.13.mjs <path>`)';
63
+ }
64
+ return '`node scripts/migrate-to-0.13.mjs <path>`';
65
+ }
@@ -0,0 +1,45 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Adds the 0.13 entity / edge tables (issue #192) to archives created
4
+ * before the 0.13 format.
5
+ *
6
+ * These are the 6 core normalised tables (`content_items`, `page_meta`,
7
+ * `resource_items`, `anchor_edges`, `resource_ref_edges`, `image_items`) that
8
+ * replace the legacy write model in the 0.13 format. Fresh archives get
9
+ * them via `initSchema`; this migration is called only by
10
+ * `scripts/migrate-to-0.13.mjs` as its schema catch-up step for pre-0.13
11
+ * input archives. The archive-open path (`db-ops/lifecycle/init.ts`) does
12
+ * not run it — `assertCompatibleVersion` guarantees every openable
13
+ * archive already has the full table set.
14
+ *
15
+ * The migration is intentionally table-only. It does not back-fill any data
16
+ * from `pages` / `resources` / `anchors` / `images` — that is the job of the
17
+ * population steps (`populateRefTables` + `populateEntityTables`), which
18
+ * read from the legacy tables and write
19
+ * the entity rows in a single WAL transaction with `.bak` protection. This
20
+ * migration only guarantees the empty tables exist so the populate step can
21
+ * INSERT into them without hitting `SQLITE_ERROR: no such table:
22
+ * content_items`.
23
+ *
24
+ * **Blocked-by contract**: `createEntityTables` references the
25
+ * 0.13 ref tables (`url_refs`, `content_type_refs`, `text_refs`,
26
+ * `json_refs`, `blob_refs`, `header_sets`) via `REFERENCES`. On an
27
+ * existing archive, `migrateRefTables` MUST have run first so the
28
+ * ref tables exist by the time this migration is applied.
29
+ * `scripts/migrate-to-0.13.mjs` orders the two calls statically so this
30
+ * ordering is enforced there, not here.
31
+ *
32
+ * **Idempotency**: `createEntityTables` itself uses
33
+ * `CREATE TABLE IF NOT EXISTS` / `CREATE INDEX IF NOT EXISTS` for every
34
+ * statement, so calling it multiple times against any DB state is safe.
35
+ * That means this wrapper does not need a defensive sentinel — the
36
+ * "content_items exists but page_meta was dropped externally" partial-
37
+ * corruption case is fully repaired on next open because every CREATE
38
+ * statement individually checks its own existence. The one thing the
39
+ * wrapper adds beyond the primitive is a log line, which we still want
40
+ * to emit only when creation actually happened, so we probe
41
+ * `content_items` first and short-circuit when the schema is already
42
+ * fully installed.
43
+ * @param instance - The Knex query builder instance connected to the database.
44
+ */
45
+ export declare function migrateEntityTables(instance: Knex): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { createEntityTables } from './create-entity-tables.js';
2
+ /**
3
+ * Adds the 0.13 entity / edge tables (issue #192) to archives created
4
+ * before the 0.13 format.
5
+ *
6
+ * These are the 6 core normalised tables (`content_items`, `page_meta`,
7
+ * `resource_items`, `anchor_edges`, `resource_ref_edges`, `image_items`) that
8
+ * replace the legacy write model in the 0.13 format. Fresh archives get
9
+ * them via `initSchema`; this migration is called only by
10
+ * `scripts/migrate-to-0.13.mjs` as its schema catch-up step for pre-0.13
11
+ * input archives. The archive-open path (`db-ops/lifecycle/init.ts`) does
12
+ * not run it — `assertCompatibleVersion` guarantees every openable
13
+ * archive already has the full table set.
14
+ *
15
+ * The migration is intentionally table-only. It does not back-fill any data
16
+ * from `pages` / `resources` / `anchors` / `images` — that is the job of the
17
+ * population steps (`populateRefTables` + `populateEntityTables`), which
18
+ * read from the legacy tables and write
19
+ * the entity rows in a single WAL transaction with `.bak` protection. This
20
+ * migration only guarantees the empty tables exist so the populate step can
21
+ * INSERT into them without hitting `SQLITE_ERROR: no such table:
22
+ * content_items`.
23
+ *
24
+ * **Blocked-by contract**: `createEntityTables` references the
25
+ * 0.13 ref tables (`url_refs`, `content_type_refs`, `text_refs`,
26
+ * `json_refs`, `blob_refs`, `header_sets`) via `REFERENCES`. On an
27
+ * existing archive, `migrateRefTables` MUST have run first so the
28
+ * ref tables exist by the time this migration is applied.
29
+ * `scripts/migrate-to-0.13.mjs` orders the two calls statically so this
30
+ * ordering is enforced there, not here.
31
+ *
32
+ * **Idempotency**: `createEntityTables` itself uses
33
+ * `CREATE TABLE IF NOT EXISTS` / `CREATE INDEX IF NOT EXISTS` for every
34
+ * statement, so calling it multiple times against any DB state is safe.
35
+ * That means this wrapper does not need a defensive sentinel — the
36
+ * "content_items exists but page_meta was dropped externally" partial-
37
+ * corruption case is fully repaired on next open because every CREATE
38
+ * statement individually checks its own existence. The one thing the
39
+ * wrapper adds beyond the primitive is a log line, which we still want
40
+ * to emit only when creation actually happened, so we probe
41
+ * `content_items` first and short-circuit when the schema is already
42
+ * fully installed.
43
+ * @param instance - The Knex query builder instance connected to the database.
44
+ */
45
+ export async function migrateEntityTables(instance) {
46
+ const hasContentItems = await instance.schema.hasTable('content_items');
47
+ if (hasContentItems) {
48
+ // Fast path: fully installed. `createEntityTables` would
49
+ // still be a safe no-op, but re-running it just to be defensive
50
+ // wastes 15 IF NOT EXISTS round-trips on every archive open.
51
+ return;
52
+ }
53
+ await createEntityTables(instance);
54
+ // eslint-disable-next-line no-console
55
+ console.error('[migrate] 0.13 entity/edge tables created');
56
+ }
@@ -0,0 +1,25 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * Adds the 0.13 dictionary tables (issue #190) to archives created before
4
+ * the 0.13 format.
5
+ *
6
+ * These are the 10 ref / header dictionary tables that form the
7
+ * durable write-model of the 0.13 format. Fresh archives get them via
8
+ * `initSchema`; this migration is called only by
9
+ * `scripts/migrate-to-0.13.mjs` as its schema catch-up step for pre-0.13
10
+ * input archives. The archive-open path (`db-ops/lifecycle/init.ts`) does
11
+ * not run it — `assertCompatibleVersion` guarantees every openable
12
+ * archive already has the full table set.
13
+ *
14
+ * The migration is intentionally table-only. It does not back-fill any data
15
+ * from `pages` / `resources` / `anchors` / `images` into the ref tables — that
16
+ * is the job of the 0.13 population step, which reads from the legacy
17
+ * tables and writes the ref rows in a single WAL transaction with `.bak`
18
+ * protection. This migration only guarantees the empty tables exist so
19
+ * consumers don't crash with `SQLITE_ERROR: no such table: url_refs`.
20
+ *
21
+ * Idempotent: presence of `url_refs` is used as the sentinel (all 10
22
+ * tables are created together, so any one of them can serve as the sentinel).
23
+ * @param instance - The Knex query builder instance connected to the database.
24
+ */
25
+ export declare function migrateRefTables(instance: Knex): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import { createRefTables } from './create-ref-tables.js';
2
+ /**
3
+ * Adds the 0.13 dictionary tables (issue #190) to archives created before
4
+ * the 0.13 format.
5
+ *
6
+ * These are the 10 ref / header dictionary tables that form the
7
+ * durable write-model of the 0.13 format. Fresh archives get them via
8
+ * `initSchema`; this migration is called only by
9
+ * `scripts/migrate-to-0.13.mjs` as its schema catch-up step for pre-0.13
10
+ * input archives. The archive-open path (`db-ops/lifecycle/init.ts`) does
11
+ * not run it — `assertCompatibleVersion` guarantees every openable
12
+ * archive already has the full table set.
13
+ *
14
+ * The migration is intentionally table-only. It does not back-fill any data
15
+ * from `pages` / `resources` / `anchors` / `images` into the ref tables — that
16
+ * is the job of the 0.13 population step, which reads from the legacy
17
+ * tables and writes the ref rows in a single WAL transaction with `.bak`
18
+ * protection. This migration only guarantees the empty tables exist so
19
+ * consumers don't crash with `SQLITE_ERROR: no such table: url_refs`.
20
+ *
21
+ * Idempotent: presence of `url_refs` is used as the sentinel (all 10
22
+ * tables are created together, so any one of them can serve as the sentinel).
23
+ * @param instance - The Knex query builder instance connected to the database.
24
+ */
25
+ export async function migrateRefTables(instance) {
26
+ const hasUrlRefs = await instance.schema.hasTable('url_refs');
27
+ if (hasUrlRefs) {
28
+ return;
29
+ }
30
+ const hasPages = await instance.schema.hasTable('pages');
31
+ if (!hasPages) {
32
+ // Empty archive; the regular initSchema path will create the tables.
33
+ return;
34
+ }
35
+ await createRefTables(instance);
36
+ // eslint-disable-next-line no-console
37
+ console.error('[migrate] 0.13 ref/header tables created');
38
+ }
@@ -0,0 +1,32 @@
1
+ import type { FlatPageMetaColumns } from './meta/types.js';
2
+ /**
3
+ * Flat-meta-field → `page_meta` FK-column mapping, shared by the two
4
+ * writers that materialise `page_meta` rows: the live-crawl upsert
5
+ * (`db-ops/pages/write/insert-page.ts`) and the archive-migration
6
+ * populate (`populate-entity-tables/populate-page-meta.ts`).
7
+ *
8
+ * The two writers MUST agree on this mapping — a fork would make
9
+ * live-crawled archives and migrated archives disagree on which flat
10
+ * meta field feeds which `page_meta` column for structurally identical
11
+ * inputs. Keeping the single definition here is what enforces that;
12
+ * adding, renaming, or removing a flat meta column is a one-place edit.
13
+ *
14
+ * - `text`: text-shaped columns mapped 1:1 to `<name>_text_id` FKs into
15
+ * `text_refs`.
16
+ * - `url`: URL-shaped columns mapped 1:1 to `<name>_url_id` FKs into
17
+ * `url_refs`.
18
+ * @example
19
+ * for (const { source, target } of PAGE_META_COLUMN_MAPS.text) {
20
+ * row[target] = textIds.get(flat[source]) ?? null;
21
+ * }
22
+ */
23
+ export declare const PAGE_META_COLUMN_MAPS: {
24
+ readonly text: readonly {
25
+ source: keyof FlatPageMetaColumns;
26
+ target: string;
27
+ }[];
28
+ readonly url: readonly {
29
+ source: keyof FlatPageMetaColumns;
30
+ target: string;
31
+ }[];
32
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Flat-meta-field → `page_meta` FK-column mapping, shared by the two
3
+ * writers that materialise `page_meta` rows: the live-crawl upsert
4
+ * (`db-ops/pages/write/insert-page.ts`) and the archive-migration
5
+ * populate (`populate-entity-tables/populate-page-meta.ts`).
6
+ *
7
+ * The two writers MUST agree on this mapping — a fork would make
8
+ * live-crawled archives and migrated archives disagree on which flat
9
+ * meta field feeds which `page_meta` column for structurally identical
10
+ * inputs. Keeping the single definition here is what enforces that;
11
+ * adding, renaming, or removing a flat meta column is a one-place edit.
12
+ *
13
+ * - `text`: text-shaped columns mapped 1:1 to `<name>_text_id` FKs into
14
+ * `text_refs`.
15
+ * - `url`: URL-shaped columns mapped 1:1 to `<name>_url_id` FKs into
16
+ * `url_refs`.
17
+ * @example
18
+ * for (const { source, target } of PAGE_META_COLUMN_MAPS.text) {
19
+ * row[target] = textIds.get(flat[source]) ?? null;
20
+ * }
21
+ */
22
+ export const PAGE_META_COLUMN_MAPS = {
23
+ text: [
24
+ { source: 'title', target: 'title_text_id' },
25
+ { source: 'description', target: 'description_text_id' },
26
+ { source: 'keywords', target: 'keywords_text_id' },
27
+ { source: 'robots_raw', target: 'robots_raw_text_id' },
28
+ { source: 'og_title', target: 'og_title_text_id' },
29
+ { source: 'og_description', target: 'og_description_text_id' },
30
+ { source: 'twitter_title', target: 'twitter_title_text_id' },
31
+ { source: 'twitter_description', target: 'twitter_description_text_id' },
32
+ ],
33
+ url: [
34
+ { source: 'canonical', target: 'canonical_url_id' },
35
+ { source: 'amphtml', target: 'amphtml_url_id' },
36
+ { source: 'manifest', target: 'manifest_url_id' },
37
+ { source: 'icon_href', target: 'icon_url_id' },
38
+ { source: 'appleTouchIcon_href', target: 'apple_touch_icon_url_id' },
39
+ { source: 'og_url', target: 'og_url_id' },
40
+ { source: 'og_image', target: 'og_image_url_id' },
41
+ { source: 'twitter_image', target: 'twitter_image_url_id' },
42
+ ],
43
+ };
@@ -14,13 +14,13 @@ declare const FLAT_META_COLUMNS: readonly ["lang", "dir", "charset", "baseHref",
14
14
  * Represents a crawled page stored in the archive.
15
15
  *
16
16
  * Provides typed getters for the most-used meta columns (title, canonical,
17
- * og:*, twitter_card, robots flags, lang), plus {@link metaFlat} as an
18
- * iterable view over all ~47 flat meta columns and {@link metaExtras} for
17
+ * og:*, twitter_card, robots flags, lang), plus {@link Page.metaFlat} as an
18
+ * iterable view over all ~47 flat meta columns and {@link Page.metaExtras} for
19
19
  * the JSON catch-all of nested sub-objects not flattened to columns.
20
20
  *
21
21
  * JSON-LD entries and Wappalyzer tag rows live in dedicated tables and are
22
- * fetched on demand via {@link jsonLd} / {@link tags} (lazy reads, same
23
- * pattern as {@link getAnchors}).
22
+ * fetched on demand via {@link Page.getJsonLd} / {@link Page.getTags} (lazy reads, same
23
+ * pattern as {@link Page.getAnchors}).
24
24
  *
25
25
  * Instances are created by {@link ArchiveAccessor.getPages} or
26
26
  * {@link ArchiveAccessor.getPagesWithRefs}.
@@ -177,7 +177,7 @@ export default class Page {
177
177
  /**
178
178
  * Sorted unique Wappalyzer provider names, comma-separated, empty string
179
179
  * when no tags. Denormalised aggregate; for the structured form fetch
180
- * {@link tags} (lazy).
180
+ * {@link Page.getTags} (lazy).
181
181
  */
182
182
  get tagsProvidersCsv(): string;
183
183
  /**
@@ -281,8 +281,8 @@ export default class Page {
281
281
  isInternalPage: boolean;
282
282
  getAnchors: Anchor[];
283
283
  getReferrers: Referrer[];
284
- dir: string | number | null;
285
284
  lang: string | number | null;
285
+ dir: string | number | null;
286
286
  charset: string | number | null;
287
287
  baseHref: string | number | null;
288
288
  viewport_raw: string | number | null;
@@ -65,13 +65,13 @@ const FLAT_META_COLUMNS = [
65
65
  * Represents a crawled page stored in the archive.
66
66
  *
67
67
  * Provides typed getters for the most-used meta columns (title, canonical,
68
- * og:*, twitter_card, robots flags, lang), plus {@link metaFlat} as an
69
- * iterable view over all ~47 flat meta columns and {@link metaExtras} for
68
+ * og:*, twitter_card, robots flags, lang), plus {@link Page.metaFlat} as an
69
+ * iterable view over all ~47 flat meta columns and {@link Page.metaExtras} for
70
70
  * the JSON catch-all of nested sub-objects not flattened to columns.
71
71
  *
72
72
  * JSON-LD entries and Wappalyzer tag rows live in dedicated tables and are
73
- * fetched on demand via {@link jsonLd} / {@link tags} (lazy reads, same
74
- * pattern as {@link getAnchors}).
73
+ * fetched on demand via {@link Page.getJsonLd} / {@link Page.getTags} (lazy reads, same
74
+ * pattern as {@link Page.getAnchors}).
75
75
  *
76
76
  * Instances are created by {@link ArchiveAccessor.getPages} or
77
77
  * {@link ArchiveAccessor.getPagesWithRefs}.
@@ -308,7 +308,7 @@ export default class Page {
308
308
  /**
309
309
  * Sorted unique Wappalyzer provider names, comma-separated, empty string
310
310
  * when no tags. Denormalised aggregate; for the structured form fetch
311
- * {@link tags} (lazy).
311
+ * {@link Page.getTags} (lazy).
312
312
  */
313
313
  get tagsProvidersCsv() {
314
314
  return this.#raw.tags_providers_csv ?? '';
@@ -23,13 +23,13 @@ export interface ArchiveLockHolder {
23
23
  /**
24
24
  * Probe `<tmpDir>.lock/pid.txt` without acquiring the lock.
25
25
  *
26
- * Mirror of the alive-check inside {@link acquireArchiveLock}, exposed for
26
+ * Mirror of the alive-check inside `acquireArchiveLock`, exposed for
27
27
  * read-only consumers so they can detect (and surface) a concurrent crawler
28
28
  * without competing for the lock. Returns `null` when no lock directory is
29
29
  * present or the pid file is missing/malformed — callers should treat that
30
30
  * as "no detectable crawler" rather than as an error.
31
31
  *
32
- * Co-located with {@link acquireArchiveLock} so the writer side and the
32
+ * Co-located with `acquireArchiveLock` so the writer side and the
33
33
  * read-only probe stay in lockstep when the lock format evolves (e.g.
34
34
  * adding a hostname/timestamp field).
35
35
  * @param tmpDir - The archive's temporary working directory whose
@@ -3,13 +3,13 @@ import path from 'node:path';
3
3
  /**
4
4
  * Probe `<tmpDir>.lock/pid.txt` without acquiring the lock.
5
5
  *
6
- * Mirror of the alive-check inside {@link acquireArchiveLock}, exposed for
6
+ * Mirror of the alive-check inside `acquireArchiveLock`, exposed for
7
7
  * read-only consumers so they can detect (and surface) a concurrent crawler
8
8
  * without competing for the lock. Returns `null` when no lock directory is
9
9
  * present or the pid file is missing/malformed — callers should treat that
10
10
  * as "no detectable crawler" rather than as an error.
11
11
  *
12
- * Co-located with {@link acquireArchiveLock} so the writer side and the
12
+ * Co-located with `acquireArchiveLock` so the writer side and the
13
13
  * read-only probe stay in lockstep when the lock format evolves (e.g.
14
14
  * adding a hostname/timestamp field).
15
15
  * @param tmpDir - The archive's temporary working directory whose
@@ -0,0 +1,41 @@
1
+ import type { AnchorEdgeRowInProgress, AnchorInputRow } from './types.js';
2
+ /**
3
+ * Collapses consecutive `anchors`-shaped rows into `anchor_edges` rows by
4
+ * `(pageId, hrefId)` (issue #193).
5
+ *
6
+ * **Input contract**: `rows` MUST be sorted by `(pageId, hrefId, id)`
7
+ * ascending. The caller (`populate-anchor-edges.ts`) achieves this via a
8
+ * single keyset scan `ORDER BY pageId, hrefId, id` over `anchors`.
9
+ *
10
+ * The `id`-then-key sort matters because the dedup rule is
11
+ * "first instance wins": the smallest `anchors.id` for a given
12
+ * `(pageId, hrefId)` pair contributes its `hash` and `textContent` to
13
+ * the edge; every subsequent duplicate is counted but its body is
14
+ * discarded. A naive `min(hash) GROUP BY pageId, hrefId` would pick the
15
+ * lexicographically smallest hex string (uniformly distributed) rather
16
+ * than the earliest occurrence, so the pass has to happen in JS.
17
+ *
18
+ * The generator yields one {@link AnchorEdgeRowInProgress} per distinct
19
+ * pair as soon as the next pair boundary is observed. Emitting eagerly
20
+ * keeps peak memory bounded to O(1) — the collapser holds at most one
21
+ * open pair state at a time.
22
+ *
23
+ * `first_text_id` is intentionally left `null` here; the caller resolves
24
+ * it in a second pass after all edges are known (see
25
+ * `populate-anchor-edges.ts`). The `first_hash` field is set to the
26
+ * first row's `hash` verbatim; a first row with `hash === null` results
27
+ * in `first_hash = null` on the edge (rare but possible on legacy
28
+ * archives that failed to compute a hash).
29
+ * @param rows - Anchor input rows sorted by `(pageId, hrefId, id)`.
30
+ * @yields {AnchorEdgeRowInProgress} One entry per distinct
31
+ * `(pageId, hrefId)` pair in the input.
32
+ * @example
33
+ * const edges = [...collapseAnchorRows([
34
+ * { id: 1, pageId: 10, hrefId: 20, hash: 'a', textContent: 'first' },
35
+ * { id: 2, pageId: 10, hrefId: 20, hash: 'b', textContent: 'second' },
36
+ * { id: 3, pageId: 10, hrefId: 30, hash: 'c', textContent: 'x' },
37
+ * ])];
38
+ * // edges[0] = { page_id: 10, href_page_id: 20, count: 2, first_hash: 'a', ... }
39
+ * // edges[1] = { page_id: 10, href_page_id: 30, count: 1, first_hash: 'c', ... }
40
+ */
41
+ export declare function collapseAnchorRows(rows: Iterable<AnchorInputRow>): Generator<AnchorEdgeRowInProgress>;