@nitpicker/crawler 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +63 -16
- package/lib/archive/archive.js +56 -17
- 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 +92 -345
- package/lib/archive/database.js +168 -1942
- 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 +1 -1
- package/lib/archive/derive-lineage-from-parent.js +1 -1
- 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 +5 -4
- package/lib/archive/get-failed-page-messages.js +5 -4
- package/lib/archive/init-schema.d.ts +35 -39
- package/lib/archive/init-schema.js +99 -460
- 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 +127 -24
- 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/crawler/build-redirect-event.d.ts +1 -1
- package/lib/crawler/build-redirect-event.js +1 -1
- 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 +1 -1
- package/lib/crawler/clear-dns-burned-host-cache.js +1 -1
- 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 +19 -0
- package/lib/crawler/crawler.js +40 -26
- package/lib/crawler/dns-burned-host-cache.d.ts +3 -3
- package/lib/crawler/dns-burned-host-cache.js +3 -3
- package/lib/crawler/dns-burned-host-short-circuit-counter.d.ts +2 -2
- package/lib/crawler/dns-burned-host-short-circuit-counter.js +2 -2
- package/lib/crawler/inject-scope-auth.d.ts +1 -1
- package/lib/crawler/inject-scope-auth.js +1 -1
- package/lib/crawler/normalize-content-type.d.ts +1 -1
- package/lib/crawler/normalize-content-type.js +1 -1
- package/lib/crawler/types.d.ts +3 -3
- package/lib/crawler-orchestrator.d.ts +9 -0
- package/lib/crawler-orchestrator.js +44 -28
- package/lib/crawler.d.ts +12 -0
- package/lib/crawler.js +21 -0
- package/lib/permanent-error-kinds.d.ts +1 -1
- package/lib/permanent-error-kinds.js +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/utils/compute-file-sha256.d.ts +5 -4
- package/lib/utils/compute-file-sha256.js +5 -4
- package/lib/utils/error/emit-error-with-retry.d.ts +1 -1
- package/lib/utils/error/emit-error-with-retry.js +1 -1
- package/package.json +10 -10
- 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-inventory-runs.d.ts +0 -29
- package/lib/archive/migrate-inventory-runs.js +0 -52
- 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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collects every `<img>` in a document — its `outerHTML` and its
|
|
3
|
+
* `dom_path` string — in document order.
|
|
4
|
+
*
|
|
5
|
+
* **Self-contained by contract.** This function is passed verbatim to
|
|
6
|
+
* puppeteer's `page.evaluate`, which serialises the function source and
|
|
7
|
+
* executes it inside the browser: it must not reference imports,
|
|
8
|
+
* module-scope bindings, or any closure state. That constraint is also
|
|
9
|
+
* what makes single-sourcing possible — the exact same function body
|
|
10
|
+
* runs in the browser during a live crawl AND in Node (against a jsdom
|
|
11
|
+
* document) in its spec, so the dom-path derivation cannot drift between
|
|
12
|
+
* the two runtimes. The spec additionally pins its output against
|
|
13
|
+
* {@link ../archive/populate-entity-tables/derive-dom-path.ts} (the
|
|
14
|
+
* Node-side derivation the migration script uses) element-for-element.
|
|
15
|
+
* @param doc - The document to walk. Defaults to the global `document`,
|
|
16
|
+
* which is how the in-browser `page.evaluate(collectImageDomPaths)`
|
|
17
|
+
* call resolves it; Node callers (specs) pass a jsdom document.
|
|
18
|
+
* @returns Candidates in document order.
|
|
19
|
+
* @example
|
|
20
|
+
* const candidates = await page.evaluate(collectImageDomPaths);
|
|
21
|
+
*/
|
|
22
|
+
export function collectImageDomPaths(doc) {
|
|
23
|
+
const target = doc ?? document;
|
|
24
|
+
/**
|
|
25
|
+
* Counts earlier same-tag siblings, returning the 1-based ordinal.
|
|
26
|
+
* @param element - The element whose ordinal is being computed.
|
|
27
|
+
* @param tag - The element's lower-cased tag name.
|
|
28
|
+
* @returns 1-based ordinal among same-tag siblings.
|
|
29
|
+
*/
|
|
30
|
+
function computeSiblingOrdinal(element, tag) {
|
|
31
|
+
let count = 1;
|
|
32
|
+
let sibling = element.previousElementSibling;
|
|
33
|
+
while (sibling !== null) {
|
|
34
|
+
if (sibling.tagName.toLowerCase() === tag) {
|
|
35
|
+
count += 1;
|
|
36
|
+
}
|
|
37
|
+
sibling = sibling.previousElementSibling;
|
|
38
|
+
}
|
|
39
|
+
return count;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Derives the slash-joined dom_path for one element.
|
|
43
|
+
* @param element - The element to derive the path for.
|
|
44
|
+
* @returns The dom_path string.
|
|
45
|
+
*/
|
|
46
|
+
function deriveDomPath(element) {
|
|
47
|
+
const segments = [];
|
|
48
|
+
let current = element;
|
|
49
|
+
while (current !== null) {
|
|
50
|
+
const tag = current.tagName.toLowerCase();
|
|
51
|
+
if (tag === 'html') {
|
|
52
|
+
segments.unshift('html');
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
segments.unshift(`${tag}[${computeSiblingOrdinal(current, tag)}]`);
|
|
56
|
+
current = current.parentElement;
|
|
57
|
+
}
|
|
58
|
+
return segments.join('/');
|
|
59
|
+
}
|
|
60
|
+
return Array.from(target.querySelectorAll('img'), (img) => ({
|
|
61
|
+
outerHTML: img.outerHTML,
|
|
62
|
+
path: deriveDomPath(img),
|
|
63
|
+
}));
|
|
64
|
+
}
|
package/lib/crawler/crawler.d.ts
CHANGED
|
@@ -81,6 +81,25 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
|
|
|
81
81
|
start(urls: ExURL[], opts?: {
|
|
82
82
|
recursive?: boolean;
|
|
83
83
|
}): void;
|
|
84
|
+
/**
|
|
85
|
+
* Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
|
|
86
|
+
*
|
|
87
|
+
* WHY per-URL browser: Each URL gets its own browser instance to ensure
|
|
88
|
+
* complete isolation (cookies, cache, service workers). The browser is always
|
|
89
|
+
* closed in the `finally` block, even on error.
|
|
90
|
+
*
|
|
91
|
+
* The cascade-guard contract for the puppeteer-fallback success / skipped
|
|
92
|
+
* branches can be exercised via `vi.spyOn(Crawler.prototype,
|
|
93
|
+
* '_launchBrowserAndScrape')` in unit tests. There is no production
|
|
94
|
+
* consumer outside this class.
|
|
95
|
+
* @internal
|
|
96
|
+
* @param url - Target URL to scrape
|
|
97
|
+
* @param update - Callback for progress messages
|
|
98
|
+
* @param isExternal - Whether the URL is external to the crawl scope
|
|
99
|
+
* @param metadataOnly - When true, only extract title metadata
|
|
100
|
+
* @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
|
|
101
|
+
* @returns The scrape result from beholder
|
|
102
|
+
*/
|
|
84
103
|
private _launchBrowserAndScrape;
|
|
85
104
|
/**
|
|
86
105
|
* The default maximum number of concurrent scraping processes.
|
package/lib/crawler/crawler.js
CHANGED
|
@@ -13,6 +13,7 @@ import { classifyErrorKind } from '../classify-error-kind.js';
|
|
|
13
13
|
import { crawlerLog } from '../debug.js';
|
|
14
14
|
import { buildJsRedirectEdge } from './build-js-redirect-edge.js';
|
|
15
15
|
import { buildRedirectEvent } from './build-redirect-event.js';
|
|
16
|
+
import { captureImageDomPaths } from './capture-image-dom-paths.js';
|
|
16
17
|
import { createChangePhaseHandler } from './create-change-phase-handler.js';
|
|
17
18
|
import { derivePageSource } from './derive-page-source.js';
|
|
18
19
|
import { detectPaginationPattern } from './detect-pagination-pattern.js';
|
|
@@ -469,31 +470,6 @@ class Crawler extends EventEmitter {
|
|
|
469
470
|
}
|
|
470
471
|
}
|
|
471
472
|
}
|
|
472
|
-
/**
|
|
473
|
-
* Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
|
|
474
|
-
*
|
|
475
|
-
* WHY per-URL browser: Each URL gets its own browser instance to ensure
|
|
476
|
-
* complete isolation (cookies, cache, service workers). The browser is always
|
|
477
|
-
* closed in the `finally` block, even on error.
|
|
478
|
-
* @param url - Target URL to scrape
|
|
479
|
-
* @param update - Callback for progress messages
|
|
480
|
-
* @param isExternal - Whether the URL is external to the crawl scope
|
|
481
|
-
* @param metadataOnly - When true, only extract title metadata
|
|
482
|
-
* @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
|
|
483
|
-
* @returns The scrape result from beholder
|
|
484
|
-
*/
|
|
485
|
-
/**
|
|
486
|
-
* @param url
|
|
487
|
-
* @param update
|
|
488
|
-
* @param isExternal
|
|
489
|
-
* @param metadataOnly
|
|
490
|
-
* @param headCheckResult
|
|
491
|
-
* @internal
|
|
492
|
-
* cascade-guard contract for the puppeteer-fallback success / skipped
|
|
493
|
-
* branches can be exercised via `vi.spyOn(Crawler.prototype,
|
|
494
|
-
* '_launchBrowserAndScrape')` in unit tests. There is no production
|
|
495
|
-
* consumer outside this class.
|
|
496
|
-
*/
|
|
497
473
|
/**
|
|
498
474
|
* Resolve the source label of the page being scraped so sub-resources
|
|
499
475
|
* captured during its render can inherit the correct lineage label
|
|
@@ -1185,7 +1161,7 @@ class Crawler extends EventEmitter {
|
|
|
1185
1161
|
// - the source is not committed via `setPage`/`updatePage` on this
|
|
1186
1162
|
// path (the redirect-edge handler in `#runDeal` only calls
|
|
1187
1163
|
// `linkList.done` + `emit('redirect', ...)` → `Archive.setRedirect`),
|
|
1188
|
-
// so `recordRedirect` →
|
|
1164
|
+
// so `recordRedirect` → `resolveContentItemId` creates a NULL-status
|
|
1189
1165
|
// placeholder row for the source if it did not already exist;
|
|
1190
1166
|
// - `#linkRedirectSources` then stamps `status = 301
|
|
1191
1167
|
// statusText='Moved Permanently'` because NULL satisfies its
|
|
@@ -1312,6 +1288,25 @@ class Crawler extends EventEmitter {
|
|
|
1312
1288
|
},
|
|
1313
1289
|
});
|
|
1314
1290
|
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Launches a fresh Puppeteer browser, runs the beholder scraper, and cleans up.
|
|
1293
|
+
*
|
|
1294
|
+
* WHY per-URL browser: Each URL gets its own browser instance to ensure
|
|
1295
|
+
* complete isolation (cookies, cache, service workers). The browser is always
|
|
1296
|
+
* closed in the `finally` block, even on error.
|
|
1297
|
+
*
|
|
1298
|
+
* The cascade-guard contract for the puppeteer-fallback success / skipped
|
|
1299
|
+
* branches can be exercised via `vi.spyOn(Crawler.prototype,
|
|
1300
|
+
* '_launchBrowserAndScrape')` in unit tests. There is no production
|
|
1301
|
+
* consumer outside this class.
|
|
1302
|
+
* @internal
|
|
1303
|
+
* @param url - Target URL to scrape
|
|
1304
|
+
* @param update - Callback for progress messages
|
|
1305
|
+
* @param isExternal - Whether the URL is external to the crawl scope
|
|
1306
|
+
* @param metadataOnly - When true, only extract title metadata
|
|
1307
|
+
* @param headCheckResult - Optional HEAD result to pass to the scraper, avoiding a redundant request
|
|
1308
|
+
* @returns The scrape result from beholder
|
|
1309
|
+
*/
|
|
1315
1310
|
// eslint-disable-next-line no-restricted-syntax -- intentional `private` (vs `#`) so tests can spyOn the prototype to drive the puppeteer-fallback cascade-guard branches without a full browser mock; see JSDoc above.
|
|
1316
1311
|
async _launchBrowserAndScrape(url, update, isExternal, metadataOnly, headCheckResult) {
|
|
1317
1312
|
update('Launching browser%dots%');
|
|
@@ -1405,6 +1400,25 @@ class Crawler extends EventEmitter {
|
|
|
1405
1400
|
retries: this.#options.retry,
|
|
1406
1401
|
headCheckResult,
|
|
1407
1402
|
});
|
|
1403
|
+
// Image dom-path capture runs here — after the scrape completed but
|
|
1404
|
+
// while `page` is still alive — because beholder's image metadata
|
|
1405
|
+
// carries each element's `outerHTML` with no positional
|
|
1406
|
+
// information. The captured candidates ride on the page data into
|
|
1407
|
+
// `image_items.dom_path_text_id` resolution at write time; a
|
|
1408
|
+
// capture failure (or a page with no images) falls back to the
|
|
1409
|
+
// synthetic `unknown/<n>` markers, so this stays best-effort.
|
|
1410
|
+
if (result.type === 'success' &&
|
|
1411
|
+
result.pageData &&
|
|
1412
|
+
result.pageData.imageList.length > 0) {
|
|
1413
|
+
const imageDomPaths = await captureImageDomPaths(page);
|
|
1414
|
+
if (imageDomPaths !== undefined) {
|
|
1415
|
+
const withDomPaths = {
|
|
1416
|
+
...result.pageData,
|
|
1417
|
+
imageDomPaths,
|
|
1418
|
+
};
|
|
1419
|
+
result.pageData = withDomPaths;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1408
1422
|
update('Closing browser%dots%');
|
|
1409
1423
|
// JS-redirect rescue capture: when `scrapeStart` catches a
|
|
1410
1424
|
// `#fetchData` throw internally (e.g. `Page.goto returned null`
|
|
@@ -3,15 +3,15 @@ import type { ErrorKind } from '../types.js';
|
|
|
3
3
|
* In-memory set of hostnames known to be unreachable due to DNS errors
|
|
4
4
|
* (e.g. `getaddrinfo ENOTFOUND`).
|
|
5
5
|
*
|
|
6
|
-
* Lives for one crawl session — cleared by
|
|
7
|
-
* the same four orchestrator sites as
|
|
6
|
+
* Lives for one crawl session — cleared by `clearDnsBurnedHostCache` at
|
|
7
|
+
* the same four orchestrator sites as `destinationCache`. Hosts are
|
|
8
8
|
* marked in two ways:
|
|
9
9
|
*
|
|
10
10
|
* - **Session learning**: the `onGiveUp` callback of `#sendHeadRequest`
|
|
11
11
|
* classifies the final retry error and stores `'dns'` when the matcher
|
|
12
12
|
* fires. The next URL on the same hostname short-circuits before retry.
|
|
13
13
|
* - **Session preload**: re-open paths (`append` / `inventory` / `retryFailed`
|
|
14
|
-
* / `resume`) call
|
|
14
|
+
* / `resume`) call `Archive.listDnsBurnedHostCandidates` and seed the
|
|
15
15
|
* map from `crawl_errors`, so previously-burned hosts cost zero retries on
|
|
16
16
|
* the next crawl.
|
|
17
17
|
*
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* In-memory set of hostnames known to be unreachable due to DNS errors
|
|
3
3
|
* (e.g. `getaddrinfo ENOTFOUND`).
|
|
4
4
|
*
|
|
5
|
-
* Lives for one crawl session — cleared by
|
|
6
|
-
* the same four orchestrator sites as
|
|
5
|
+
* Lives for one crawl session — cleared by `clearDnsBurnedHostCache` at
|
|
6
|
+
* the same four orchestrator sites as `destinationCache`. Hosts are
|
|
7
7
|
* marked in two ways:
|
|
8
8
|
*
|
|
9
9
|
* - **Session learning**: the `onGiveUp` callback of `#sendHeadRequest`
|
|
10
10
|
* classifies the final retry error and stores `'dns'` when the matcher
|
|
11
11
|
* fires. The next URL on the same hostname short-circuits before retry.
|
|
12
12
|
* - **Session preload**: re-open paths (`append` / `inventory` / `retryFailed`
|
|
13
|
-
* / `resume`) call
|
|
13
|
+
* / `resume`) call `Archive.listDnsBurnedHostCandidates` and seed the
|
|
14
14
|
* map from `crawl_errors`, so previously-burned hosts cost zero retries on
|
|
15
15
|
* the next crawl.
|
|
16
16
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session-scoped counter for how many URL fetches were short-circuited by the
|
|
3
|
-
*
|
|
3
|
+
* `dnsBurnedHostCache`. The orchestrator reads this at crawl shutdown
|
|
4
4
|
* to emit a `[preload] Short-circuited N URL(s)` summary line, then
|
|
5
|
-
*
|
|
5
|
+
* `clearDnsBurnedHostCache` zeroes it for the next session.
|
|
6
6
|
*
|
|
7
7
|
* Exposed as a mutable object (not a plain `let`) so that the counter remains
|
|
8
8
|
* a single shared reference across crawler / orchestrator imports — `let`
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session-scoped counter for how many URL fetches were short-circuited by the
|
|
3
|
-
*
|
|
3
|
+
* `dnsBurnedHostCache`. The orchestrator reads this at crawl shutdown
|
|
4
4
|
* to emit a `[preload] Short-circuited N URL(s)` summary line, then
|
|
5
|
-
*
|
|
5
|
+
* `clearDnsBurnedHostCache` zeroes it for the next session.
|
|
6
6
|
*
|
|
7
7
|
* Exposed as a mutable object (not a plain `let`) so that the counter remains
|
|
8
8
|
* a single shared reference across crawler / orchestrator imports — `let`
|
|
@@ -3,7 +3,7 @@ import type { ExURL } from '@d-zero/shared/parse-url';
|
|
|
3
3
|
* Copy `username` / `password` from a matched scope URL into the target URL.
|
|
4
4
|
*
|
|
5
5
|
* The matched scope is supplied by the caller (typically the result of a single
|
|
6
|
-
*
|
|
6
|
+
* `findScopeEntry` call). This avoids the previous implementation's
|
|
7
7
|
* redundant hostname lookup and re-search.
|
|
8
8
|
*
|
|
9
9
|
* Mutates the `url` parameter in place. Only non-empty credentials overwrite
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copy `username` / `password` from a matched scope URL into the target URL.
|
|
3
3
|
*
|
|
4
4
|
* The matched scope is supplied by the caller (typically the result of a single
|
|
5
|
-
*
|
|
5
|
+
* `findScopeEntry` call). This avoids the previous implementation's
|
|
6
6
|
* redundant hostname lookup and re-search.
|
|
7
7
|
*
|
|
8
8
|
* Mutates the `url` parameter in place. Only non-empty credentials overwrite
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* normalization, so `Text/HTML` or `text/html ` can otherwise reach the
|
|
8
8
|
* database. Storing the canonical (trimmed, lower-cased) form lets the exact
|
|
9
9
|
* SQL page-ness predicate (`WHERE contentType = 'text/html'`) agree with the
|
|
10
|
-
* code-level
|
|
10
|
+
* code-level `isHtmlContentType` check, which trims and lower-cases.
|
|
11
11
|
* @param contentType - The raw media type, or `null` when unknown.
|
|
12
12
|
* @returns The trimmed, lower-cased media type, or `null` when unknown/blank.
|
|
13
13
|
*/
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* normalization, so `Text/HTML` or `text/html ` can otherwise reach the
|
|
8
8
|
* database. Storing the canonical (trimmed, lower-cased) form lets the exact
|
|
9
9
|
* SQL page-ness predicate (`WHERE contentType = 'text/html'`) agree with the
|
|
10
|
-
* code-level
|
|
10
|
+
* code-level `isHtmlContentType` check, which trims and lower-cases.
|
|
11
11
|
* @param contentType - The raw media type, or `null` when unknown.
|
|
12
12
|
* @returns The trimmed, lower-cased media type, or `null` when unknown/blank.
|
|
13
13
|
*/
|
package/lib/crawler/types.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export type BrowserScrapeResult = ScrapeResult & {
|
|
|
82
82
|
* exactly that.
|
|
83
83
|
*
|
|
84
84
|
* Consumers should also confirm the URL is meaningful via
|
|
85
|
-
*
|
|
85
|
+
* `deriveJsRedirectTarget` — `about:blank`, identity values,
|
|
86
86
|
* case-only or trailing-slash variants are all filtered there, not
|
|
87
87
|
* here.
|
|
88
88
|
*/
|
|
@@ -188,7 +188,7 @@ export type ResourceLookup = (urls: readonly string[]) => Promise<ResourceLookup
|
|
|
188
188
|
* that has not been INSERTed yet) so the caller can fall through to its
|
|
189
189
|
* default behaviour.
|
|
190
190
|
*
|
|
191
|
-
* Used by
|
|
191
|
+
* Used by `Crawler` during sub-resource lineage propagation:
|
|
192
192
|
* `#scrapePage` consults this once per page to resolve the parent's
|
|
193
193
|
* lineage when the in-memory `inventoryMode` is unavailable (i.e. on
|
|
194
194
|
* `--resume` / `--retry-failed` sessions where inventory state lives only
|
|
@@ -250,7 +250,7 @@ export interface CrawlerEventTypes {
|
|
|
250
250
|
externalPage: {
|
|
251
251
|
/** The scraped page data for the external page. */
|
|
252
252
|
result: PageData;
|
|
253
|
-
/** Inventory provenance for new rows — see
|
|
253
|
+
/** Inventory provenance for new rows — see `CrawlerEventTypes.page.source`. */
|
|
254
254
|
source?: PageSource;
|
|
255
255
|
};
|
|
256
256
|
/**
|
|
@@ -8,6 +8,9 @@ import Archive from './archive/archive.js';
|
|
|
8
8
|
* Default list of external URL prefixes excluded from crawling.
|
|
9
9
|
* Includes social media sharing endpoints that are commonly linked
|
|
10
10
|
* but provide no useful crawl data.
|
|
11
|
+
* @example
|
|
12
|
+
* // Merged ahead of user-supplied excludeUrls when a crawl starts:
|
|
13
|
+
* const excludeUrls = [...DEFAULT_EXCLUDED_EXTERNAL_URLS, 'https://ads.example.com'];
|
|
11
14
|
*/
|
|
12
15
|
export declare const DEFAULT_EXCLUDED_EXTERNAL_URLS: string[];
|
|
13
16
|
/**
|
|
@@ -117,6 +120,12 @@ export declare class CrawlerOrchestrator extends EventEmitter<CrawlEvent> {
|
|
|
117
120
|
/**
|
|
118
121
|
* Write the archive to its configured file path.
|
|
119
122
|
*
|
|
123
|
+
* The crawler's write path inserts directly into the 0.13 entity
|
|
124
|
+
* tables (`content_items` / `page_meta` / `anchor_edges` / …) during
|
|
125
|
+
* `crawling` / `append` / `resume` / `retryFailed` / `inventory`, so by
|
|
126
|
+
* the time `write()` is called those tables are already populated.
|
|
127
|
+
* This method just tars.
|
|
128
|
+
*
|
|
120
129
|
* Emits `writeFileStart` before writing and `writeFileEnd` after
|
|
121
130
|
* the write completes successfully.
|
|
122
131
|
*/
|
|
@@ -5,6 +5,7 @@ import { sortUrl } from '@d-zero/shared/sort-url';
|
|
|
5
5
|
import { TypedAwaitEventEmitter as EventEmitter } from '@d-zero/shared/typed-await-event-emitter';
|
|
6
6
|
import pkg from '../package.json' with { type: 'json' };
|
|
7
7
|
import Archive from './archive/archive.js';
|
|
8
|
+
import { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
|
|
8
9
|
import { clearDestinationCache } from './crawler/clear-destination-cache.js';
|
|
9
10
|
import { clearDnsBurnedHostCache } from './crawler/clear-dns-burned-host-cache.js';
|
|
10
11
|
import Crawler from './crawler/crawler.js';
|
|
@@ -24,6 +25,9 @@ import { WriteQueue } from './write-queue.js';
|
|
|
24
25
|
* Default list of external URL prefixes excluded from crawling.
|
|
25
26
|
* Includes social media sharing endpoints that are commonly linked
|
|
26
27
|
* but provide no useful crawl data.
|
|
28
|
+
* @example
|
|
29
|
+
* // Merged ahead of user-supplied excludeUrls when a crawl starts:
|
|
30
|
+
* const excludeUrls = [...DEFAULT_EXCLUDED_EXTERNAL_URLS, 'https://ads.example.com'];
|
|
27
31
|
*/
|
|
28
32
|
export const DEFAULT_EXCLUDED_EXTERNAL_URLS = [
|
|
29
33
|
'https://social-plugins.line.me',
|
|
@@ -128,8 +132,8 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
128
132
|
// back to the DB DEFAULT `'crawled'` and lose their
|
|
129
133
|
// `'inventory-discovered'` provenance.
|
|
130
134
|
lookupPageSource: async (url) => this.#archive.getPageSourceByUrl(url),
|
|
131
|
-
// Inventory mode is opted into by `CrawlerOrchestrator.inventory
|
|
132
|
-
//
|
|
135
|
+
// Inventory mode is opted into by `CrawlerOrchestrator.inventory`;
|
|
136
|
+
// the default crawl path stays in normal mode so new
|
|
133
137
|
// rows continue to land in pages/resources with the DB DEFAULT
|
|
134
138
|
// `'crawled'` provenance label.
|
|
135
139
|
inventoryMode: options?.inventoryMode ?? null,
|
|
@@ -258,6 +262,12 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
258
262
|
/**
|
|
259
263
|
* Write the archive to its configured file path.
|
|
260
264
|
*
|
|
265
|
+
* The crawler's write path inserts directly into the 0.13 entity
|
|
266
|
+
* tables (`content_items` / `page_meta` / `anchor_edges` / …) during
|
|
267
|
+
* `crawling` / `append` / `resume` / `retryFailed` / `inventory`, so by
|
|
268
|
+
* the time `write()` is called those tables are already populated.
|
|
269
|
+
* This method just tars.
|
|
270
|
+
*
|
|
261
271
|
* Emits `writeFileStart` before writing and `writeFileEnd` after
|
|
262
272
|
* the write completes successfully.
|
|
263
273
|
*/
|
|
@@ -299,7 +309,14 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
299
309
|
// Each positional URL is both a starting point and a scope entry.
|
|
300
310
|
const rootHrefs = list.map((u) => u.withoutHash);
|
|
301
311
|
await archive.setConfig({
|
|
302
|
-
version
|
|
312
|
+
// `version` is the archive-format version (see
|
|
313
|
+
// `assertCompatibleVersion`), NOT the npm package version. Decoupled
|
|
314
|
+
// because format-breaking changes and code-release cadence are
|
|
315
|
+
// different concerns — a patch release must not silently bump the
|
|
316
|
+
// format version and reject older archives, and a dev build of an
|
|
317
|
+
// unreleased breaking change must be able to produce archives the
|
|
318
|
+
// same build can read back.
|
|
319
|
+
version: REQUIRED_FORMAT_VERSION,
|
|
303
320
|
name: fileName,
|
|
304
321
|
baseUrl: rootHrefs[0],
|
|
305
322
|
roots: rootHrefs,
|
|
@@ -520,13 +537,14 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
520
537
|
// anchor-referenced, `scraped=0` rows. Predicted-discard leaks
|
|
521
538
|
// and external anomalies are filtered out at the reader, so a
|
|
522
539
|
// non-empty pending here means the previous session genuinely
|
|
523
|
-
// stopped with interrupted in-scope work.
|
|
524
|
-
//
|
|
525
|
-
//
|
|
526
|
-
//
|
|
540
|
+
// stopped with interrupted in-scope work. A hard rejection is
|
|
541
|
+
// still not warranted (with a looser reader it would block
|
|
542
|
+
// legitimate inventory runs whenever leak rows polluted the
|
|
543
|
+
// count), so a warning is
|
|
527
544
|
// enough — the inventory pass continues and the crawled-wins
|
|
528
545
|
// source priority keeps stale labels stable even if some of
|
|
529
546
|
// the strict-pending rows happen to land on inventory seeds.
|
|
547
|
+
// eslint-disable-next-line no-console -- operator-facing warning, must be visible regardless of DEBUG filters
|
|
530
548
|
console.warn(`inventory: archive has ${pending.length} pending URLs from a previous crawl. Proceeding — crawled-wins priority keeps their labels stable. Consider \`--resume\` first if you want the prior work finalized.`);
|
|
531
549
|
}
|
|
532
550
|
// Parse + scope-classify the candidate URLs. sortUrl drops
|
|
@@ -556,7 +574,7 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
556
574
|
}
|
|
557
575
|
// Drop URLs that are already represented in the archive (either
|
|
558
576
|
// as pages or resources). Comparison key is `withoutHashAndAuth`
|
|
559
|
-
// to mirror what
|
|
577
|
+
// to mirror what `resolveContentItemId` / `insertResource` actually store.
|
|
560
578
|
// Two independent reads — Promise.all halves the wait on large
|
|
561
579
|
// archives where each `WHERE url IN (?)` chunk costs real I/O.
|
|
562
580
|
const candidateUrls = inScope.map((u) => u.withoutHashAndAuth);
|
|
@@ -656,8 +674,8 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
656
674
|
htmlSeeds.push(url);
|
|
657
675
|
}
|
|
658
676
|
// Bulk-record non-HTML novel URLs in `resources` as
|
|
659
|
-
// `source='inventory-seed'` placeholders.
|
|
660
|
-
// per-URL `await setResources(...)` loop
|
|
677
|
+
// `source='inventory-seed'` placeholders. A
|
|
678
|
+
// per-URL `await setResources(...)` loop would spend minutes
|
|
661
679
|
// inside the `.bak`-protected window on large inventory
|
|
662
680
|
// lists; the chunked bulk path collapses N round-trips
|
|
663
681
|
// to N/500.
|
|
@@ -665,7 +683,7 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
665
683
|
// Pre-insert HTML seeds as `scraped = 0`,
|
|
666
684
|
// `source = 'inventory-seed'` placeholders *before* the
|
|
667
685
|
// scrape phase, so a Ctrl+C between here and `setPage`
|
|
668
|
-
//
|
|
686
|
+
// cannot lose the URL. The strict-pending set picks
|
|
669
687
|
// these rows up on the next `--resume` via the
|
|
670
688
|
// `OR p.source != 'crawled'` clause.
|
|
671
689
|
await archive.insertInventorySeeds(htmlSeeds);
|
|
@@ -674,9 +692,9 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
674
692
|
// hiccup or transient lock on the INSERT aborts the ingestion
|
|
675
693
|
// and the `.bak` restore wipes the pre-inserted seeds too,
|
|
676
694
|
// so "either the whole run took or none of it did" holds at
|
|
677
|
-
// the ingestion boundary.
|
|
678
|
-
//
|
|
679
|
-
// and useful
|
|
695
|
+
// the ingestion boundary. Audit failures are deliberately
|
|
696
|
+
// NOT swallowed — inside the `.bak` window a restore is
|
|
697
|
+
// safe and useful (see
|
|
680
698
|
// {@link CrawlerOrchestrator.#writeInventoryRunRow}).
|
|
681
699
|
await CrawlerOrchestrator.#writeInventoryRunRow(archive, {
|
|
682
700
|
inventoryUrlsCount: inventoryUrls.length,
|
|
@@ -962,13 +980,12 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
962
980
|
* static helper because the audit-row shape (timestamp stamping + label
|
|
963
981
|
* auto-gen + the privacy-driven path elision documented below) is a
|
|
964
982
|
* cohesive concern that benefits from staying outside the long
|
|
965
|
-
* `inventory()` body even though
|
|
966
|
-
* ingestion-phase consolidation.
|
|
983
|
+
* `inventory()` body even though it has a single caller.
|
|
967
984
|
*
|
|
968
985
|
* `ran_at` is stamped now (ingestion-completion timestamp; the scrape
|
|
969
986
|
* phase that may follow is treated as separate). `list_label` is
|
|
970
|
-
* auto-generated from `ran_at` when the CLI did not pass one —
|
|
971
|
-
*
|
|
987
|
+
* auto-generated from `ran_at` when the CLI did not pass one — there is
|
|
988
|
+
* no `--label` flag, so this is always the auto form.
|
|
972
989
|
* `source_file_sha256` arrives pre-computed via
|
|
973
990
|
* `aggregates.sourceFileSha256` (the CLI's `inventoryCrawl` ran
|
|
974
991
|
* `computeFileSha256` against the input txt before the orchestrator
|
|
@@ -976,17 +993,17 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
976
993
|
* the absolute path — see {@link InventoryRunAggregates} for the
|
|
977
994
|
* privacy rationale.
|
|
978
995
|
*
|
|
979
|
-
* **Audit-write failures abort the ingestion phase.**
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
996
|
+
* **Audit-write failures abort the ingestion phase.** Swallowing them
|
|
997
|
+
* would only be justified if the audit were the last write after the
|
|
998
|
+
* scrape (re-throwing there would wipe a completed crawl); inside the
|
|
999
|
+
* `.bak`-protected ingestion phase the
|
|
983
1000
|
* trade-off flips. A failed audit row is restorable: the outer catch
|
|
984
1001
|
* copies `.bak` back over the archive and the operator reruns the
|
|
985
1002
|
* (short) ingestion from scratch. That keeps `inventory_runs` honest
|
|
986
1003
|
* (no "ran but unrecorded" rows) at the cost of one rerun.
|
|
987
1004
|
*
|
|
988
|
-
* Forward-compat:
|
|
989
|
-
*
|
|
1005
|
+
* Forward-compat: if an explicit `--label` flag is ever added, thread
|
|
1006
|
+
* `labelOverride` through {@link inventory} into the `aggregates`
|
|
990
1007
|
* shape so the auto-name can be overridden.
|
|
991
1008
|
* @param archive - The opened archive to write the audit row into.
|
|
992
1009
|
* @param aggregates - The counts captured during the inventory pass; see {@link InventoryRunAggregates}.
|
|
@@ -1005,10 +1022,9 @@ export class CrawlerOrchestrator extends EventEmitter {
|
|
|
1005
1022
|
}
|
|
1006
1023
|
/**
|
|
1007
1024
|
* Tears down session-scoped crawler caches and prints a short-circuit
|
|
1008
|
-
* summary if any URL fetches were skipped. Invoked at
|
|
1009
|
-
* crawl-session
|
|
1010
|
-
* `retryFailed` / `resume`)
|
|
1011
|
-
* call already lived.
|
|
1025
|
+
* summary if any URL fetches were skipped. Invoked at every
|
|
1026
|
+
* crawl-session boundary (`crawling` / `append` / `inventory` /
|
|
1027
|
+
* `retryFailed` / `resume`).
|
|
1012
1028
|
*/
|
|
1013
1029
|
static #finalizeCrawlSession() {
|
|
1014
1030
|
const skipped = dnsBurnedHostShortCircuitCounter.count;
|
package/lib/crawler.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { default as ArchiveResource } from './archive/resource.js';
|
|
|
16
16
|
export * from './archive/types.js';
|
|
17
17
|
export { default as Archive } from './archive/archive.js';
|
|
18
18
|
export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
|
|
19
|
+
export { acquireArchiveLock, ArchiveLockError } from './archive/archive-lock.js';
|
|
19
20
|
export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
20
21
|
export type { ArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
21
22
|
export type { FlatPageMetaColumns, JsonLdRow, JsonLdRowForInsert, TagRow, TagRowForInsert, JsonLdSummary, TagsSummary, TagInventoryEntry, PageDenormalizedColumns, } from './archive/meta/types.js';
|
|
@@ -26,3 +27,14 @@ export * from './types.js';
|
|
|
26
27
|
export * from './crawler/types.js';
|
|
27
28
|
export { classifyErrorKind } from './classify-error-kind.js';
|
|
28
29
|
export { computeFileSha256 } from './utils/compute-file-sha256.js';
|
|
30
|
+
export { populateEntityTables } from './archive/populate-entity-tables/populate-entities.js';
|
|
31
|
+
export type { PageDomPathResolver } from './archive/populate-entity-tables/populate-image-items.js';
|
|
32
|
+
export { populateRefTables } from './archive/populate-ref-tables/populate-refs.js';
|
|
33
|
+
export { populateContentTypeRefs } from './archive/populate-ref-tables/populate-content-type-refs.js';
|
|
34
|
+
export { populateUrlRefs } from './archive/populate-ref-tables/populate-url-refs.js';
|
|
35
|
+
export { populateTextRefs } from './archive/populate-ref-tables/populate-text-refs.js';
|
|
36
|
+
export { populateJsonRefs } from './archive/populate-ref-tables/populate-json-refs.js';
|
|
37
|
+
export { populateBlobRefs } from './archive/populate-ref-tables/populate-blob-refs.js';
|
|
38
|
+
export { populateHeaderTables } from './archive/populate-ref-tables/populate-header-tables.js';
|
|
39
|
+
export { loadResponseHeadersBySetIds } from './archive/db-ops/_shared/load-response-headers-by-set-ids.js';
|
|
40
|
+
export { decodeJsonRef } from './archive/db-ops/_shared/decode-json-ref.js';
|
package/lib/crawler.js
CHANGED
|
@@ -17,6 +17,7 @@ export { default as ArchiveResource } from './archive/resource.js';
|
|
|
17
17
|
export * from './archive/types.js';
|
|
18
18
|
export { default as Archive } from './archive/archive.js';
|
|
19
19
|
export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
|
|
20
|
+
export { acquireArchiveLock, ArchiveLockError } from './archive/archive-lock.js';
|
|
20
21
|
export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
21
22
|
export { IncompatibleArchiveError } from './archive/meta/types.js';
|
|
22
23
|
export { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
|
|
@@ -26,3 +27,23 @@ export * from './types.js';
|
|
|
26
27
|
export * from './crawler/types.js';
|
|
27
28
|
export { classifyErrorKind } from './classify-error-kind.js';
|
|
28
29
|
export { computeFileSha256 } from './utils/compute-file-sha256.js';
|
|
30
|
+
// 0.13 ref-table population (issue #191, epic #103). Exposed as the
|
|
31
|
+
// public seam that the migration script (`scripts/migrate-to-0.13.mjs`)
|
|
32
|
+
// drives against an already-connected archive.
|
|
33
|
+
// The individual sub-steps are also exported so the migration script can
|
|
34
|
+
// resume mid-way if the caller decides to split the transaction.
|
|
35
|
+
export { populateEntityTables } from './archive/populate-entity-tables/populate-entities.js';
|
|
36
|
+
export { populateRefTables } from './archive/populate-ref-tables/populate-refs.js';
|
|
37
|
+
export { populateContentTypeRefs } from './archive/populate-ref-tables/populate-content-type-refs.js';
|
|
38
|
+
export { populateUrlRefs } from './archive/populate-ref-tables/populate-url-refs.js';
|
|
39
|
+
export { populateTextRefs } from './archive/populate-ref-tables/populate-text-refs.js';
|
|
40
|
+
export { populateJsonRefs } from './archive/populate-ref-tables/populate-json-refs.js';
|
|
41
|
+
export { populateBlobRefs } from './archive/populate-ref-tables/populate-blob-refs.js';
|
|
42
|
+
export { populateHeaderTables } from './archive/populate-ref-tables/populate-header-tables.js';
|
|
43
|
+
// 0.13 read-side reconstruction primitives. Exported so downstream
|
|
44
|
+
// readers (`@nitpicker/query`'s page-detail view) reconstruct
|
|
45
|
+
// `responseHeaders` / json_refs payloads with the exact same merge and
|
|
46
|
+
// decode semantics as the crawler's own read paths — one implementation,
|
|
47
|
+
// no cross-package drift.
|
|
48
|
+
export { loadResponseHeadersBySetIds } from './archive/db-ops/_shared/load-response-headers-by-set-ids.js';
|
|
49
|
+
export { decodeJsonRef } from './archive/db-ops/_shared/decode-json-ref.js';
|
|
@@ -4,7 +4,7 @@ import type { ErrorKind } from './types.js';
|
|
|
4
4
|
* (without changing the network, the certificate, the destination host, or the
|
|
5
5
|
* browser's block-list state) will almost certainly produce the same failure.
|
|
6
6
|
*
|
|
7
|
-
* Used by
|
|
7
|
+
* Used by `resetFailedPages` to exclude pages whose latest recorded error
|
|
8
8
|
* falls in this set, so `--retry-failed` actually converges: without the
|
|
9
9
|
* exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
|
|
10
10
|
* `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* (without changing the network, the certificate, the destination host, or the
|
|
4
4
|
* browser's block-list state) will almost certainly produce the same failure.
|
|
5
5
|
*
|
|
6
|
-
* Used by
|
|
6
|
+
* Used by `resetFailedPages` to exclude pages whose latest recorded error
|
|
7
7
|
* falls in this set, so `--retry-failed` actually converges: without the
|
|
8
8
|
* exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
|
|
9
9
|
* `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
|
package/lib/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { CrawlerError, PageData } from './utils/types/types.js';
|
|
|
3
3
|
* Aggregate counts captured during a `--inventory` invocation, forwarded to
|
|
4
4
|
* `#writeInventoryRunRow` so the audit log row is consistent between the
|
|
5
5
|
* HTML-seed branch and the non-HTML-only branch of
|
|
6
|
-
*
|
|
6
|
+
* `CrawlerOrchestrator.inventory`.
|
|
7
7
|
*
|
|
8
8
|
* Spelled out here (not inlined at the call site) so a new field added to
|
|
9
9
|
* the audit row has a single edit point and so each field's semantics are
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Compute the SHA-256 digest of a file's bytes, streaming so memory stays
|
|
3
3
|
* O(1) regardless of file size.
|
|
4
4
|
*
|
|
5
|
-
* Used by
|
|
6
|
-
* URL list `.txt` and store the digest on the `inventory_runs` row.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Used by `CrawlerOrchestrator.inventory` to fingerprint the source
|
|
6
|
+
* URL list `.txt` and store the digest on the `inventory_runs` row. The
|
|
7
|
+
* digest is the content-identity key for "was this exact list applied
|
|
8
|
+
* before" — recorded for operator audit; nothing dedupes on it at write
|
|
9
|
+
* time.
|
|
9
10
|
*
|
|
10
11
|
* Returns `null` instead of throwing when the file cannot be read (e.g.
|
|
11
12
|
* vanished mid-run, permissions issue) so the inventory run's audit row
|