@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.
- package/README.md +6 -4
- package/lib/archive/archive-accessor.d.ts +2 -2
- package/lib/archive/archive-accessor.js +2 -2
- package/lib/archive/archive-lock.d.ts +7 -0
- package/lib/archive/archive-lock.js +7 -0
- package/lib/archive/archive.d.ts +175 -13
- package/lib/archive/archive.js +198 -14
- package/lib/archive/cache/compute-archive-cache-key.d.ts +39 -0
- package/lib/archive/cache/compute-archive-cache-key.js +95 -0
- package/lib/archive/cache/extract-archive-to-cache.d.ts +43 -0
- package/lib/archive/cache/extract-archive-to-cache.js +309 -0
- package/lib/archive/cache/get-archive-cache-root.d.ts +20 -0
- package/lib/archive/cache/get-archive-cache-root.js +53 -0
- package/lib/archive/cache/is-archive-cache-disabled.d.ts +24 -0
- package/lib/archive/cache/is-archive-cache-disabled.js +34 -0
- package/lib/archive/cache/resolve-archive-cache-dir.d.ts +26 -0
- package/lib/archive/cache/resolve-archive-cache-dir.js +32 -0
- package/lib/archive/create-adjunct-tables.d.ts +43 -0
- package/lib/archive/create-adjunct-tables.js +213 -0
- package/lib/archive/create-entity-tables.d.ts +173 -0
- package/lib/archive/create-entity-tables.js +318 -0
- package/lib/archive/create-progress-reporter.d.ts +30 -0
- package/lib/archive/create-progress-reporter.js +38 -0
- package/lib/archive/create-ref-tables.d.ts +35 -0
- package/lib/archive/create-ref-tables.js +188 -0
- package/lib/archive/database.d.ts +130 -182
- package/lib/archive/database.js +524 -1777
- package/lib/archive/db-ops/_shared/clear-write-ref-caches.d.ts +27 -0
- package/lib/archive/db-ops/_shared/clear-write-ref-caches.js +34 -0
- package/lib/archive/db-ops/_shared/create-write-ref-caches.d.ts +17 -0
- package/lib/archive/db-ops/_shared/create-write-ref-caches.js +26 -0
- package/lib/archive/db-ops/_shared/decode-json-ref.d.ts +17 -0
- package/lib/archive/db-ops/_shared/decode-json-ref.js +31 -0
- package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.d.ts +20 -0
- package/lib/archive/db-ops/_shared/load-response-headers-by-set-ids.js +53 -0
- package/lib/archive/db-ops/_shared/resolve-content-item-id.d.ts +61 -0
- package/lib/archive/db-ops/_shared/resolve-content-item-id.js +111 -0
- package/lib/archive/db-ops/_shared/resolve-url-or-blob.d.ts +23 -0
- package/lib/archive/db-ops/_shared/resolve-url-or-blob.js +29 -0
- package/lib/archive/db-ops/_shared/retry-setting.d.ts +16 -0
- package/lib/archive/db-ops/_shared/retry-setting.js +18 -0
- package/lib/archive/db-ops/_shared/safe-parse-json.d.ts +11 -0
- package/lib/archive/db-ops/_shared/safe-parse-json.js +18 -0
- package/lib/archive/db-ops/_shared/types.d.ts +53 -0
- package/lib/archive/db-ops/_shared/types.js +1 -0
- package/lib/archive/db-ops/_shared/upsert-blob-ref.d.ts +25 -0
- package/lib/archive/db-ops/_shared/upsert-blob-ref.js +48 -0
- package/lib/archive/db-ops/_shared/upsert-content-type-ref.d.ts +30 -0
- package/lib/archive/db-ops/_shared/upsert-content-type-ref.js +45 -0
- package/lib/archive/db-ops/_shared/upsert-json-ref.d.ts +22 -0
- package/lib/archive/db-ops/_shared/upsert-json-ref.js +41 -0
- package/lib/archive/db-ops/_shared/upsert-response-headers.d.ts +35 -0
- package/lib/archive/db-ops/_shared/upsert-response-headers.js +49 -0
- package/lib/archive/db-ops/_shared/upsert-url-ref.d.ts +39 -0
- package/lib/archive/db-ops/_shared/upsert-url-ref.js +62 -0
- package/lib/archive/db-ops/analysis/replace-analysis-violations.d.ts +28 -0
- package/lib/archive/db-ops/analysis/replace-analysis-violations.js +152 -0
- package/lib/archive/db-ops/anchors/get-anchors-on-page.d.ts +10 -0
- package/lib/archive/db-ops/anchors/get-anchors-on-page.js +21 -0
- package/lib/archive/db-ops/config/get-base-url.d.ts +8 -0
- package/lib/archive/db-ops/config/get-base-url.js +14 -0
- package/lib/archive/db-ops/config/get-config.d.ts +10 -0
- package/lib/archive/db-ops/config/get-config.js +27 -0
- package/lib/archive/db-ops/config/get-name.d.ts +8 -0
- package/lib/archive/db-ops/config/get-name.js +14 -0
- package/lib/archive/db-ops/config/info-column-allowlist.d.ts +7 -0
- package/lib/archive/db-ops/config/info-column-allowlist.js +26 -0
- package/lib/archive/db-ops/config/info-json-columns.d.ts +5 -0
- package/lib/archive/db-ops/config/info-json-columns.js +10 -0
- package/lib/archive/db-ops/config/set-config.d.ts +12 -0
- package/lib/archive/db-ops/config/set-config.js +21 -0
- package/lib/archive/db-ops/config/update-config.d.ts +17 -0
- package/lib/archive/db-ops/config/update-config.js +36 -0
- package/lib/archive/db-ops/errors/insert-crawl-error.d.ts +15 -0
- package/lib/archive/db-ops/errors/insert-crawl-error.js +21 -0
- package/lib/archive/db-ops/errors/insert-page-error.d.ts +21 -0
- package/lib/archive/db-ops/errors/insert-page-error.js +28 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.d.ts +22 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.js +141 -0
- package/lib/archive/db-ops/html/get-html-of-page-by-id.d.ts +18 -0
- package/lib/archive/db-ops/html/get-html-of-page-by-id.js +29 -0
- package/lib/archive/db-ops/inventory/record-inventory-run.d.ts +21 -0
- package/lib/archive/db-ops/inventory/record-inventory-run.js +38 -0
- package/lib/archive/db-ops/lifecycle/checkpoint.d.ts +8 -0
- package/lib/archive/db-ops/lifecycle/checkpoint.js +9 -0
- package/lib/archive/db-ops/lifecycle/destroy.d.ts +6 -0
- package/lib/archive/db-ops/lifecycle/destroy.js +7 -0
- package/lib/archive/db-ops/lifecycle/init.d.ts +22 -0
- package/lib/archive/db-ops/lifecycle/init.js +42 -0
- package/lib/archive/db-ops/meta/get-jsonld-of-page.d.ts +13 -0
- package/lib/archive/db-ops/meta/get-jsonld-of-page.js +27 -0
- package/lib/archive/db-ops/meta/get-tags-of-page.d.ts +12 -0
- package/lib/archive/db-ops/meta/get-tags-of-page.js +28 -0
- package/lib/archive/db-ops/pages/order/set-url-order.d.ts +8 -0
- package/lib/archive/db-ops/pages/order/set-url-order.js +32 -0
- package/lib/archive/db-ops/pages/read/build-page-query.d.ts +18 -0
- package/lib/archive/db-ops/pages/read/build-page-query.js +40 -0
- package/lib/archive/db-ops/pages/read/get-crawling-state.d.ts +70 -0
- package/lib/archive/db-ops/pages/read/get-crawling-state.js +98 -0
- package/lib/archive/db-ops/pages/read/get-existing-page-urls.d.ts +15 -0
- package/lib/archive/db-ops/pages/read/get-existing-page-urls.js +30 -0
- package/lib/archive/db-ops/pages/read/get-page-count.d.ts +12 -0
- package/lib/archive/db-ops/pages/read/get-page-count.js +21 -0
- package/lib/archive/db-ops/pages/read/get-page-source-by-url.d.ts +24 -0
- package/lib/archive/db-ops/pages/read/get-page-source-by-url.js +28 -0
- package/lib/archive/db-ops/pages/read/get-pages-with-rels.d.ts +38 -0
- package/lib/archive/db-ops/pages/read/get-pages-with-rels.js +107 -0
- package/lib/archive/db-ops/pages/read/get-pages.d.ts +11 -0
- package/lib/archive/db-ops/pages/read/get-pages.js +51 -0
- package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.d.ts +18 -0
- package/lib/archive/db-ops/pages/read/get-scraped-html-page-count.js +25 -0
- package/lib/archive/db-ops/pages/read/reconstruct-page-rows.d.ts +31 -0
- package/lib/archive/db-ops/pages/read/reconstruct-page-rows.js +32 -0
- package/lib/archive/db-ops/pages/reset/repromote-external-pages.d.ts +24 -0
- package/lib/archive/db-ops/pages/reset/repromote-external-pages.js +93 -0
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.d.ts +47 -0
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.js +124 -0
- package/lib/archive/db-ops/pages/write/insert-inventory-seeds.d.ts +37 -0
- package/lib/archive/db-ops/pages/write/insert-inventory-seeds.js +72 -0
- package/lib/archive/db-ops/pages/write/insert-jsonld.d.ts +17 -0
- package/lib/archive/db-ops/pages/write/insert-jsonld.js +49 -0
- package/lib/archive/db-ops/pages/write/insert-page.d.ts +36 -0
- package/lib/archive/db-ops/pages/write/insert-page.js +208 -0
- package/lib/archive/db-ops/pages/write/insert-tags.d.ts +16 -0
- package/lib/archive/db-ops/pages/write/insert-tags.js +34 -0
- package/lib/archive/db-ops/pages/write/link-redirect-sources.d.ts +36 -0
- package/lib/archive/db-ops/pages/write/link-redirect-sources.js +93 -0
- package/lib/archive/db-ops/pages/write/record-redirect.d.ts +35 -0
- package/lib/archive/db-ops/pages/write/record-redirect.js +100 -0
- package/lib/archive/db-ops/pages/write/set-skipped-page.d.ts +13 -0
- package/lib/archive/db-ops/pages/write/set-skipped-page.js +22 -0
- package/lib/archive/db-ops/pages/write/update-page.d.ts +29 -0
- package/lib/archive/db-ops/pages/write/update-page.js +334 -0
- package/lib/archive/db-ops/pages/write/write-page-html-blob.d.ts +19 -0
- package/lib/archive/db-ops/pages/write/write-page-html-blob.js +41 -0
- package/lib/archive/db-ops/referrers/get-redirects-for-pages.d.ts +9 -0
- package/lib/archive/db-ops/referrers/get-redirects-for-pages.js +15 -0
- package/lib/archive/db-ops/referrers/get-referrers-of-page.d.ts +17 -0
- package/lib/archive/db-ops/referrers/get-referrers-of-page.js +32 -0
- package/lib/archive/db-ops/referrers/get-referrers-of-resource.d.ts +8 -0
- package/lib/archive/db-ops/referrers/get-referrers-of-resource.js +15 -0
- package/lib/archive/db-ops/resources/build-resource-query.d.ts +25 -0
- package/lib/archive/db-ops/resources/build-resource-query.js +29 -0
- package/lib/archive/db-ops/resources/get-existing-resource-urls.d.ts +9 -0
- package/lib/archive/db-ops/resources/get-existing-resource-urls.js +24 -0
- package/lib/archive/db-ops/resources/get-resource-by-url.d.ts +13 -0
- package/lib/archive/db-ops/resources/get-resource-by-url.js +22 -0
- package/lib/archive/db-ops/resources/get-resource-url-list.d.ts +9 -0
- package/lib/archive/db-ops/resources/get-resource-url-list.js +13 -0
- package/lib/archive/db-ops/resources/get-resources.d.ts +8 -0
- package/lib/archive/db-ops/resources/get-resources.js +11 -0
- package/lib/archive/db-ops/resources/insert-inventory-resources.d.ts +24 -0
- package/lib/archive/db-ops/resources/insert-inventory-resources.js +64 -0
- package/lib/archive/db-ops/resources/insert-resource-referrers.d.ts +15 -0
- package/lib/archive/db-ops/resources/insert-resource-referrers.js +54 -0
- package/lib/archive/db-ops/resources/insert-resource.d.ts +34 -0
- package/lib/archive/db-ops/resources/insert-resource.js +73 -0
- package/lib/archive/db-ops/resources/reconstruct-resource-rows.d.ts +26 -0
- package/lib/archive/db-ops/resources/reconstruct-resource-rows.js +30 -0
- package/lib/archive/decode-html-blob.d.ts +18 -0
- package/lib/archive/decode-html-blob.js +31 -0
- package/lib/archive/derive-lineage-from-parent.d.ts +37 -0
- package/lib/archive/derive-lineage-from-parent.js +42 -0
- package/lib/archive/drop-legacy-tables.d.ts +45 -0
- package/lib/archive/drop-legacy-tables.js +56 -0
- package/lib/archive/filesystem/rename.js +1 -1
- package/lib/archive/get-failed-page-messages.d.ts +44 -0
- package/lib/archive/get-failed-page-messages.js +132 -0
- package/lib/archive/init-schema.d.ts +35 -39
- package/lib/archive/init-schema.js +111 -320
- package/lib/archive/is-inventory-source.d.ts +21 -0
- package/lib/archive/is-inventory-source.js +22 -0
- package/lib/archive/limited-page-ids.d.ts +2 -1
- package/lib/archive/limited-page-ids.js +5 -4
- package/lib/archive/meta/assert-compatible-version.d.ts +24 -3
- package/lib/archive/meta/assert-compatible-version.js +24 -3
- package/lib/archive/meta/types.d.ts +87 -1
- package/lib/archive/meta/types.js +34 -2
- package/lib/archive/migrate-entity-tables.d.ts +45 -0
- package/lib/archive/migrate-entity-tables.js +56 -0
- package/lib/archive/migrate-ref-tables.d.ts +25 -0
- package/lib/archive/migrate-ref-tables.js +38 -0
- package/lib/archive/page-meta-column-maps.d.ts +32 -0
- package/lib/archive/page-meta-column-maps.js +43 -0
- package/lib/archive/page.d.ts +6 -6
- package/lib/archive/page.js +5 -5
- package/lib/archive/peek-archive-lock.d.ts +2 -2
- package/lib/archive/peek-archive-lock.js +2 -2
- package/lib/archive/populate-entity-tables/collapse-anchor-rows.d.ts +41 -0
- package/lib/archive/populate-entity-tables/collapse-anchor-rows.js +87 -0
- package/lib/archive/populate-entity-tables/derive-dom-path.d.ts +35 -0
- package/lib/archive/populate-entity-tables/derive-dom-path.js +72 -0
- package/lib/archive/populate-entity-tables/is-blob-ref-value.d.ts +16 -0
- package/lib/archive/populate-entity-tables/is-blob-ref-value.js +19 -0
- package/lib/archive/populate-entity-tables/match-images-to-dom-paths.d.ts +66 -0
- package/lib/archive/populate-entity-tables/match-images-to-dom-paths.js +96 -0
- package/lib/archive/populate-entity-tables/populate-anchor-edges.d.ts +33 -0
- package/lib/archive/populate-entity-tables/populate-anchor-edges.js +153 -0
- package/lib/archive/populate-entity-tables/populate-content-items.d.ts +40 -0
- package/lib/archive/populate-entity-tables/populate-content-items.js +141 -0
- package/lib/archive/populate-entity-tables/populate-entities.d.ts +81 -0
- package/lib/archive/populate-entity-tables/populate-entities.js +111 -0
- package/lib/archive/populate-entity-tables/populate-image-items.d.ts +91 -0
- package/lib/archive/populate-entity-tables/populate-image-items.js +223 -0
- package/lib/archive/populate-entity-tables/populate-page-meta.d.ts +33 -0
- package/lib/archive/populate-entity-tables/populate-page-meta.js +267 -0
- package/lib/archive/populate-entity-tables/populate-resource-items.d.ts +22 -0
- package/lib/archive/populate-entity-tables/populate-resource-items.js +114 -0
- package/lib/archive/populate-entity-tables/populate-resource-ref-edges.d.ts +31 -0
- package/lib/archive/populate-entity-tables/populate-resource-ref-edges.js +33 -0
- package/lib/archive/populate-entity-tables/resolve-blob-refs.d.ts +31 -0
- package/lib/archive/populate-entity-tables/resolve-blob-refs.js +100 -0
- package/lib/archive/populate-entity-tables/resolve-content-type-refs.d.ts +22 -0
- package/lib/archive/populate-entity-tables/resolve-content-type-refs.js +27 -0
- package/lib/archive/populate-entity-tables/resolve-header-sets.d.ts +49 -0
- package/lib/archive/populate-entity-tables/resolve-header-sets.js +122 -0
- package/lib/archive/populate-entity-tables/resolve-json-refs.d.ts +25 -0
- package/lib/archive/populate-entity-tables/resolve-json-refs.js +67 -0
- package/lib/archive/populate-entity-tables/resolve-text-refs.d.ts +30 -0
- package/lib/archive/populate-entity-tables/resolve-text-refs.js +61 -0
- package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.d.ts +21 -0
- package/lib/archive/populate-entity-tables/resolve-url-or-blob-from-maps.js +27 -0
- package/lib/archive/populate-entity-tables/resolve-url-refs.d.ts +33 -0
- package/lib/archive/populate-entity-tables/resolve-url-refs.js +60 -0
- package/lib/archive/populate-entity-tables/test-utils/count-rows.d.ts +17 -0
- package/lib/archive/populate-entity-tables/test-utils/count-rows.js +20 -0
- package/lib/archive/populate-entity-tables/test-utils/seed-content-items.d.ts +25 -0
- package/lib/archive/populate-entity-tables/test-utils/seed-content-items.js +42 -0
- package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.d.ts +23 -0
- package/lib/archive/populate-entity-tables/test-utils/setup-entities-db.js +178 -0
- package/lib/archive/populate-entity-tables/types.d.ts +157 -0
- package/lib/archive/populate-entity-tables/types.js +12 -0
- package/lib/archive/populate-entity-tables/upsert-text-refs.d.ts +38 -0
- package/lib/archive/populate-entity-tables/upsert-text-refs.js +78 -0
- package/lib/archive/populate-ref-tables/classify-content-type.d.ts +16 -0
- package/lib/archive/populate-ref-tables/classify-content-type.js +52 -0
- package/lib/archive/populate-ref-tables/compute-content-hash.d.ts +22 -0
- package/lib/archive/populate-ref-tables/compute-content-hash.js +26 -0
- package/lib/archive/populate-ref-tables/compute-header-flags.d.ts +16 -0
- package/lib/archive/populate-ref-tables/compute-header-flags.js +70 -0
- package/lib/archive/populate-ref-tables/content-type-rules.d.ts +38 -0
- package/lib/archive/populate-ref-tables/content-type-rules.js +133 -0
- package/lib/archive/populate-ref-tables/create-header-table-caches.d.ts +25 -0
- package/lib/archive/populate-ref-tables/create-header-table-caches.js +49 -0
- package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.d.ts +15 -0
- package/lib/archive/populate-ref-tables/data-uri-url-refs-limit.js +15 -0
- package/lib/archive/populate-ref-tables/decode-data-uri.d.ts +21 -0
- package/lib/archive/populate-ref-tables/decode-data-uri.js +126 -0
- package/lib/archive/populate-ref-tables/decompose-header-set.d.ts +29 -0
- package/lib/archive/populate-ref-tables/decompose-header-set.js +157 -0
- package/lib/archive/populate-ref-tables/decompose-url.d.ts +25 -0
- package/lib/archive/populate-ref-tables/decompose-url.js +70 -0
- package/lib/archive/populate-ref-tables/header-stability.d.ts +19 -0
- package/lib/archive/populate-ref-tables/header-stability.js +22 -0
- package/lib/archive/populate-ref-tables/header-value-cache-key.d.ts +17 -0
- package/lib/archive/populate-ref-tables/header-value-cache-key.js +19 -0
- package/lib/archive/populate-ref-tables/normalize-mime.d.ts +24 -0
- package/lib/archive/populate-ref-tables/normalize-mime.js +36 -0
- package/lib/archive/populate-ref-tables/populate-blob-refs.d.ts +38 -0
- package/lib/archive/populate-ref-tables/populate-blob-refs.js +134 -0
- package/lib/archive/populate-ref-tables/populate-content-type-refs.d.ts +27 -0
- package/lib/archive/populate-ref-tables/populate-content-type-refs.js +70 -0
- package/lib/archive/populate-ref-tables/populate-header-tables.d.ts +35 -0
- package/lib/archive/populate-ref-tables/populate-header-tables.js +80 -0
- package/lib/archive/populate-ref-tables/populate-json-refs.d.ts +29 -0
- package/lib/archive/populate-ref-tables/populate-json-refs.js +101 -0
- package/lib/archive/populate-ref-tables/populate-refs.d.ts +51 -0
- package/lib/archive/populate-ref-tables/populate-refs.js +62 -0
- package/lib/archive/populate-ref-tables/populate-text-refs.d.ts +32 -0
- package/lib/archive/populate-ref-tables/populate-text-refs.js +133 -0
- package/lib/archive/populate-ref-tables/populate-url-refs.d.ts +28 -0
- package/lib/archive/populate-ref-tables/populate-url-refs.js +148 -0
- package/lib/archive/populate-ref-tables/test-utils/count-rows.d.ts +15 -0
- package/lib/archive/populate-ref-tables/test-utils/count-rows.js +17 -0
- package/lib/archive/populate-ref-tables/types.d.ts +197 -0
- package/lib/archive/populate-ref-tables/types.js +7 -0
- package/lib/archive/populate-ref-tables/upsert-one-header-set.d.ts +34 -0
- package/lib/archive/populate-ref-tables/upsert-one-header-set.js +208 -0
- package/lib/archive/populate-ref-tables/volatile-header-names.d.ts +20 -0
- package/lib/archive/populate-ref-tables/volatile-header-names.js +33 -0
- package/lib/archive/redirect-table.d.ts +4 -2
- package/lib/archive/redirect-table.js +15 -10
- package/lib/archive/resolve-redirect-chain.d.ts +3 -3
- package/lib/archive/resolve-redirect-chain.js +2 -2
- package/lib/archive/resource.d.ts +1 -1
- package/lib/archive/retarget-legacy-fk-tables.d.ts +47 -0
- package/lib/archive/retarget-legacy-fk-tables.js +107 -0
- package/lib/archive/test-utils/fk-parent-tables.d.ts +15 -0
- package/lib/archive/test-utils/fk-parent-tables.js +19 -0
- package/lib/archive/test-utils/seed-content-item.d.ts +35 -0
- package/lib/archive/test-utils/seed-content-item.js +42 -0
- package/lib/archive/test-utils/setup-legacy-fk-db.d.ts +33 -0
- package/lib/archive/test-utils/setup-legacy-fk-db.js +270 -0
- package/lib/archive/types.d.ts +151 -15
- package/lib/archive/verify-migration/capture-rejection.d.ts +24 -0
- package/lib/archive/verify-migration/capture-rejection.js +31 -0
- package/lib/archive/verify-migration/check-anchor-edges-count.d.ts +34 -0
- package/lib/archive/verify-migration/check-anchor-edges-count.js +72 -0
- package/lib/archive/verify-migration/check-anchor-edges-sum.d.ts +13 -0
- package/lib/archive/verify-migration/check-anchor-edges-sum.js +27 -0
- package/lib/archive/verify-migration/check-content-items-count.d.ts +16 -0
- package/lib/archive/verify-migration/check-content-items-count.js +30 -0
- package/lib/archive/verify-migration/check-content-type-preservation.d.ts +22 -0
- package/lib/archive/verify-migration/check-content-type-preservation.js +40 -0
- package/lib/archive/verify-migration/check-foreign-key-integrity.d.ts +31 -0
- package/lib/archive/verify-migration/check-foreign-key-integrity.js +47 -0
- package/lib/archive/verify-migration/check-image-items-count.d.ts +12 -0
- package/lib/archive/verify-migration/check-image-items-count.js +26 -0
- package/lib/archive/verify-migration/check-page-meta-count.d.ts +15 -0
- package/lib/archive/verify-migration/check-page-meta-count.js +31 -0
- package/lib/archive/verify-migration/check-reader-parity.d.ts +23 -0
- package/lib/archive/verify-migration/check-reader-parity.js +211 -0
- package/lib/archive/verify-migration/check-resource-items-count.d.ts +17 -0
- package/lib/archive/verify-migration/check-resource-items-count.js +33 -0
- package/lib/archive/verify-migration/check-url-round-trip.d.ts +43 -0
- package/lib/archive/verify-migration/check-url-round-trip.js +112 -0
- package/lib/archive/verify-migration/types.d.ts +70 -0
- package/lib/archive/verify-migration/types.js +63 -0
- package/lib/archive/verify-migration/verify-migration.d.ts +41 -0
- package/lib/archive/verify-migration/verify-migration.js +120 -0
- package/lib/classify-error-kind.d.ts +19 -0
- package/lib/classify-error-kind.js +122 -0
- package/lib/crawler/build-js-redirect-edge.d.ts +68 -0
- package/lib/crawler/build-js-redirect-edge.js +57 -0
- package/lib/crawler/build-redirect-event.d.ts +24 -0
- package/lib/crawler/build-redirect-event.js +28 -0
- package/lib/crawler/capture-image-dom-paths.d.ts +33 -0
- package/lib/crawler/capture-image-dom-paths.js +39 -0
- package/lib/crawler/clear-dns-burned-host-cache.d.ts +6 -0
- package/lib/crawler/clear-dns-burned-host-cache.js +11 -0
- package/lib/crawler/collect-image-dom-paths.d.ts +23 -0
- package/lib/crawler/collect-image-dom-paths.js +64 -0
- package/lib/crawler/crawler.d.ts +22 -1
- package/lib/crawler/crawler.js +679 -117
- package/lib/crawler/derive-js-redirect-target.d.ts +68 -0
- package/lib/crawler/derive-js-redirect-target.js +129 -0
- package/lib/crawler/derive-resource-source.d.ts +25 -15
- package/lib/crawler/derive-resource-source.js +28 -17
- package/lib/crawler/dns-burned-host-cache.d.ts +26 -0
- package/lib/crawler/dns-burned-host-cache.js +25 -0
- package/lib/crawler/dns-burned-host-short-circuit-counter.d.ts +13 -0
- package/lib/crawler/dns-burned-host-short-circuit-counter.js +11 -0
- package/lib/crawler/fetch-destination.d.ts +12 -4
- package/lib/crawler/fetch-destination.js +94 -16
- package/lib/crawler/inject-scope-auth.d.ts +1 -1
- package/lib/crawler/inject-scope-auth.js +1 -1
- package/lib/crawler/is-js-redirect-error-shape.d.ts +40 -0
- package/lib/crawler/is-js-redirect-error-shape.js +53 -0
- package/lib/crawler/is-puppeteer-fallback-candidate.d.ts +16 -0
- package/lib/crawler/is-puppeteer-fallback-candidate.js +63 -0
- package/lib/crawler/link-list.d.ts +21 -1
- package/lib/crawler/link-list.js +23 -3
- package/lib/crawler/normalize-content-type.d.ts +1 -1
- package/lib/crawler/normalize-content-type.js +1 -1
- package/lib/crawler/plan-sub-resource-emits.d.ts +63 -0
- package/lib/crawler/plan-sub-resource-emits.js +44 -0
- package/lib/crawler/preload-short-circuit-error.d.ts +22 -0
- package/lib/crawler/preload-short-circuit-error.js +25 -0
- package/lib/crawler/should-burn-host.d.ts +78 -0
- package/lib/crawler/should-burn-host.js +61 -0
- package/lib/crawler/should-get-fallback-on-head-failure.d.ts +38 -0
- package/lib/crawler/should-get-fallback-on-head-failure.js +46 -0
- package/lib/crawler/types.d.ts +108 -1
- package/lib/crawler-orchestrator.d.ts +22 -3
- package/lib/crawler-orchestrator.js +312 -73
- package/lib/crawler.d.ts +15 -2
- package/lib/crawler.js +24 -1
- package/lib/permanent-error-kinds.d.ts +43 -0
- package/lib/permanent-error-kinds.js +48 -0
- package/lib/types.d.ts +84 -0
- package/lib/utils/compute-file-sha256.d.ts +24 -0
- package/lib/utils/compute-file-sha256.js +56 -0
- package/lib/utils/error/emit-error-with-retry.d.ts +40 -0
- package/lib/utils/error/emit-error-with-retry.js +44 -0
- package/lib/utils/error/emit-error.d.ts +39 -0
- package/lib/utils/error/emit-error.js +41 -0
- package/package.json +12 -12
- package/lib/archive/migrate-crawl-errors.d.ts +0 -20
- package/lib/archive/migrate-crawl-errors.js +0 -38
- package/lib/archive/migrate-html-blob-tables.d.ts +0 -24
- package/lib/archive/migrate-html-blob-tables.js +0 -53
- package/lib/archive/migrate-page-errors.d.ts +0 -16
- package/lib/archive/migrate-page-errors.js +0 -35
- package/lib/archive/migrate-pages-resources-source.d.ts +0 -16
- package/lib/archive/migrate-pages-resources-source.js +0 -46
- package/lib/utils/error/error-emitter.d.ts +0 -18
- package/lib/utils/error/error-emitter.js +0 -29
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the entire `content_type_refs` dictionary into an in-process map
|
|
3
|
+
* keyed by the raw wire value (issue #193).
|
|
4
|
+
*
|
|
5
|
+
* Content-type cardinality is small in practice — the reference archive
|
|
6
|
+
* carries ≈ 400 distinct raw values across `pages` + `resources`, so
|
|
7
|
+
* loading everything into a `Map` costs ≈ 40 KB and eliminates every
|
|
8
|
+
* per-chunk round-trip. This is the same trade-off {@link
|
|
9
|
+
* ../populate-ref-tables/populate-header-tables.ts} makes for `header_name_refs`.
|
|
10
|
+
*
|
|
11
|
+
* Callers should invoke this once at the start of a 0.13 populate
|
|
12
|
+
* step (e.g. `populateContentItems`, `populateResourceItems`) and reuse
|
|
13
|
+
* the map for every chunk.
|
|
14
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
15
|
+
* @returns Map keyed by `content_type_refs.raw`.
|
|
16
|
+
* @example
|
|
17
|
+
* const contentTypeIds = await loadContentTypeRefs(trx);
|
|
18
|
+
* const id = contentTypeIds.get('text/html; charset=utf-8'); // number | undefined
|
|
19
|
+
*/
|
|
20
|
+
export async function loadContentTypeRefs(trx) {
|
|
21
|
+
const rows = await trx('content_type_refs').select('id', 'raw');
|
|
22
|
+
const map = new Map();
|
|
23
|
+
for (const row of rows) {
|
|
24
|
+
map.set(row.raw, row.id);
|
|
25
|
+
}
|
|
26
|
+
return map;
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { HeaderSetIdMap } from './types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Batch-resolves `header_sets.id` for a set of raw `responseHeaders`
|
|
5
|
+
* JSON strings (issue #193).
|
|
6
|
+
*
|
|
7
|
+
* The lookup is a two-stage cascade:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Primary lookup** by `header_sets.raw_json_hash` — SHA-256 of the
|
|
10
|
+
* raw JSON string exactly as stored on the source row. This hits when
|
|
11
|
+
* the row's JSON key ordering matches whichever ordering populated
|
|
12
|
+
* `header_sets` first for that stable-set equivalence class (see
|
|
13
|
+
* {@link ../populate-ref-tables/populate-header-tables.ts}).
|
|
14
|
+
* 2. **Fallback lookup** by `header_sets.raw_hash` for the misses — SHA-
|
|
15
|
+
* 256 of the sorted `name=value` pairs. `populate-header-tables.ts`
|
|
16
|
+
* stores exactly one `raw_json_hash` per `raw_hash` equivalence class
|
|
17
|
+
* (the first JSON variant encountered), so a second variant with
|
|
18
|
+
* identical decoded content but different key ordering never had its
|
|
19
|
+
* `raw_json_hash` persisted — but its `raw_hash` still points at the
|
|
20
|
+
* shared `header_sets` row. Without the fallback these rows would
|
|
21
|
+
* silently get `header_set_id = NULL` on `content_items` /
|
|
22
|
+
* `resource_items` and the count-based acceptance check would still
|
|
23
|
+
* pass; the fallback closes that gap.
|
|
24
|
+
*
|
|
25
|
+
* Hashes are computed in JS because SQLite has no built-in BLAKE3 /
|
|
26
|
+
* SHA-256 (see {@link ../populate-ref-tables/compute-content-hash.ts} for the
|
|
27
|
+
* algorithm choice). The `raw_hash` fallback re-decomposes each miss via
|
|
28
|
+
* {@link ../populate-ref-tables/decompose-header-set.ts} so the canonicalisation
|
|
29
|
+
* matches the one `populateHeaderTables` used at insert time.
|
|
30
|
+
*
|
|
31
|
+
* Empty / null values and the sentinel `'{}'` / `'null'` strings are
|
|
32
|
+
* skipped — those responses were decomposed to `null` by
|
|
33
|
+
* `decomposeHeaderSet` and never produced a `header_sets` row, so the
|
|
34
|
+
* caller writes `header_set_id = null` for them.
|
|
35
|
+
*
|
|
36
|
+
* Duplicate JSON strings are deduped internally so a page and a
|
|
37
|
+
* resource sharing the same raw responseHeaders JSON only contribute
|
|
38
|
+
* one lookup slot.
|
|
39
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
40
|
+
* @param rawJsonStrings - Iterable of raw responseHeaders JSON strings.
|
|
41
|
+
* @returns Map keyed by the raw JSON string; missing entries indicate
|
|
42
|
+
* no matching `header_sets` row exists (parse failure or empty set).
|
|
43
|
+
* @example
|
|
44
|
+
* const idMap = await resolveHeaderSets(trx, [
|
|
45
|
+
* '{"content-type":"text/html"}',
|
|
46
|
+
* ]);
|
|
47
|
+
* const setId = idMap.get('{"content-type":"text/html"}'); // number | undefined
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveHeaderSets(trx: Knex, rawJsonStrings: Iterable<string>): Promise<HeaderSetIdMap>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { computeContentHash } from '../populate-ref-tables/compute-content-hash.js';
|
|
2
|
+
import { decomposeHeaderSet } from '../populate-ref-tables/decompose-header-set.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rows sent per `SELECT ... WHERE raw_json_hash IN (?, ...)` chunk. Same
|
|
5
|
+
* rationale as {@link ./resolve-url-refs.ts}: 500 rows × 1 param each is
|
|
6
|
+
* well under the SQLite variable limit and gives good round-trip
|
|
7
|
+
* amortisation.
|
|
8
|
+
*/
|
|
9
|
+
const LOOKUP_CHUNK_SIZE = 500;
|
|
10
|
+
/**
|
|
11
|
+
* Batch-resolves `header_sets.id` for a set of raw `responseHeaders`
|
|
12
|
+
* JSON strings (issue #193).
|
|
13
|
+
*
|
|
14
|
+
* The lookup is a two-stage cascade:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Primary lookup** by `header_sets.raw_json_hash` — SHA-256 of the
|
|
17
|
+
* raw JSON string exactly as stored on the source row. This hits when
|
|
18
|
+
* the row's JSON key ordering matches whichever ordering populated
|
|
19
|
+
* `header_sets` first for that stable-set equivalence class (see
|
|
20
|
+
* {@link ../populate-ref-tables/populate-header-tables.ts}).
|
|
21
|
+
* 2. **Fallback lookup** by `header_sets.raw_hash` for the misses — SHA-
|
|
22
|
+
* 256 of the sorted `name=value` pairs. `populate-header-tables.ts`
|
|
23
|
+
* stores exactly one `raw_json_hash` per `raw_hash` equivalence class
|
|
24
|
+
* (the first JSON variant encountered), so a second variant with
|
|
25
|
+
* identical decoded content but different key ordering never had its
|
|
26
|
+
* `raw_json_hash` persisted — but its `raw_hash` still points at the
|
|
27
|
+
* shared `header_sets` row. Without the fallback these rows would
|
|
28
|
+
* silently get `header_set_id = NULL` on `content_items` /
|
|
29
|
+
* `resource_items` and the count-based acceptance check would still
|
|
30
|
+
* pass; the fallback closes that gap.
|
|
31
|
+
*
|
|
32
|
+
* Hashes are computed in JS because SQLite has no built-in BLAKE3 /
|
|
33
|
+
* SHA-256 (see {@link ../populate-ref-tables/compute-content-hash.ts} for the
|
|
34
|
+
* algorithm choice). The `raw_hash` fallback re-decomposes each miss via
|
|
35
|
+
* {@link ../populate-ref-tables/decompose-header-set.ts} so the canonicalisation
|
|
36
|
+
* matches the one `populateHeaderTables` used at insert time.
|
|
37
|
+
*
|
|
38
|
+
* Empty / null values and the sentinel `'{}'` / `'null'` strings are
|
|
39
|
+
* skipped — those responses were decomposed to `null` by
|
|
40
|
+
* `decomposeHeaderSet` and never produced a `header_sets` row, so the
|
|
41
|
+
* caller writes `header_set_id = null` for them.
|
|
42
|
+
*
|
|
43
|
+
* Duplicate JSON strings are deduped internally so a page and a
|
|
44
|
+
* resource sharing the same raw responseHeaders JSON only contribute
|
|
45
|
+
* one lookup slot.
|
|
46
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
47
|
+
* @param rawJsonStrings - Iterable of raw responseHeaders JSON strings.
|
|
48
|
+
* @returns Map keyed by the raw JSON string; missing entries indicate
|
|
49
|
+
* no matching `header_sets` row exists (parse failure or empty set).
|
|
50
|
+
* @example
|
|
51
|
+
* const idMap = await resolveHeaderSets(trx, [
|
|
52
|
+
* '{"content-type":"text/html"}',
|
|
53
|
+
* ]);
|
|
54
|
+
* const setId = idMap.get('{"content-type":"text/html"}'); // number | undefined
|
|
55
|
+
*/
|
|
56
|
+
export async function resolveHeaderSets(trx, rawJsonStrings) {
|
|
57
|
+
const distinct = new Set();
|
|
58
|
+
for (const raw of rawJsonStrings) {
|
|
59
|
+
if (typeof raw !== 'string' || raw === '' || raw === 'null' || raw === '{}') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
distinct.add(raw);
|
|
63
|
+
}
|
|
64
|
+
if (distinct.size === 0) {
|
|
65
|
+
return new Map();
|
|
66
|
+
}
|
|
67
|
+
const values = [...distinct];
|
|
68
|
+
const hashByValue = new Map();
|
|
69
|
+
const hashHexToValue = new Map();
|
|
70
|
+
for (const value of values) {
|
|
71
|
+
const hash = computeContentHash(value);
|
|
72
|
+
hashByValue.set(value, hash);
|
|
73
|
+
hashHexToValue.set(hash.toString('hex'), value);
|
|
74
|
+
}
|
|
75
|
+
const hashes = [...hashByValue.values()];
|
|
76
|
+
const result = new Map();
|
|
77
|
+
for (let index = 0; index < hashes.length; index += LOOKUP_CHUNK_SIZE) {
|
|
78
|
+
const chunkHashes = hashes.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
79
|
+
const rows = await trx('header_sets')
|
|
80
|
+
.select('id', 'raw_json_hash')
|
|
81
|
+
.whereIn('raw_json_hash', chunkHashes);
|
|
82
|
+
for (const row of rows) {
|
|
83
|
+
const hex = Buffer.from(row.raw_json_hash).toString('hex');
|
|
84
|
+
const value = hashHexToValue.get(hex);
|
|
85
|
+
if (value !== undefined) {
|
|
86
|
+
result.set(value, row.id);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Fallback pass: any value we could not resolve by `raw_json_hash`
|
|
91
|
+
// might still map to an existing `header_sets` row via `raw_hash`
|
|
92
|
+
// (identical decoded content, different JSON key ordering).
|
|
93
|
+
const misses = values.filter((value) => !result.has(value));
|
|
94
|
+
if (misses.length === 0) {
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
const rawHashByValue = new Map();
|
|
98
|
+
const rawHashHexToValue = new Map();
|
|
99
|
+
for (const value of misses) {
|
|
100
|
+
const decomposed = decomposeHeaderSet(value);
|
|
101
|
+
if (decomposed === null) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
rawHashByValue.set(value, decomposed.rawHash);
|
|
105
|
+
rawHashHexToValue.set(decomposed.rawHash.toString('hex'), value);
|
|
106
|
+
}
|
|
107
|
+
const rawHashes = [...rawHashByValue.values()];
|
|
108
|
+
for (let index = 0; index < rawHashes.length; index += LOOKUP_CHUNK_SIZE) {
|
|
109
|
+
const chunkHashes = rawHashes.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
110
|
+
const rows = await trx('header_sets')
|
|
111
|
+
.select('id', 'raw_hash')
|
|
112
|
+
.whereIn('raw_hash', chunkHashes);
|
|
113
|
+
for (const row of rows) {
|
|
114
|
+
const hex = Buffer.from(row.raw_hash).toString('hex');
|
|
115
|
+
const value = rawHashHexToValue.get(hex);
|
|
116
|
+
if (value !== undefined) {
|
|
117
|
+
result.set(value, row.id);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Batch-resolves `json_refs.id` for a set of raw `meta_extras` JSON
|
|
4
|
+
* strings (issue #193).
|
|
5
|
+
*
|
|
6
|
+
* The lookup goes through `json_refs.hash`, the SHA-256 hash of the raw
|
|
7
|
+
* JSON string stored by `populateJsonRefs` (see
|
|
8
|
+
* {@link ../populate-ref-tables/populate-json-refs.ts}). Hashes are computed in JS
|
|
9
|
+
* for the same reason as {@link ./resolve-header-sets.ts}: SQLite has no
|
|
10
|
+
* built-in hash function.
|
|
11
|
+
*
|
|
12
|
+
* Empty / null strings are skipped — those pages had no `meta_extras`
|
|
13
|
+
* and never produced a `json_refs` row, so the caller writes
|
|
14
|
+
* `meta_extras_json_id = null` for them.
|
|
15
|
+
*
|
|
16
|
+
* Duplicate strings in `rawJsonStrings` are deduped internally.
|
|
17
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
18
|
+
* @param rawJsonStrings - Iterable of raw `meta_extras` JSON strings.
|
|
19
|
+
* @returns Map keyed by the raw JSON string; missing entries indicate
|
|
20
|
+
* no matching `json_refs` row exists.
|
|
21
|
+
* @example
|
|
22
|
+
* const idMap = await resolveJsonRefs(trx, ['{"customField":"x"}']);
|
|
23
|
+
* const jsonId = idMap.get('{"customField":"x"}'); // number | undefined
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveJsonRefs(trx: Knex, rawJsonStrings: Iterable<string>): Promise<ReadonlyMap<string, number>>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { computeContentHash } from '../populate-ref-tables/compute-content-hash.js';
|
|
2
|
+
/**
|
|
3
|
+
* Rows sent per `SELECT ... WHERE hash IN (?, ...)` chunk. `json_refs`
|
|
4
|
+
* cardinality is bounded by the count of distinct `pages.meta_extras`
|
|
5
|
+
* JSON strings — typically low thousands on a reference archive — so
|
|
6
|
+
* 500 per chunk keeps round-trips low without straining the SQLite
|
|
7
|
+
* variable limit.
|
|
8
|
+
*/
|
|
9
|
+
const LOOKUP_CHUNK_SIZE = 500;
|
|
10
|
+
/**
|
|
11
|
+
* Batch-resolves `json_refs.id` for a set of raw `meta_extras` JSON
|
|
12
|
+
* strings (issue #193).
|
|
13
|
+
*
|
|
14
|
+
* The lookup goes through `json_refs.hash`, the SHA-256 hash of the raw
|
|
15
|
+
* JSON string stored by `populateJsonRefs` (see
|
|
16
|
+
* {@link ../populate-ref-tables/populate-json-refs.ts}). Hashes are computed in JS
|
|
17
|
+
* for the same reason as {@link ./resolve-header-sets.ts}: SQLite has no
|
|
18
|
+
* built-in hash function.
|
|
19
|
+
*
|
|
20
|
+
* Empty / null strings are skipped — those pages had no `meta_extras`
|
|
21
|
+
* and never produced a `json_refs` row, so the caller writes
|
|
22
|
+
* `meta_extras_json_id = null` for them.
|
|
23
|
+
*
|
|
24
|
+
* Duplicate strings in `rawJsonStrings` are deduped internally.
|
|
25
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
26
|
+
* @param rawJsonStrings - Iterable of raw `meta_extras` JSON strings.
|
|
27
|
+
* @returns Map keyed by the raw JSON string; missing entries indicate
|
|
28
|
+
* no matching `json_refs` row exists.
|
|
29
|
+
* @example
|
|
30
|
+
* const idMap = await resolveJsonRefs(trx, ['{"customField":"x"}']);
|
|
31
|
+
* const jsonId = idMap.get('{"customField":"x"}'); // number | undefined
|
|
32
|
+
*/
|
|
33
|
+
export async function resolveJsonRefs(trx, rawJsonStrings) {
|
|
34
|
+
const distinct = new Set();
|
|
35
|
+
for (const raw of rawJsonStrings) {
|
|
36
|
+
if (typeof raw === 'string' && raw !== '') {
|
|
37
|
+
distinct.add(raw);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (distinct.size === 0) {
|
|
41
|
+
return new Map();
|
|
42
|
+
}
|
|
43
|
+
const values = [...distinct];
|
|
44
|
+
const hashByValue = new Map();
|
|
45
|
+
const hashHexToValue = new Map();
|
|
46
|
+
for (const value of values) {
|
|
47
|
+
const hash = computeContentHash(value);
|
|
48
|
+
hashByValue.set(value, hash);
|
|
49
|
+
hashHexToValue.set(hash.toString('hex'), value);
|
|
50
|
+
}
|
|
51
|
+
const hashes = [...hashByValue.values()];
|
|
52
|
+
const result = new Map();
|
|
53
|
+
for (let index = 0; index < hashes.length; index += LOOKUP_CHUNK_SIZE) {
|
|
54
|
+
const chunkHashes = hashes.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
55
|
+
const rows = await trx('json_refs')
|
|
56
|
+
.select('id', 'hash')
|
|
57
|
+
.whereIn('hash', chunkHashes);
|
|
58
|
+
for (const row of rows) {
|
|
59
|
+
const hex = Buffer.from(row.hash).toString('hex');
|
|
60
|
+
const value = hashHexToValue.get(hex);
|
|
61
|
+
if (value !== undefined) {
|
|
62
|
+
result.set(value, row.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TextRefIdMap } from './types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Batch-resolves `text_refs.id` for a set of raw text strings (issue #193).
|
|
5
|
+
*
|
|
6
|
+
* The `text_refs` UNIQUE constraint is on `(hash, text)` so lookups
|
|
7
|
+
* prefix-seek on `hash`. Each caller-supplied text is hashed in JS via
|
|
8
|
+
* {@link ../populate-ref-tables/compute-content-hash.ts} (32-byte SHA-256, matching
|
|
9
|
+
* how `populateTextRefs` inserted the rows) before the
|
|
10
|
+
* SQL query; providing the hash lets SQLite's index seek in O(log n)
|
|
11
|
+
* without a full table scan.
|
|
12
|
+
*
|
|
13
|
+
* The `(hash, text)` UNIQUE composite makes the trailing text column
|
|
14
|
+
* theoretically necessary to disambiguate the astronomically improbable
|
|
15
|
+
* hash collision — we narrow on both by including `text` in the WHERE
|
|
16
|
+
* clause, then filter the map keys by the exact text on read-back.
|
|
17
|
+
*
|
|
18
|
+
* Empty / null texts are ignored. Duplicate strings in `texts` are
|
|
19
|
+
* deduped internally.
|
|
20
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
21
|
+
* @param texts - Iterable of raw text strings to resolve.
|
|
22
|
+
* @returns Map keyed by the raw text; missing entries indicate the text
|
|
23
|
+
* is not present in `text_refs` (which should not happen after
|
|
24
|
+
* `populateTextRefs` completes but does happen mid-migration when a caller
|
|
25
|
+
* passes texts that were never inserted).
|
|
26
|
+
* @example
|
|
27
|
+
* const idMap = await resolveTextRefs(trx, ['My Page Title', 'Alt text']);
|
|
28
|
+
* const titleId = idMap.get('My Page Title'); // number | undefined
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveTextRefs(trx: Knex, texts: Iterable<string>): Promise<TextRefIdMap>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { computeContentHash } from '../populate-ref-tables/compute-content-hash.js';
|
|
2
|
+
/**
|
|
3
|
+
* Rows sent per `SELECT ... WHERE hash IN (?, ...)` chunk. Same rationale
|
|
4
|
+
* as {@link ./resolve-url-refs.ts}: 800 rows keeps the parameter count
|
|
5
|
+
* well under the SQLite variable limit even in the worst case where every
|
|
6
|
+
* hash is bound as its own parameter.
|
|
7
|
+
*/
|
|
8
|
+
const LOOKUP_CHUNK_SIZE = 800;
|
|
9
|
+
/**
|
|
10
|
+
* Batch-resolves `text_refs.id` for a set of raw text strings (issue #193).
|
|
11
|
+
*
|
|
12
|
+
* The `text_refs` UNIQUE constraint is on `(hash, text)` so lookups
|
|
13
|
+
* prefix-seek on `hash`. Each caller-supplied text is hashed in JS via
|
|
14
|
+
* {@link ../populate-ref-tables/compute-content-hash.ts} (32-byte SHA-256, matching
|
|
15
|
+
* how `populateTextRefs` inserted the rows) before the
|
|
16
|
+
* SQL query; providing the hash lets SQLite's index seek in O(log n)
|
|
17
|
+
* without a full table scan.
|
|
18
|
+
*
|
|
19
|
+
* The `(hash, text)` UNIQUE composite makes the trailing text column
|
|
20
|
+
* theoretically necessary to disambiguate the astronomically improbable
|
|
21
|
+
* hash collision — we narrow on both by including `text` in the WHERE
|
|
22
|
+
* clause, then filter the map keys by the exact text on read-back.
|
|
23
|
+
*
|
|
24
|
+
* Empty / null texts are ignored. Duplicate strings in `texts` are
|
|
25
|
+
* deduped internally.
|
|
26
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
27
|
+
* @param texts - Iterable of raw text strings to resolve.
|
|
28
|
+
* @returns Map keyed by the raw text; missing entries indicate the text
|
|
29
|
+
* is not present in `text_refs` (which should not happen after
|
|
30
|
+
* `populateTextRefs` completes but does happen mid-migration when a caller
|
|
31
|
+
* passes texts that were never inserted).
|
|
32
|
+
* @example
|
|
33
|
+
* const idMap = await resolveTextRefs(trx, ['My Page Title', 'Alt text']);
|
|
34
|
+
* const titleId = idMap.get('My Page Title'); // number | undefined
|
|
35
|
+
*/
|
|
36
|
+
export async function resolveTextRefs(trx, texts) {
|
|
37
|
+
const distinct = new Set();
|
|
38
|
+
for (const text of texts) {
|
|
39
|
+
if (typeof text === 'string' && text !== '') {
|
|
40
|
+
distinct.add(text);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (distinct.size === 0) {
|
|
44
|
+
return new Map();
|
|
45
|
+
}
|
|
46
|
+
const values = [...distinct];
|
|
47
|
+
const hashes = values.map((text) => computeContentHash(text));
|
|
48
|
+
const result = new Map();
|
|
49
|
+
for (let index = 0; index < values.length; index += LOOKUP_CHUNK_SIZE) {
|
|
50
|
+
const chunkValues = values.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
51
|
+
const chunkHashes = hashes.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
52
|
+
const rows = await trx('text_refs')
|
|
53
|
+
.select('id', 'hash', 'text')
|
|
54
|
+
.whereIn('hash', chunkHashes)
|
|
55
|
+
.whereIn('text', chunkValues);
|
|
56
|
+
for (const row of rows) {
|
|
57
|
+
result.set(row.text, row.id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes one legacy URL-shaped value to either `url_refs` or `blob_refs`
|
|
3
|
+
* per the {@link isBlobRefValue} threshold rule, looking the id up in
|
|
4
|
+
* pre-resolved maps rather than upserting (the populate steps batch-resolve
|
|
5
|
+
* every distinct value across a whole chunk before this per-row lookup —
|
|
6
|
+
* see `resolveUrlRefs` / `resolveBlobRefs`). At most one of `url` / `blob`
|
|
7
|
+
* is non-null; both may be `null` when the value is null or fails to
|
|
8
|
+
* resolve (e.g. the `blob_refs` row is missing because the data URI was
|
|
9
|
+
* malformed and skipped by `populateBlobRefs`).
|
|
10
|
+
* @param value - Raw URL-shaped column value.
|
|
11
|
+
* @param urlIds - Map of URL string → `url_refs.id`.
|
|
12
|
+
* @param blobIds - Map of data-URI string → `blob_refs.id`.
|
|
13
|
+
* @returns `{ url, blob }` pair with at most one non-null field.
|
|
14
|
+
* @example
|
|
15
|
+
* const slot = resolveUrlOrBlobFromMaps(row.src, urlIds, blobIds);
|
|
16
|
+
* // slot.url set for a regular URL, slot.blob set for a large data: URI.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveUrlOrBlobFromMaps(value: string | null, urlIds: ReadonlyMap<string, number>, blobIds: ReadonlyMap<string, number>): {
|
|
19
|
+
url: number | null;
|
|
20
|
+
blob: number | null;
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isBlobRefValue } from './is-blob-ref-value.js';
|
|
2
|
+
/**
|
|
3
|
+
* Routes one legacy URL-shaped value to either `url_refs` or `blob_refs`
|
|
4
|
+
* per the {@link isBlobRefValue} threshold rule, looking the id up in
|
|
5
|
+
* pre-resolved maps rather than upserting (the populate steps batch-resolve
|
|
6
|
+
* every distinct value across a whole chunk before this per-row lookup —
|
|
7
|
+
* see `resolveUrlRefs` / `resolveBlobRefs`). At most one of `url` / `blob`
|
|
8
|
+
* is non-null; both may be `null` when the value is null or fails to
|
|
9
|
+
* resolve (e.g. the `blob_refs` row is missing because the data URI was
|
|
10
|
+
* malformed and skipped by `populateBlobRefs`).
|
|
11
|
+
* @param value - Raw URL-shaped column value.
|
|
12
|
+
* @param urlIds - Map of URL string → `url_refs.id`.
|
|
13
|
+
* @param blobIds - Map of data-URI string → `blob_refs.id`.
|
|
14
|
+
* @returns `{ url, blob }` pair with at most one non-null field.
|
|
15
|
+
* @example
|
|
16
|
+
* const slot = resolveUrlOrBlobFromMaps(row.src, urlIds, blobIds);
|
|
17
|
+
* // slot.url set for a regular URL, slot.blob set for a large data: URI.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveUrlOrBlobFromMaps(value, urlIds, blobIds) {
|
|
20
|
+
if (typeof value !== 'string' || value === '') {
|
|
21
|
+
return { url: null, blob: null };
|
|
22
|
+
}
|
|
23
|
+
if (isBlobRefValue(value)) {
|
|
24
|
+
return { url: null, blob: blobIds.get(value) ?? null };
|
|
25
|
+
}
|
|
26
|
+
return { url: urlIds.get(value) ?? null, blob: null };
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { UrlRefIdMap } from './types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Batch-resolves `url_refs.id` for a set of URL strings (issue #193).
|
|
5
|
+
*
|
|
6
|
+
* Called by every entity populate helper that needs to translate a
|
|
7
|
+
* legacy URL string column into a `url_id` FK. Rather than open a
|
|
8
|
+
* separate SELECT per row (which multiplies migration wall-clock by
|
|
9
|
+
* chunk size × URL column count) the resolver collects the distinct
|
|
10
|
+
* strings the caller cares about, splits them into chunks of
|
|
11
|
+
* {@link LOOKUP_CHUNK_SIZE}, issues one `WHERE url IN (?, ...)` per
|
|
12
|
+
* chunk, and returns a single map.
|
|
13
|
+
*
|
|
14
|
+
* Missing entries fall out of the map — callers distinguish "URL is a
|
|
15
|
+
* large data URI routed to blob_refs" from "URL is absent from the
|
|
16
|
+
* dictionary" via a separate {@link ./resolve-blob-refs.ts} probe.
|
|
17
|
+
*
|
|
18
|
+
* Duplicates in `urls` are deduped internally so an image whose `src`
|
|
19
|
+
* and `currentSrc` are the same value only counts once against
|
|
20
|
+
* `LOOKUP_CHUNK_SIZE`.
|
|
21
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
22
|
+
* @param urls - Iterable of URL strings to resolve. Empty and null-like
|
|
23
|
+
* values are ignored.
|
|
24
|
+
* @returns Map keyed by the raw URL string; missing entries indicate
|
|
25
|
+
* the URL is not present in `url_refs`.
|
|
26
|
+
* @example
|
|
27
|
+
* const idMap = await resolveUrlRefs(trx, [
|
|
28
|
+
* 'https://example.com/a',
|
|
29
|
+
* 'https://example.com/b',
|
|
30
|
+
* ]);
|
|
31
|
+
* const id = idMap.get('https://example.com/a'); // number | undefined
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveUrlRefs(trx: Knex, urls: Iterable<string>): Promise<UrlRefIdMap>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rows sent per `SELECT ... WHERE url IN (?, ...)` chunk. SQLite's default
|
|
3
|
+
* `SQLITE_MAX_VARIABLE_NUMBER` is 32766 on modern builds — 800 URLs per
|
|
4
|
+
* chunk stays well under that while amortising the round-trip cost across
|
|
5
|
+
* many rows.
|
|
6
|
+
*/
|
|
7
|
+
const LOOKUP_CHUNK_SIZE = 800;
|
|
8
|
+
/**
|
|
9
|
+
* Batch-resolves `url_refs.id` for a set of URL strings (issue #193).
|
|
10
|
+
*
|
|
11
|
+
* Called by every entity populate helper that needs to translate a
|
|
12
|
+
* legacy URL string column into a `url_id` FK. Rather than open a
|
|
13
|
+
* separate SELECT per row (which multiplies migration wall-clock by
|
|
14
|
+
* chunk size × URL column count) the resolver collects the distinct
|
|
15
|
+
* strings the caller cares about, splits them into chunks of
|
|
16
|
+
* {@link LOOKUP_CHUNK_SIZE}, issues one `WHERE url IN (?, ...)` per
|
|
17
|
+
* chunk, and returns a single map.
|
|
18
|
+
*
|
|
19
|
+
* Missing entries fall out of the map — callers distinguish "URL is a
|
|
20
|
+
* large data URI routed to blob_refs" from "URL is absent from the
|
|
21
|
+
* dictionary" via a separate {@link ./resolve-blob-refs.ts} probe.
|
|
22
|
+
*
|
|
23
|
+
* Duplicates in `urls` are deduped internally so an image whose `src`
|
|
24
|
+
* and `currentSrc` are the same value only counts once against
|
|
25
|
+
* `LOOKUP_CHUNK_SIZE`.
|
|
26
|
+
* @param trx - Knex instance or transaction connected to the archive DB.
|
|
27
|
+
* @param urls - Iterable of URL strings to resolve. Empty and null-like
|
|
28
|
+
* values are ignored.
|
|
29
|
+
* @returns Map keyed by the raw URL string; missing entries indicate
|
|
30
|
+
* the URL is not present in `url_refs`.
|
|
31
|
+
* @example
|
|
32
|
+
* const idMap = await resolveUrlRefs(trx, [
|
|
33
|
+
* 'https://example.com/a',
|
|
34
|
+
* 'https://example.com/b',
|
|
35
|
+
* ]);
|
|
36
|
+
* const id = idMap.get('https://example.com/a'); // number | undefined
|
|
37
|
+
*/
|
|
38
|
+
export async function resolveUrlRefs(trx, urls) {
|
|
39
|
+
const distinct = new Set();
|
|
40
|
+
for (const url of urls) {
|
|
41
|
+
if (typeof url === 'string' && url !== '') {
|
|
42
|
+
distinct.add(url);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (distinct.size === 0) {
|
|
46
|
+
return new Map();
|
|
47
|
+
}
|
|
48
|
+
const values = [...distinct];
|
|
49
|
+
const result = new Map();
|
|
50
|
+
for (let index = 0; index < values.length; index += LOOKUP_CHUNK_SIZE) {
|
|
51
|
+
const chunk = values.slice(index, index + LOOKUP_CHUNK_SIZE);
|
|
52
|
+
const rows = await trx('url_refs')
|
|
53
|
+
.select('id', 'url')
|
|
54
|
+
.whereIn('url', chunk);
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
result.set(row.url, row.id);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Runs `SELECT count(<countColumn>) FROM <table>` and returns the count
|
|
4
|
+
* as a plain JS number. Kept in this package instead of importing from
|
|
5
|
+
* `populate-ref-tables/test-utils/count-rows.ts` because a spec in populate-entities importing
|
|
6
|
+
* from populate-refs test-utils would establish a cross-directory test-utils
|
|
7
|
+
* dependency; the populate-refs copy has the same shape but its default
|
|
8
|
+
* countColumn is scoped to that phase's tables. Duplication is minimal
|
|
9
|
+
* and keeps each phase's test scaffolding self-contained.
|
|
10
|
+
* @param db - Knex instance (typically a spec-local in-memory DB).
|
|
11
|
+
* @param table - Table name.
|
|
12
|
+
* @param countColumn - Column to count; defaults to `'*'` so this helper
|
|
13
|
+
* works uniformly across `content_items` / `page_meta` /
|
|
14
|
+
* `resource_ref_edges` (some of which do not have an `id` column).
|
|
15
|
+
* @returns Row count.
|
|
16
|
+
*/
|
|
17
|
+
export declare function countRows(db: Knex, table: string, countColumn?: string): Promise<number>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `SELECT count(<countColumn>) FROM <table>` and returns the count
|
|
3
|
+
* as a plain JS number. Kept in this package instead of importing from
|
|
4
|
+
* `populate-ref-tables/test-utils/count-rows.ts` because a spec in populate-entities importing
|
|
5
|
+
* from populate-refs test-utils would establish a cross-directory test-utils
|
|
6
|
+
* dependency; the populate-refs copy has the same shape but its default
|
|
7
|
+
* countColumn is scoped to that phase's tables. Duplication is minimal
|
|
8
|
+
* and keeps each phase's test scaffolding self-contained.
|
|
9
|
+
* @param db - Knex instance (typically a spec-local in-memory DB).
|
|
10
|
+
* @param table - Table name.
|
|
11
|
+
* @param countColumn - Column to count; defaults to `'*'` so this helper
|
|
12
|
+
* works uniformly across `content_items` / `page_meta` /
|
|
13
|
+
* `resource_ref_edges` (some of which do not have an `id` column).
|
|
14
|
+
* @returns Row count.
|
|
15
|
+
*/
|
|
16
|
+
export async function countRows(db, table, countColumn = '*') {
|
|
17
|
+
const rows = await db(table).count({ n: countColumn });
|
|
18
|
+
const first = rows[0];
|
|
19
|
+
return Number(first.n);
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type knex from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Inserts one row into each of `pages`, `url_refs`, and `content_items` per
|
|
4
|
+
* requested id so downstream inserts against tables that FK to
|
|
5
|
+
* `content_items(id)` (`anchor_edges`, `image_items`, `page_meta`, …) satisfy
|
|
6
|
+
* their foreign key without every spec re-authoring the same 20 lines of
|
|
7
|
+
* seed logic.
|
|
8
|
+
*
|
|
9
|
+
* Shared by 0.13 check specs (`check-anchor-edges-count.spec.ts`,
|
|
10
|
+
* `check-anchor-edges-sum.spec.ts`, `check-image-items-count.spec.ts`,
|
|
11
|
+
* `verify-migration.spec.ts`) so a schema change to
|
|
12
|
+
* pages/url_refs/content_items only requires editing one file. Kept in
|
|
13
|
+
* `populate-entity-tables/test-utils/` alongside {@link setup-entities-db.ts} because that
|
|
14
|
+
* module already provisions the tables this helper writes to.
|
|
15
|
+
*
|
|
16
|
+
* Rows are inserted with defaults suitable for count / structural
|
|
17
|
+
* invariants: `scraped=1`, `isTarget=1`, `isExternal=0`, `source='crawled'`,
|
|
18
|
+
* URL `https://example.com/<id>` and matching `url_refs` row on the same id
|
|
19
|
+
* so `url_id` binds 1:1 with `pages.id` (helpful for URL round-trip specs).
|
|
20
|
+
* @param db - Knex handle from {@link setupMigrationDb}.
|
|
21
|
+
* @param ids - Content-item ids to create. Ordering does not matter but the
|
|
22
|
+
* helper does not deduplicate the input list — callers should pass
|
|
23
|
+
* distinct ids.
|
|
24
|
+
*/
|
|
25
|
+
export declare function seedContentItems(db: ReturnType<typeof knex>, ids: readonly number[]): Promise<void>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inserts one row into each of `pages`, `url_refs`, and `content_items` per
|
|
3
|
+
* requested id so downstream inserts against tables that FK to
|
|
4
|
+
* `content_items(id)` (`anchor_edges`, `image_items`, `page_meta`, …) satisfy
|
|
5
|
+
* their foreign key without every spec re-authoring the same 20 lines of
|
|
6
|
+
* seed logic.
|
|
7
|
+
*
|
|
8
|
+
* Shared by 0.13 check specs (`check-anchor-edges-count.spec.ts`,
|
|
9
|
+
* `check-anchor-edges-sum.spec.ts`, `check-image-items-count.spec.ts`,
|
|
10
|
+
* `verify-migration.spec.ts`) so a schema change to
|
|
11
|
+
* pages/url_refs/content_items only requires editing one file. Kept in
|
|
12
|
+
* `populate-entity-tables/test-utils/` alongside {@link setup-entities-db.ts} because that
|
|
13
|
+
* module already provisions the tables this helper writes to.
|
|
14
|
+
*
|
|
15
|
+
* Rows are inserted with defaults suitable for count / structural
|
|
16
|
+
* invariants: `scraped=1`, `isTarget=1`, `isExternal=0`, `source='crawled'`,
|
|
17
|
+
* URL `https://example.com/<id>` and matching `url_refs` row on the same id
|
|
18
|
+
* so `url_id` binds 1:1 with `pages.id` (helpful for URL round-trip specs).
|
|
19
|
+
* @param db - Knex handle from {@link setupMigrationDb}.
|
|
20
|
+
* @param ids - Content-item ids to create. Ordering does not matter but the
|
|
21
|
+
* helper does not deduplicate the input list — callers should pass
|
|
22
|
+
* distinct ids.
|
|
23
|
+
*/
|
|
24
|
+
export async function seedContentItems(db, ids) {
|
|
25
|
+
for (const id of ids) {
|
|
26
|
+
await db('pages').insert({
|
|
27
|
+
id,
|
|
28
|
+
url: `https://example.com/${id}`,
|
|
29
|
+
scraped: 1,
|
|
30
|
+
isTarget: 1,
|
|
31
|
+
});
|
|
32
|
+
await db('url_refs').insert({ id, url: `https://example.com/${id}` });
|
|
33
|
+
await db('content_items').insert({
|
|
34
|
+
id,
|
|
35
|
+
url_id: id,
|
|
36
|
+
is_external: 0,
|
|
37
|
+
scraped: 1,
|
|
38
|
+
is_target: 1,
|
|
39
|
+
source: 'crawled',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|