@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,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves a flat list of all resource URLs from the `resource_items`
|
|
3
|
+
* table. URL text is normalised into `url_refs`, so the read joins the
|
|
4
|
+
* two tables and returns the resolved strings.
|
|
5
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
6
|
+
* @returns An array of resource URL strings.
|
|
7
|
+
*/
|
|
8
|
+
export async function getResourceUrlList(knex) {
|
|
9
|
+
const res = await knex('resource_items')
|
|
10
|
+
.join('url_refs', 'url_refs.id', 'resource_items.url_id')
|
|
11
|
+
.select('url_refs.url as url');
|
|
12
|
+
return res.map((r) => r.url);
|
|
13
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DB_Resource } from '../../types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves all sub-resources.
|
|
5
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
6
|
+
* @returns An array of reconstructed {@link DB_Resource} rows.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getResources(knex: Knex): Promise<DB_Resource[]>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { buildResourceQuery } from './build-resource-query.js';
|
|
2
|
+
import { reconstructResourceRows } from './reconstruct-resource-rows.js';
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves all sub-resources.
|
|
5
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
6
|
+
* @returns An array of reconstructed {@link DB_Resource} rows.
|
|
7
|
+
*/
|
|
8
|
+
export async function getResources(knex) {
|
|
9
|
+
const rows = await buildResourceQuery(knex);
|
|
10
|
+
return reconstructResourceRows(knex, rows);
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { WriteRefCaches } from '../_shared/types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Pre-insert inventory non-HTML URLs into `resource_items` as placeholder
|
|
5
|
+
* rows with `source = 'inventory-seed'` and all metadata columns NULL —
|
|
6
|
+
* the non-HTML counterpart of `insertInventorySeeds`. Used by
|
|
7
|
+
* `CrawlerOrchestrator.inventory` so the ingestion phase commits all of
|
|
8
|
+
* its non-HTML URLs in one chunked round-trip per 500 instead of N
|
|
9
|
+
* sequential `insertResource` awaits — a per-URL loop would spend
|
|
10
|
+
* minutes inside the `.bak`-protected window on a 50k-URL inventory
|
|
11
|
+
* list, where the bulk path finishes in seconds.
|
|
12
|
+
*
|
|
13
|
+
* Idempotent: both the `url_refs` and `resource_items` inserts are
|
|
14
|
+
* `ON CONFLICT ... IGNORE`, leaving existing rows untouched (the
|
|
15
|
+
* orchestrator's `getExistingResourceUrls` filter is what keeps a
|
|
16
|
+
* crawled-lineage `resource_items` row from being downgraded to the
|
|
17
|
+
* inventory label here).
|
|
18
|
+
*
|
|
19
|
+
* Chunked at 500 to stay well under SQLite's `SQLITE_MAX_VARIABLE_NUMBER`.
|
|
20
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
21
|
+
* @param caches
|
|
22
|
+
* @param urls - URL strings (already in `withoutHashAndAuth` form).
|
|
23
|
+
*/
|
|
24
|
+
export declare function insertInventoryResources(knex: Knex, caches: WriteRefCaches, urls: readonly string[]): Promise<void>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { eachSplitted } from '../../../utils/array/each-splitted.js';
|
|
2
|
+
import { resolveUrlRefs } from '../../populate-entity-tables/resolve-url-refs.js';
|
|
3
|
+
import { decomposeUrl } from '../../populate-ref-tables/decompose-url.js';
|
|
4
|
+
/**
|
|
5
|
+
* Pre-insert inventory non-HTML URLs into `resource_items` as placeholder
|
|
6
|
+
* rows with `source = 'inventory-seed'` and all metadata columns NULL —
|
|
7
|
+
* the non-HTML counterpart of `insertInventorySeeds`. Used by
|
|
8
|
+
* `CrawlerOrchestrator.inventory` so the ingestion phase commits all of
|
|
9
|
+
* its non-HTML URLs in one chunked round-trip per 500 instead of N
|
|
10
|
+
* sequential `insertResource` awaits — a per-URL loop would spend
|
|
11
|
+
* minutes inside the `.bak`-protected window on a 50k-URL inventory
|
|
12
|
+
* list, where the bulk path finishes in seconds.
|
|
13
|
+
*
|
|
14
|
+
* Idempotent: both the `url_refs` and `resource_items` inserts are
|
|
15
|
+
* `ON CONFLICT ... IGNORE`, leaving existing rows untouched (the
|
|
16
|
+
* orchestrator's `getExistingResourceUrls` filter is what keeps a
|
|
17
|
+
* crawled-lineage `resource_items` row from being downgraded to the
|
|
18
|
+
* inventory label here).
|
|
19
|
+
*
|
|
20
|
+
* Chunked at 500 to stay well under SQLite's `SQLITE_MAX_VARIABLE_NUMBER`.
|
|
21
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
22
|
+
* @param caches
|
|
23
|
+
* @param urls - URL strings (already in `withoutHashAndAuth` form).
|
|
24
|
+
*/
|
|
25
|
+
export async function insertInventoryResources(knex, caches, urls) {
|
|
26
|
+
if (urls.length === 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
await eachSplitted([...urls], 500, async (chunk) => {
|
|
30
|
+
await knex('url_refs')
|
|
31
|
+
.insert(chunk.map((url) => ({ url, ...decomposeUrl(url) })))
|
|
32
|
+
.onConflict('url')
|
|
33
|
+
.ignore();
|
|
34
|
+
const urlIds = await resolveUrlRefs(knex, chunk);
|
|
35
|
+
const rows = chunk.map((url) => {
|
|
36
|
+
const urlId = urlIds.get(url);
|
|
37
|
+
if (urlId === undefined) {
|
|
38
|
+
throw new Error(`insertInventoryResources: url_refs.id not resolved for ${url}`);
|
|
39
|
+
}
|
|
40
|
+
caches.urlIds.set(url, urlId);
|
|
41
|
+
return {
|
|
42
|
+
url_id: urlId,
|
|
43
|
+
is_external: 0,
|
|
44
|
+
status: null,
|
|
45
|
+
status_text: null,
|
|
46
|
+
content_type_id: null,
|
|
47
|
+
content_length: null,
|
|
48
|
+
header_set_id: null,
|
|
49
|
+
compress: 0,
|
|
50
|
+
cdn: 0,
|
|
51
|
+
source: 'inventory-seed',
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
await knex('resource_items').insert(rows).onConflict('url_id').ignore();
|
|
55
|
+
const inserted = (await knex
|
|
56
|
+
.select('ri.id', 'ur.url')
|
|
57
|
+
.from('resource_items as ri')
|
|
58
|
+
.join('url_refs as ur', 'ur.id', 'ri.url_id')
|
|
59
|
+
.whereIn('ur.url', chunk));
|
|
60
|
+
for (const row of inserted) {
|
|
61
|
+
caches.resourceIds.set(row.url, row.id);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WriteRefCaches } from '../_shared/types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Inserts a referrer relationship between a resource and a page into the
|
|
5
|
+
* `resource_ref_edges` table. Silently skips if the resource is not found.
|
|
6
|
+
*
|
|
7
|
+
* A repeat observation of the same `(resource, page)` pair is ignored
|
|
8
|
+
* (`ON CONFLICT ... IGNORE`), leaving `count` at its DEFAULT `1` — one
|
|
9
|
+
* row per pair, matching the legacy uniqueness contract.
|
|
10
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
11
|
+
* @param caches - The connection's write-side id caches.
|
|
12
|
+
* @param src - The URL of the resource.
|
|
13
|
+
* @param pageUrl - The URL of the page that references the resource.
|
|
14
|
+
*/
|
|
15
|
+
export declare function insertResourceReferrers(knex: Knex, caches: WriteRefCaches, src: string, pageUrl: string): Promise<void>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { resolveContentItemId } from '../_shared/resolve-content-item-id.js';
|
|
2
|
+
/**
|
|
3
|
+
* Inserts a referrer relationship between a resource and a page into the
|
|
4
|
+
* `resource_ref_edges` table. Silently skips if the resource is not found.
|
|
5
|
+
*
|
|
6
|
+
* A repeat observation of the same `(resource, page)` pair is ignored
|
|
7
|
+
* (`ON CONFLICT ... IGNORE`), leaving `count` at its DEFAULT `1` — one
|
|
8
|
+
* row per pair, matching the legacy uniqueness contract.
|
|
9
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
10
|
+
* @param caches - The connection's write-side id caches.
|
|
11
|
+
* @param src - The URL of the resource.
|
|
12
|
+
* @param pageUrl - The URL of the page that references the resource.
|
|
13
|
+
*/
|
|
14
|
+
export async function insertResourceReferrers(knex, caches, src, pageUrl) {
|
|
15
|
+
const resourceId = await findResourceIdByUrl(knex, caches, src);
|
|
16
|
+
if (resourceId === undefined) {
|
|
17
|
+
// Ignore when the resource is not found
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const pageId = await resolveContentItemId(knex, caches, pageUrl);
|
|
21
|
+
await knex('resource_ref_edges')
|
|
22
|
+
.insert({
|
|
23
|
+
resource_id: resourceId,
|
|
24
|
+
page_id: pageId,
|
|
25
|
+
})
|
|
26
|
+
.onConflict(['resource_id', 'page_id'])
|
|
27
|
+
.ignore();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Cache-first lookup of `resource_items.id` by the resource URL. The
|
|
31
|
+
* cache only ever gains entries for URLs that exist in the table
|
|
32
|
+
* (resource identities are never deleted during a crawl), so a hit is
|
|
33
|
+
* always valid; a miss falls through to a `url_refs` join.
|
|
34
|
+
* @param knex - Knex query builder.
|
|
35
|
+
* @param caches - The connection's write-side id caches.
|
|
36
|
+
* @param url - The resource URL, verbatim as stored.
|
|
37
|
+
* @returns The resource id, or `undefined` when the URL is unknown.
|
|
38
|
+
*/
|
|
39
|
+
async function findResourceIdByUrl(knex, caches, url) {
|
|
40
|
+
const cached = caches.resourceIds.get(url);
|
|
41
|
+
if (cached !== undefined) {
|
|
42
|
+
return cached;
|
|
43
|
+
}
|
|
44
|
+
const [row] = (await knex
|
|
45
|
+
.select('ri.id')
|
|
46
|
+
.from('resource_items as ri')
|
|
47
|
+
.join('url_refs as ur', 'ur.id', 'ri.url_id')
|
|
48
|
+
.where('ur.url', url));
|
|
49
|
+
if (row === undefined) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
caches.resourceIds.set(url, row.id);
|
|
53
|
+
return row.id;
|
|
54
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Resource } from '../../../utils/types/types.js';
|
|
2
|
+
import type { PageSource } from '../../types.js';
|
|
3
|
+
import type { WriteRefCaches } from '../_shared/types.js';
|
|
4
|
+
import type { Knex } from 'knex';
|
|
5
|
+
/**
|
|
6
|
+
* Inserts a sub-resource into the `resource_items` table, interning its
|
|
7
|
+
* URL / content type / response headers into the ref tables first. A
|
|
8
|
+
* resource's identity URL routes through {@link resolveUrlOrBlob} like an
|
|
9
|
+
* image `src` — a large inline `data:` URI (e.g. a CSS
|
|
10
|
+
* `background-image` sub-resource) lands in `blob_refs` instead of
|
|
11
|
+
* `url_refs`.
|
|
12
|
+
*
|
|
13
|
+
* A conflict on the identity column (`url_id` or `url_blob_id`) is an
|
|
14
|
+
* **upgrade-only merge**, not first-write-wins: the existing row's
|
|
15
|
+
* response fields (`status` / `status_text` / `content_type_id` /
|
|
16
|
+
* `content_length` / `header_set_id` / `compress` / `cdn`) are replaced
|
|
17
|
+
* only when the existing row currently has `status IS NULL` (beholder's
|
|
18
|
+
* signal for "the request never got a response" — see the `Resource`
|
|
19
|
+
* type) AND the new observation has a non-null `status`. A resource that
|
|
20
|
+
* failed on first sight and later succeeds (the exact case
|
|
21
|
+
* `--retry-failed` re-renders a page for) is therefore healed instead of
|
|
22
|
+
* staying frozen at its failure; a resource that already has a real
|
|
23
|
+
* response never gets overwritten by a later transient failure, and two
|
|
24
|
+
* failures in a row are a no-op — neither carries new information.
|
|
25
|
+
*
|
|
26
|
+
* The `source` provenance label is written ONLY on insert; a conflict
|
|
27
|
+
* (upgrade or no-op alike) leaves an existing row's source untouched
|
|
28
|
+
* (this is what makes a second `crawl --inventory` non-destructive).
|
|
29
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
30
|
+
* @param caches - The connection's write-side id caches.
|
|
31
|
+
* @param resource - The resource data to insert.
|
|
32
|
+
* @param source - Provenance label for new rows. `undefined` leaves the DB DEFAULT (`'crawled'`).
|
|
33
|
+
*/
|
|
34
|
+
export declare function insertResource(knex: Knex, caches: WriteRefCaches, resource: Resource, source?: PageSource): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { normalizeContentType } from '../../../crawler/normalize-content-type.js';
|
|
2
|
+
import { resolveUrlOrBlob } from '../_shared/resolve-url-or-blob.js';
|
|
3
|
+
import { upsertContentTypeRef } from '../_shared/upsert-content-type-ref.js';
|
|
4
|
+
import { upsertResponseHeaders } from '../_shared/upsert-response-headers.js';
|
|
5
|
+
/**
|
|
6
|
+
* Inserts a sub-resource into the `resource_items` table, interning its
|
|
7
|
+
* URL / content type / response headers into the ref tables first. A
|
|
8
|
+
* resource's identity URL routes through {@link resolveUrlOrBlob} like an
|
|
9
|
+
* image `src` — a large inline `data:` URI (e.g. a CSS
|
|
10
|
+
* `background-image` sub-resource) lands in `blob_refs` instead of
|
|
11
|
+
* `url_refs`.
|
|
12
|
+
*
|
|
13
|
+
* A conflict on the identity column (`url_id` or `url_blob_id`) is an
|
|
14
|
+
* **upgrade-only merge**, not first-write-wins: the existing row's
|
|
15
|
+
* response fields (`status` / `status_text` / `content_type_id` /
|
|
16
|
+
* `content_length` / `header_set_id` / `compress` / `cdn`) are replaced
|
|
17
|
+
* only when the existing row currently has `status IS NULL` (beholder's
|
|
18
|
+
* signal for "the request never got a response" — see the `Resource`
|
|
19
|
+
* type) AND the new observation has a non-null `status`. A resource that
|
|
20
|
+
* failed on first sight and later succeeds (the exact case
|
|
21
|
+
* `--retry-failed` re-renders a page for) is therefore healed instead of
|
|
22
|
+
* staying frozen at its failure; a resource that already has a real
|
|
23
|
+
* response never gets overwritten by a later transient failure, and two
|
|
24
|
+
* failures in a row are a no-op — neither carries new information.
|
|
25
|
+
*
|
|
26
|
+
* The `source` provenance label is written ONLY on insert; a conflict
|
|
27
|
+
* (upgrade or no-op alike) leaves an existing row's source untouched
|
|
28
|
+
* (this is what makes a second `crawl --inventory` non-destructive).
|
|
29
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
30
|
+
* @param caches - The connection's write-side id caches.
|
|
31
|
+
* @param resource - The resource data to insert.
|
|
32
|
+
* @param source - Provenance label for new rows. `undefined` leaves the DB DEFAULT (`'crawled'`).
|
|
33
|
+
*/
|
|
34
|
+
export async function insertResource(knex, caches, resource, source) {
|
|
35
|
+
const slot = await resolveUrlOrBlob(knex, caches, resource.url.href);
|
|
36
|
+
// Canonicalize like the page path (see `insertPage`) so resource
|
|
37
|
+
// content-type filters / dedupe keys are case- and whitespace-stable.
|
|
38
|
+
const contentType = normalizeContentType(resource.contentType);
|
|
39
|
+
const contentTypeId = contentType == null || contentType === ''
|
|
40
|
+
? null
|
|
41
|
+
: await upsertContentTypeRef(knex, caches, contentType);
|
|
42
|
+
const headerSetId = await upsertResponseHeaders(knex, caches, resource.headers);
|
|
43
|
+
const identityColumn = slot.blob === null ? 'url_id' : 'url_blob_id';
|
|
44
|
+
const identityValue = slot.blob === null ? slot.url : slot.blob;
|
|
45
|
+
const responseFields = {
|
|
46
|
+
is_external: resource.isExternal ? 1 : 0,
|
|
47
|
+
status: resource.status,
|
|
48
|
+
status_text: resource.statusText,
|
|
49
|
+
content_type_id: contentTypeId,
|
|
50
|
+
content_length: resource.contentLength,
|
|
51
|
+
header_set_id: headerSetId,
|
|
52
|
+
compress: resource.compress || 0,
|
|
53
|
+
cdn: resource.cdn || 0,
|
|
54
|
+
};
|
|
55
|
+
const existing = await knex('resource_items')
|
|
56
|
+
.select('id', 'status')
|
|
57
|
+
.where(identityColumn, identityValue)
|
|
58
|
+
.first();
|
|
59
|
+
if (existing === undefined) {
|
|
60
|
+
await knex('resource_items').insert({
|
|
61
|
+
url_id: slot.url,
|
|
62
|
+
url_blob_id: slot.blob,
|
|
63
|
+
...responseFields,
|
|
64
|
+
...(source === undefined ? {} : { source }),
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (existing.status === null && resource.status !== null) {
|
|
69
|
+
await knex('resource_items')
|
|
70
|
+
.where('id', existing.id)
|
|
71
|
+
.update(responseFields);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DB_Resource } from '../../types.js';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
/**
|
|
4
|
+
* Raw row shape produced by {@link ../resources/build-resource-query.js}
|
|
5
|
+
* before `responseHeaders` reconstruction.
|
|
6
|
+
*/
|
|
7
|
+
interface RawResourceRow extends Omit<DB_Resource, 'responseHeaders'> {
|
|
8
|
+
/** `resource_items.header_set_id`, or null when no headers were recorded. */
|
|
9
|
+
headerSetId: number | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Reconstructs `responseHeaders` (JSON string) for a batch of raw resource
|
|
13
|
+
* rows. Headers load through
|
|
14
|
+
* {@link ../_shared/load-response-headers-by-set-ids.js} (chunked batch
|
|
15
|
+
* lookup, never N+1) — the same reconstruction the page read path uses,
|
|
16
|
+
* so pages and resources always agree on how a given `header_set_id`
|
|
17
|
+
* reads back.
|
|
18
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
19
|
+
* @param rows - Raw rows from {@link ../resources/build-resource-query.js}.
|
|
20
|
+
* @returns Fully reconstructed `DB_Resource` rows, in the same order as `rows`.
|
|
21
|
+
* @example
|
|
22
|
+
* const raw = await buildResourceQuery(knex).whereIn('ur.url', urls);
|
|
23
|
+
* const resources = await reconstructResourceRows(knex, raw);
|
|
24
|
+
*/
|
|
25
|
+
export declare function reconstructResourceRows(knex: Knex, rows: readonly RawResourceRow[]): Promise<DB_Resource[]>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { loadResponseHeadersBySetIds } from '../_shared/load-response-headers-by-set-ids.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reconstructs `responseHeaders` (JSON string) for a batch of raw resource
|
|
4
|
+
* rows. Headers load through
|
|
5
|
+
* {@link ../_shared/load-response-headers-by-set-ids.js} (chunked batch
|
|
6
|
+
* lookup, never N+1) — the same reconstruction the page read path uses,
|
|
7
|
+
* so pages and resources always agree on how a given `header_set_id`
|
|
8
|
+
* reads back.
|
|
9
|
+
* @param knex - Knex query builder connected to the archive DB.
|
|
10
|
+
* @param rows - Raw rows from {@link ../resources/build-resource-query.js}.
|
|
11
|
+
* @returns Fully reconstructed `DB_Resource` rows, in the same order as `rows`.
|
|
12
|
+
* @example
|
|
13
|
+
* const raw = await buildResourceQuery(knex).whereIn('ur.url', urls);
|
|
14
|
+
* const resources = await reconstructResourceRows(knex, raw);
|
|
15
|
+
*/
|
|
16
|
+
export async function reconstructResourceRows(knex, rows) {
|
|
17
|
+
const headerSetIds = [
|
|
18
|
+
...new Set(rows.map((r) => r.headerSetId).filter((id) => id != null)),
|
|
19
|
+
];
|
|
20
|
+
const headersBySetId = await loadResponseHeadersBySetIds(knex, headerSetIds);
|
|
21
|
+
return rows.map((row) => {
|
|
22
|
+
const { headerSetId, ...rest } = row;
|
|
23
|
+
return {
|
|
24
|
+
...rest,
|
|
25
|
+
responseHeaders: headerSetId == null
|
|
26
|
+
? null
|
|
27
|
+
: JSON.stringify(headersBySetId.get(headerSetId) ?? {}),
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decodes a stored HTML body BLOB according to its codec marker. The codec
|
|
3
|
+
* column on `page_html_blobs` records which encoding was applied at write
|
|
4
|
+
* time so individual rows can be migrated to a different compression without
|
|
5
|
+
* a table-wide rewrite.
|
|
6
|
+
*
|
|
7
|
+
* Shared by {@link ./database.ts#Database.getHtmlOfPageById} (writer read
|
|
8
|
+
* path) and {@link ./populate-entity-tables/populate-image-items.ts} (0.13
|
|
9
|
+
* migration, which reads HTML *inside* its writer transaction and therefore
|
|
10
|
+
* cannot go through `Database.getHtmlOfPageById` — that method uses the
|
|
11
|
+
* non-transactional Knex instance, and re-entering the pool from within an
|
|
12
|
+
* outer writer trx serialises on libsql's single writer connection).
|
|
13
|
+
* @param body - Raw bytes as stored in `page_html_blobs.body`.
|
|
14
|
+
* @param codec - The `codec` column value (e.g. `'zstd'`, `'none'`).
|
|
15
|
+
* @returns The decoded HTML string.
|
|
16
|
+
* @throws {Error} If the codec is not recognised.
|
|
17
|
+
*/
|
|
18
|
+
export declare function decodeStoredBlob(body: Uint8Array, codec: string): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { zstdDecompressSync } from 'node:zlib';
|
|
2
|
+
/**
|
|
3
|
+
* Decodes a stored HTML body BLOB according to its codec marker. The codec
|
|
4
|
+
* column on `page_html_blobs` records which encoding was applied at write
|
|
5
|
+
* time so individual rows can be migrated to a different compression without
|
|
6
|
+
* a table-wide rewrite.
|
|
7
|
+
*
|
|
8
|
+
* Shared by {@link ./database.ts#Database.getHtmlOfPageById} (writer read
|
|
9
|
+
* path) and {@link ./populate-entity-tables/populate-image-items.ts} (0.13
|
|
10
|
+
* migration, which reads HTML *inside* its writer transaction and therefore
|
|
11
|
+
* cannot go through `Database.getHtmlOfPageById` — that method uses the
|
|
12
|
+
* non-transactional Knex instance, and re-entering the pool from within an
|
|
13
|
+
* outer writer trx serialises on libsql's single writer connection).
|
|
14
|
+
* @param body - Raw bytes as stored in `page_html_blobs.body`.
|
|
15
|
+
* @param codec - The `codec` column value (e.g. `'zstd'`, `'none'`).
|
|
16
|
+
* @returns The decoded HTML string.
|
|
17
|
+
* @throws {Error} If the codec is not recognised.
|
|
18
|
+
*/
|
|
19
|
+
export function decodeStoredBlob(body, codec) {
|
|
20
|
+
// `Buffer.from(buffer)` accepts Uint8Array, Buffer, and array-like
|
|
21
|
+
// shapes uniformly; libsql may hand back any of these for a BLOB
|
|
22
|
+
// column depending on the row encoding.
|
|
23
|
+
const buffer = Buffer.from(body);
|
|
24
|
+
if (codec === 'zstd') {
|
|
25
|
+
return zstdDecompressSync(buffer).toString('utf8');
|
|
26
|
+
}
|
|
27
|
+
if (codec === 'none') {
|
|
28
|
+
return buffer.toString('utf8');
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`Unknown page_html_blobs.codec: ${codec}`);
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PageSource } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decide which {@link PageSource} label a child row reached through the
|
|
4
|
+
* crawl graph (anchor placeholder, sub-resource, redirect chain
|
|
5
|
+
* intermediate) should inherit from its parent.
|
|
6
|
+
*
|
|
7
|
+
* Two simple rules, expressed once so anchor / redirect / sub-resource
|
|
8
|
+
* call sites stay in lockstep:
|
|
9
|
+
*
|
|
10
|
+
* 1. If the parent is in the inventory chain
|
|
11
|
+
* ({@link isInventorySource}) → propagate
|
|
12
|
+
* `'inventory-discovered'`. The child is itself a transitively
|
|
13
|
+
* reached node in the inventory chain; it is NOT a new seed (the
|
|
14
|
+
* seed label is reserved for URLs the operator listed in
|
|
15
|
+
* `--inventory ./list.txt`).
|
|
16
|
+
*
|
|
17
|
+
* 2. Otherwise → return `fallback`. The two production fallbacks differ
|
|
18
|
+
* by call site:
|
|
19
|
+
*
|
|
20
|
+
* - Anchor lineage passes `'crawled'` explicitly so the crawled-wins
|
|
21
|
+
* downgrade inside `resolveContentItemId` fires when the anchor reaches an
|
|
22
|
+
* existing `'inventory-*'` row.
|
|
23
|
+
* - Sub-resource emit passes `undefined` so the DB DEFAULT
|
|
24
|
+
* `'crawled'` lands on the freshly INSERTed `resources` row (the
|
|
25
|
+
* `setResources` path is INSERT-only with `onConflict.ignore()`, so
|
|
26
|
+
* no downgrade is needed).
|
|
27
|
+
* - Redirect chain intermediate uses `'crawled'` (same reason as
|
|
28
|
+
* anchor): an existing inventory-* intermediate reached by a
|
|
29
|
+
* crawled redirect chain must be downgraded.
|
|
30
|
+
*
|
|
31
|
+
* Pure function — keeps the lineage decision testable in isolation from
|
|
32
|
+
* the database transaction / event-emitter wiring that consumes it.
|
|
33
|
+
* @param parentSource - The parent page's stored `source` column (or `undefined` when no parent row exists).
|
|
34
|
+
* @param fallback - The label to return when the parent is NOT in the inventory chain. Pass `'crawled'` to enable the crawled-wins downgrade, or `undefined` to let the DB DEFAULT apply.
|
|
35
|
+
* @returns The lineage label to attach to the child row.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deriveLineageFromParent(parentSource: PageSource | undefined, fallback: PageSource | undefined): PageSource | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isInventorySource } from './is-inventory-source.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decide which {@link PageSource} label a child row reached through the
|
|
4
|
+
* crawl graph (anchor placeholder, sub-resource, redirect chain
|
|
5
|
+
* intermediate) should inherit from its parent.
|
|
6
|
+
*
|
|
7
|
+
* Two simple rules, expressed once so anchor / redirect / sub-resource
|
|
8
|
+
* call sites stay in lockstep:
|
|
9
|
+
*
|
|
10
|
+
* 1. If the parent is in the inventory chain
|
|
11
|
+
* ({@link isInventorySource}) → propagate
|
|
12
|
+
* `'inventory-discovered'`. The child is itself a transitively
|
|
13
|
+
* reached node in the inventory chain; it is NOT a new seed (the
|
|
14
|
+
* seed label is reserved for URLs the operator listed in
|
|
15
|
+
* `--inventory ./list.txt`).
|
|
16
|
+
*
|
|
17
|
+
* 2. Otherwise → return `fallback`. The two production fallbacks differ
|
|
18
|
+
* by call site:
|
|
19
|
+
*
|
|
20
|
+
* - Anchor lineage passes `'crawled'` explicitly so the crawled-wins
|
|
21
|
+
* downgrade inside `resolveContentItemId` fires when the anchor reaches an
|
|
22
|
+
* existing `'inventory-*'` row.
|
|
23
|
+
* - Sub-resource emit passes `undefined` so the DB DEFAULT
|
|
24
|
+
* `'crawled'` lands on the freshly INSERTed `resources` row (the
|
|
25
|
+
* `setResources` path is INSERT-only with `onConflict.ignore()`, so
|
|
26
|
+
* no downgrade is needed).
|
|
27
|
+
* - Redirect chain intermediate uses `'crawled'` (same reason as
|
|
28
|
+
* anchor): an existing inventory-* intermediate reached by a
|
|
29
|
+
* crawled redirect chain must be downgraded.
|
|
30
|
+
*
|
|
31
|
+
* Pure function — keeps the lineage decision testable in isolation from
|
|
32
|
+
* the database transaction / event-emitter wiring that consumes it.
|
|
33
|
+
* @param parentSource - The parent page's stored `source` column (or `undefined` when no parent row exists).
|
|
34
|
+
* @param fallback - The label to return when the parent is NOT in the inventory chain. Pass `'crawled'` to enable the crawled-wins downgrade, or `undefined` to let the DB DEFAULT apply.
|
|
35
|
+
* @returns The lineage label to attach to the child row.
|
|
36
|
+
*/
|
|
37
|
+
export function deriveLineageFromParent(parentSource, fallback) {
|
|
38
|
+
if (isInventorySource(parentSource)) {
|
|
39
|
+
return 'inventory-discovered';
|
|
40
|
+
}
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Drops the five legacy write-model tables from a migrated archive. Reader
|
|
4
|
+
* and writer both operate exclusively on the entity / ref tables, so once
|
|
5
|
+
* the 0.13 populate has copied everything across (and
|
|
6
|
+
* `retargetLegacyFkTables` has repointed the adjunct FKs at
|
|
7
|
+
* `content_items`), the legacy tables are pure dead weight — dropping them
|
|
8
|
+
* reclaims the duplicated storage and removes the last consumers of the
|
|
9
|
+
* `pages(id)` id-space.
|
|
10
|
+
*
|
|
11
|
+
* **Requires `PRAGMA foreign_keys = OFF`** (asserted at runtime, because a
|
|
12
|
+
* caller that forgets the toggle would fail nondeterministically instead
|
|
13
|
+
* of loudly). Two reasons for the requirement:
|
|
14
|
+
*
|
|
15
|
+
* 1. `pages.redirectDestId` is a self-referential FK. With enforcement ON,
|
|
16
|
+
* `DROP TABLE` performs an implicit `DELETE FROM`, and deleting a
|
|
17
|
+
* redirect-destination row before its source row trips the constraint —
|
|
18
|
+
* whether the drop survives depends on row order, so archives with
|
|
19
|
+
* redirect chains can fail nondeterministically.
|
|
20
|
+
* 2. With enforcement OFF the implicit `DELETE FROM` is skipped entirely
|
|
21
|
+
* and SQLite reclaims each table as a whole b-tree — O(pages) row
|
|
22
|
+
* deletions become O(1) truncations, which matters at the several
|
|
23
|
+
* hundred-thousand-row scale real archives reach.
|
|
24
|
+
*
|
|
25
|
+
* The drops still run children-first (`resources-referrers` / `anchors` /
|
|
26
|
+
* `images` reference `pages` / `resources`) as defence in depth. Missing
|
|
27
|
+
* tables are skipped so the function is idempotent.
|
|
28
|
+
*
|
|
29
|
+
* Data-integrity of the surviving tables is asserted separately by
|
|
30
|
+
* `checkForeignKeyIntegrity` (`PRAGMA foreign_key_check` ignores the
|
|
31
|
+
* `foreign_keys` setting), which the migration script runs right after
|
|
32
|
+
* this function.
|
|
33
|
+
* @param trx - Knex transaction on the archive being migrated
|
|
34
|
+
* (`scripts/migrate-to-0.13.mjs` is the caller).
|
|
35
|
+
* @throws {Error} when the connection still has `PRAGMA foreign_keys = ON`
|
|
36
|
+
* (`foreign_keys` cannot change inside a transaction, so the caller must
|
|
37
|
+
* toggle it off before opening the transaction).
|
|
38
|
+
* @example
|
|
39
|
+
* await db.raw('PRAGMA foreign_keys = OFF');
|
|
40
|
+
* await db.transaction(async (trx) => {
|
|
41
|
+
* await dropLegacyTables(trx);
|
|
42
|
+
* });
|
|
43
|
+
* await db.raw('PRAGMA foreign_keys = ON');
|
|
44
|
+
*/
|
|
45
|
+
export declare function dropLegacyTables(trx: Knex): Promise<void>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drops the five legacy write-model tables from a migrated archive. Reader
|
|
3
|
+
* and writer both operate exclusively on the entity / ref tables, so once
|
|
4
|
+
* the 0.13 populate has copied everything across (and
|
|
5
|
+
* `retargetLegacyFkTables` has repointed the adjunct FKs at
|
|
6
|
+
* `content_items`), the legacy tables are pure dead weight — dropping them
|
|
7
|
+
* reclaims the duplicated storage and removes the last consumers of the
|
|
8
|
+
* `pages(id)` id-space.
|
|
9
|
+
*
|
|
10
|
+
* **Requires `PRAGMA foreign_keys = OFF`** (asserted at runtime, because a
|
|
11
|
+
* caller that forgets the toggle would fail nondeterministically instead
|
|
12
|
+
* of loudly). Two reasons for the requirement:
|
|
13
|
+
*
|
|
14
|
+
* 1. `pages.redirectDestId` is a self-referential FK. With enforcement ON,
|
|
15
|
+
* `DROP TABLE` performs an implicit `DELETE FROM`, and deleting a
|
|
16
|
+
* redirect-destination row before its source row trips the constraint —
|
|
17
|
+
* whether the drop survives depends on row order, so archives with
|
|
18
|
+
* redirect chains can fail nondeterministically.
|
|
19
|
+
* 2. With enforcement OFF the implicit `DELETE FROM` is skipped entirely
|
|
20
|
+
* and SQLite reclaims each table as a whole b-tree — O(pages) row
|
|
21
|
+
* deletions become O(1) truncations, which matters at the several
|
|
22
|
+
* hundred-thousand-row scale real archives reach.
|
|
23
|
+
*
|
|
24
|
+
* The drops still run children-first (`resources-referrers` / `anchors` /
|
|
25
|
+
* `images` reference `pages` / `resources`) as defence in depth. Missing
|
|
26
|
+
* tables are skipped so the function is idempotent.
|
|
27
|
+
*
|
|
28
|
+
* Data-integrity of the surviving tables is asserted separately by
|
|
29
|
+
* `checkForeignKeyIntegrity` (`PRAGMA foreign_key_check` ignores the
|
|
30
|
+
* `foreign_keys` setting), which the migration script runs right after
|
|
31
|
+
* this function.
|
|
32
|
+
* @param trx - Knex transaction on the archive being migrated
|
|
33
|
+
* (`scripts/migrate-to-0.13.mjs` is the caller).
|
|
34
|
+
* @throws {Error} when the connection still has `PRAGMA foreign_keys = ON`
|
|
35
|
+
* (`foreign_keys` cannot change inside a transaction, so the caller must
|
|
36
|
+
* toggle it off before opening the transaction).
|
|
37
|
+
* @example
|
|
38
|
+
* await db.raw('PRAGMA foreign_keys = OFF');
|
|
39
|
+
* await db.transaction(async (trx) => {
|
|
40
|
+
* await dropLegacyTables(trx);
|
|
41
|
+
* });
|
|
42
|
+
* await db.raw('PRAGMA foreign_keys = ON');
|
|
43
|
+
*/
|
|
44
|
+
export async function dropLegacyTables(trx) {
|
|
45
|
+
const pragma = await trx.raw('PRAGMA foreign_keys');
|
|
46
|
+
if (pragma[0]?.foreign_keys === 1) {
|
|
47
|
+
throw new Error('dropLegacyTables: PRAGMA foreign_keys is ON — turn it OFF before the transaction. ' +
|
|
48
|
+
'With enforcement ON, dropping `pages` runs an implicit DELETE whose row order ' +
|
|
49
|
+
'can trip the redirectDestId self-FK nondeterministically.');
|
|
50
|
+
}
|
|
51
|
+
await trx.raw('DROP TABLE IF EXISTS "resources-referrers"');
|
|
52
|
+
await trx.raw('DROP TABLE IF EXISTS "anchors"');
|
|
53
|
+
await trx.raw('DROP TABLE IF EXISTS "images"');
|
|
54
|
+
await trx.raw('DROP TABLE IF EXISTS "resources"');
|
|
55
|
+
await trx.raw('DROP TABLE IF EXISTS "pages"');
|
|
56
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import { remove } from './remove.js';
|
|
3
3
|
/**
|
|
4
|
-
* Checks whether a value is a
|
|
4
|
+
* Checks whether a value is a `NodeJS.ErrnoException`.
|
|
5
5
|
* @param error - The value to check.
|
|
6
6
|
* @returns `true` if the value has a `code` property of type `string`.
|
|
7
7
|
*/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Bulk-resolve a raw error message for each given page id, using only sources
|
|
4
|
+
* reachable from a {@link Knex} handle. Read order: `page_errors` (keyed by
|
|
5
|
+
* `pageId`, the most direct signal a scrape attempt recorded), then
|
|
6
|
+
* `crawl_errors` (keyed by `url`, the crawler-channel record for failures
|
|
7
|
+
* that happened before a page row was scraped).
|
|
8
|
+
*
|
|
9
|
+
* **Known limitation — pre-`crawl_errors` archives**: This helper does NOT
|
|
10
|
+
* read `error.log`. The `crawl_errors` table is created empty (by
|
|
11
|
+
* `initSchema` on fresh archives, by `scripts/migrate-to-0.13.mjs` on
|
|
12
|
+
* migrated ones) and historical lines from `error.log` are never
|
|
13
|
+
* back-filled, so an archive whose failures live only in `error.log`
|
|
14
|
+
* will resolve every id to "no message" here. The
|
|
15
|
+
* downstream `Database.resetFailedPages` treats absence as `unknown` (still
|
|
16
|
+
* retryable), so legacy archives lose the permanent-kind exclusion until a
|
|
17
|
+
* fresh crawl run populates `crawl_errors` / `page_errors`. The trade-off
|
|
18
|
+
* (no error.log parsing in the writer path) keeps the writer dependency
|
|
19
|
+
* surface narrow and avoids re-implementing the parser already living in
|
|
20
|
+
* `@nitpicker/query`'s `resolveFailedPageMessages` — which the crawler
|
|
21
|
+
* package cannot import (reverse-direction dependency). When this matters
|
|
22
|
+
* in practice, run the archive through one fresh `crawl --retry-failed`
|
|
23
|
+
* pass first to populate the structured tables.
|
|
24
|
+
*
|
|
25
|
+
* Pages with no message in any consulted source are simply absent from the
|
|
26
|
+
* returned map; callers treat the absence as "unclassifiable, keep retrying"
|
|
27
|
+
* (i.e. `unknown`).
|
|
28
|
+
* @param instance - The {@link Knex} handle.
|
|
29
|
+
* @param ids - Candidate `pages.id` values.
|
|
30
|
+
* @param urls - The corresponding `pages.url` values, in the same order as
|
|
31
|
+
* `ids`. Length and indexing MUST match `ids` so the page → url join can be
|
|
32
|
+
* reconstructed without a second `pages` round-trip.
|
|
33
|
+
* @returns `Map<pageId, message>` populated only for ids whose message was
|
|
34
|
+
* found in one of the consulted tables.
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const messages = await getFailedPageMessages(
|
|
38
|
+
* instance,
|
|
39
|
+
* candidates.map(c => c.id),
|
|
40
|
+
* candidates.map(c => c.url),
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function getFailedPageMessages(instance: Knex, ids: readonly number[], urls: readonly string[]): Promise<Map<number, string>>;
|