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