@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,43 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the adjunct tables that hang off `content_items` (plus the two
|
|
4
|
+
* standalone log tables), guarded per-table so partially-provisioned
|
|
5
|
+
* archives converge to the full set:
|
|
6
|
+
*
|
|
7
|
+
* - `page_errors` — partial scrape failures, FK → `content_items(id)`
|
|
8
|
+
* - `crawl_errors` — crawler-level error channel (no FK; the URL may be
|
|
9
|
+
* an external link that failed DNS, or null for a process-level error)
|
|
10
|
+
* - `page_tags` — Wappalyzer detections, FK → `content_items(id)`
|
|
11
|
+
* - `page_jsonld` — JSON-LD / SpeculationRules, FK → `content_items(id)`
|
|
12
|
+
* - `inventory_runs` — `--inventory` audit log (no FK; append-only)
|
|
13
|
+
* - `analysis_text_refs` + `analysis_violations` — analyze-phase findings,
|
|
14
|
+
* FK → `content_items(id)`
|
|
15
|
+
* - `page_html_blobs` + `page_html_ref` — content-addressable HTML
|
|
16
|
+
* snapshots, FK → `content_items(id)`
|
|
17
|
+
*
|
|
18
|
+
* The DDL is shared between fresh-archive provisioning ({@link initSchema}
|
|
19
|
+
* calls this right after `createEntityTables`) and the migration script
|
|
20
|
+
* (`scripts/migrate-to-0.13.mjs` calls it before retargeting FK
|
|
21
|
+
* declarations and dropping the legacy tables). Keeping the schema in one
|
|
22
|
+
* function guarantees both origin points produce identical tables — the
|
|
23
|
+
* pre-0.13 era kept per-table copies of this DDL in separate lazy-migration
|
|
24
|
+
* modules, and those copies drifted: they declared `REFERENCES pages(id)`
|
|
25
|
+
* while `initSchema` had moved on to `content_items(id)`, leaving migrated
|
|
26
|
+
* archives with stale FK targets that only `scripts/migrate-to-0.13.mjs`'s
|
|
27
|
+
* rename-copy-drop pass can now repair.
|
|
28
|
+
*
|
|
29
|
+
* Unlike `createRefTables` / `createEntityTables` (whose callers guard with
|
|
30
|
+
* a single sentinel table), each table here is guarded individually because
|
|
31
|
+
* the migration-script caller sees archives where any subset may already
|
|
32
|
+
* exist (e.g. `page_tags` from the 0.10 migration but no `inventory_runs`).
|
|
33
|
+
* Index creation stays inside each guard: an existing table keeps whatever
|
|
34
|
+
* indexes its creation path declared.
|
|
35
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
36
|
+
* @example
|
|
37
|
+
* // Must run after createEntityTables — the page-scoped tables FK into
|
|
38
|
+
* // content_items(id).
|
|
39
|
+
* await createRefTables(db);
|
|
40
|
+
* await createEntityTables(db);
|
|
41
|
+
* await createAdjunctTables(db);
|
|
42
|
+
*/
|
|
43
|
+
export declare function createAdjunctTables(instance: Knex): Promise<void>;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates the adjunct tables that hang off `content_items` (plus the two
|
|
3
|
+
* standalone log tables), guarded per-table so partially-provisioned
|
|
4
|
+
* archives converge to the full set:
|
|
5
|
+
*
|
|
6
|
+
* - `page_errors` — partial scrape failures, FK → `content_items(id)`
|
|
7
|
+
* - `crawl_errors` — crawler-level error channel (no FK; the URL may be
|
|
8
|
+
* an external link that failed DNS, or null for a process-level error)
|
|
9
|
+
* - `page_tags` — Wappalyzer detections, FK → `content_items(id)`
|
|
10
|
+
* - `page_jsonld` — JSON-LD / SpeculationRules, FK → `content_items(id)`
|
|
11
|
+
* - `inventory_runs` — `--inventory` audit log (no FK; append-only)
|
|
12
|
+
* - `analysis_text_refs` + `analysis_violations` — analyze-phase findings,
|
|
13
|
+
* FK → `content_items(id)`
|
|
14
|
+
* - `page_html_blobs` + `page_html_ref` — content-addressable HTML
|
|
15
|
+
* snapshots, FK → `content_items(id)`
|
|
16
|
+
*
|
|
17
|
+
* The DDL is shared between fresh-archive provisioning ({@link initSchema}
|
|
18
|
+
* calls this right after `createEntityTables`) and the migration script
|
|
19
|
+
* (`scripts/migrate-to-0.13.mjs` calls it before retargeting FK
|
|
20
|
+
* declarations and dropping the legacy tables). Keeping the schema in one
|
|
21
|
+
* function guarantees both origin points produce identical tables — the
|
|
22
|
+
* pre-0.13 era kept per-table copies of this DDL in separate lazy-migration
|
|
23
|
+
* modules, and those copies drifted: they declared `REFERENCES pages(id)`
|
|
24
|
+
* while `initSchema` had moved on to `content_items(id)`, leaving migrated
|
|
25
|
+
* archives with stale FK targets that only `scripts/migrate-to-0.13.mjs`'s
|
|
26
|
+
* rename-copy-drop pass can now repair.
|
|
27
|
+
*
|
|
28
|
+
* Unlike `createRefTables` / `createEntityTables` (whose callers guard with
|
|
29
|
+
* a single sentinel table), each table here is guarded individually because
|
|
30
|
+
* the migration-script caller sees archives where any subset may already
|
|
31
|
+
* exist (e.g. `page_tags` from the 0.10 migration but no `inventory_runs`).
|
|
32
|
+
* Index creation stays inside each guard: an existing table keeps whatever
|
|
33
|
+
* indexes its creation path declared.
|
|
34
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
35
|
+
* @example
|
|
36
|
+
* // Must run after createEntityTables — the page-scoped tables FK into
|
|
37
|
+
* // content_items(id).
|
|
38
|
+
* await createRefTables(db);
|
|
39
|
+
* await createEntityTables(db);
|
|
40
|
+
* await createAdjunctTables(db);
|
|
41
|
+
*/
|
|
42
|
+
export async function createAdjunctTables(instance) {
|
|
43
|
+
if (!(await instance.schema.hasTable('page_errors'))) {
|
|
44
|
+
await instance.schema.createTable('page_errors', (t) => {
|
|
45
|
+
// Records partial scrape failures (e.g. a viewport switch that
|
|
46
|
+
// detaches the frame and trips beholder's @retryable into the
|
|
47
|
+
// `retryExhausted` phase). A page can have zero or more rows here
|
|
48
|
+
// in addition to its normal `content_items` entry — the page
|
|
49
|
+
// itself is considered successfully scraped, but image capture or
|
|
50
|
+
// another secondary step failed for at least one device preset.
|
|
51
|
+
t.increments('id');
|
|
52
|
+
t.integer('pageId').notNullable().unsigned().references('content_items.id');
|
|
53
|
+
t.string('phase').notNullable();
|
|
54
|
+
t.text('message').notNullable();
|
|
55
|
+
t.integer('createdAt').notNullable();
|
|
56
|
+
t.index('pageId');
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!(await instance.schema.hasTable('crawl_errors'))) {
|
|
60
|
+
await instance.schema.createTable('crawl_errors', (t) => {
|
|
61
|
+
// Structured form of the crawler-level `error` channel that otherwise
|
|
62
|
+
// only lands in `error.log`. Unlike `page_errors` these are not tied to
|
|
63
|
+
// a scraped page (the URL may be an external link that failed DNS, or
|
|
64
|
+
// null for a process-level error), so there is no `pageId` FK and `url`
|
|
65
|
+
// is nullable. The cause is NOT stored — it is classified on read from
|
|
66
|
+
// `message` so older archives (which only have `error.log`) classify the
|
|
67
|
+
// same way.
|
|
68
|
+
t.increments('id');
|
|
69
|
+
t.string('url', 8190).nullable();
|
|
70
|
+
t.boolean('isExternal');
|
|
71
|
+
t.text('message').notNullable();
|
|
72
|
+
t.integer('createdAt').notNullable();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (!(await instance.schema.hasTable('page_tags'))) {
|
|
76
|
+
await instance.schema.createTable('page_tags', (t) => {
|
|
77
|
+
// Wappalyzer-derived technology detection. One row per
|
|
78
|
+
// (provider × externalId) tuple per page. `category` is the first
|
|
79
|
+
// element of `categories`; the full list lives in the JSON
|
|
80
|
+
// `categories` column. `sources` records where the provider was
|
|
81
|
+
// detected (script-src / inline / iframe-src / window-global / …).
|
|
82
|
+
t.increments('id');
|
|
83
|
+
t.integer('pageId')
|
|
84
|
+
.notNullable()
|
|
85
|
+
.unsigned()
|
|
86
|
+
.references('content_items.id')
|
|
87
|
+
.onDelete('CASCADE');
|
|
88
|
+
t.string('provider').notNullable();
|
|
89
|
+
t.string('category');
|
|
90
|
+
t.string('externalId');
|
|
91
|
+
t.string('version');
|
|
92
|
+
t.integer('confidence');
|
|
93
|
+
t.json('categories');
|
|
94
|
+
t.json('sources');
|
|
95
|
+
t.index('pageId');
|
|
96
|
+
t.index('provider');
|
|
97
|
+
t.index('externalId');
|
|
98
|
+
});
|
|
99
|
+
// Compound indexes for the "find duplicate IDs across pages" and
|
|
100
|
+
// "list pages using provider X" hot paths. Knex's schema builder
|
|
101
|
+
// can't express compound indexes inline in a way that round-trips
|
|
102
|
+
// through libsql consistently, so raw SQL is used.
|
|
103
|
+
await instance.raw('CREATE INDEX page_tags_provider_extId ON page_tags(provider, externalId)');
|
|
104
|
+
await instance.raw('CREATE INDEX page_tags_provider_pageId ON page_tags(provider, pageId)');
|
|
105
|
+
}
|
|
106
|
+
if (!(await instance.schema.hasTable('page_jsonld'))) {
|
|
107
|
+
await instance.schema.createTable('page_jsonld', (t) => {
|
|
108
|
+
// JSON-LD and SpeculationRules entries captured from
|
|
109
|
+
// `<script type="application/ld+json">` and
|
|
110
|
+
// `<script type="speculationrules">`. `kind` discriminates; `type`
|
|
111
|
+
// is the top-level `@type` extracted by classify-jsonld-type for
|
|
112
|
+
// indexable filtering. `raw` is stored uncompressed; SQLite
|
|
113
|
+
// overflow pages handle multi-KB JSON bodies transparently.
|
|
114
|
+
t.increments('id');
|
|
115
|
+
t.integer('pageId')
|
|
116
|
+
.notNullable()
|
|
117
|
+
.unsigned()
|
|
118
|
+
.references('content_items.id')
|
|
119
|
+
.onDelete('CASCADE');
|
|
120
|
+
t.string('kind').notNullable();
|
|
121
|
+
t.string('type');
|
|
122
|
+
t.text('raw').notNullable();
|
|
123
|
+
t.json('parsed');
|
|
124
|
+
t.text('parseError');
|
|
125
|
+
t.index('pageId');
|
|
126
|
+
t.index('type');
|
|
127
|
+
});
|
|
128
|
+
// Compound `(type, pageId)` accelerates streaming
|
|
129
|
+
// `list_pages_by_jsonld_type` JOINs.
|
|
130
|
+
await instance.raw('CREATE INDEX page_jsonld_type_pageId ON page_jsonld(type, pageId)');
|
|
131
|
+
}
|
|
132
|
+
if (!(await instance.schema.hasTable('inventory_runs'))) {
|
|
133
|
+
await instance.schema.createTable('inventory_runs', (t) => {
|
|
134
|
+
// One row per successful `--inventory <list>` invocation. The
|
|
135
|
+
// archive's audit log of "when did we apply which deploy list
|
|
136
|
+
// at what scale". `.bak` is removed on success so this table
|
|
137
|
+
// is the only durable provenance record. Column semantics live
|
|
138
|
+
// on the `InventoryRunMeta` interface in `archive/types.ts`.
|
|
139
|
+
t.increments('id');
|
|
140
|
+
t.string('ran_at').notNullable();
|
|
141
|
+
t.string('list_label').nullable();
|
|
142
|
+
t.string('source_file_sha256', 64).nullable();
|
|
143
|
+
t.integer('total_lines').nullable();
|
|
144
|
+
t.integer('new_pages').nullable();
|
|
145
|
+
t.integer('new_resources').nullable();
|
|
146
|
+
t.integer('scope_skipped').nullable();
|
|
147
|
+
t.text('notes').nullable();
|
|
148
|
+
t.index('ran_at');
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (!(await instance.schema.hasTable('analysis_text_refs'))) {
|
|
152
|
+
await instance.raw(`
|
|
153
|
+
CREATE TABLE analysis_text_refs (
|
|
154
|
+
id integer primary key,
|
|
155
|
+
text text not null,
|
|
156
|
+
sha256 text not null,
|
|
157
|
+
unique(sha256, text)
|
|
158
|
+
)
|
|
159
|
+
`);
|
|
160
|
+
}
|
|
161
|
+
if (!(await instance.schema.hasTable('analysis_violations'))) {
|
|
162
|
+
await instance.raw(`
|
|
163
|
+
CREATE TABLE analysis_violations (
|
|
164
|
+
id integer primary key,
|
|
165
|
+
page_id integer not null references content_items(id),
|
|
166
|
+
validator text not null,
|
|
167
|
+
severity text not null,
|
|
168
|
+
rule text not null,
|
|
169
|
+
message_text_id integer not null references analysis_text_refs(id),
|
|
170
|
+
code_text_id integer references analysis_text_refs(id),
|
|
171
|
+
page_url_sort_key text not null,
|
|
172
|
+
message_sort_key text not null,
|
|
173
|
+
code_sort_key text not null,
|
|
174
|
+
line integer,
|
|
175
|
+
col integer
|
|
176
|
+
)
|
|
177
|
+
`);
|
|
178
|
+
await instance.raw('CREATE INDEX av_url_order ON analysis_violations(page_url_sort_key, id)');
|
|
179
|
+
await instance.raw('CREATE INDEX av_filter_url ON analysis_violations(validator, severity, rule, page_url_sort_key, id)');
|
|
180
|
+
await instance.raw('CREATE INDEX av_validator_url ON analysis_violations(validator, page_url_sort_key, id)');
|
|
181
|
+
await instance.raw('CREATE INDEX av_severity_url ON analysis_violations(severity, page_url_sort_key, id)');
|
|
182
|
+
await instance.raw('CREATE INDEX av_rule_url ON analysis_violations(rule, page_url_sort_key, id)');
|
|
183
|
+
await instance.raw('CREATE INDEX av_message_order ON analysis_violations(message_sort_key, id)');
|
|
184
|
+
await instance.raw('CREATE INDEX av_code_order ON analysis_violations(code_sort_key, id)');
|
|
185
|
+
await instance.raw('CREATE INDEX av_page ON analysis_violations(page_id, id)');
|
|
186
|
+
}
|
|
187
|
+
// Content-addressable HTML blob storage. Knex's schema builder doesn't
|
|
188
|
+
// expose a WITHOUT ROWID toggle, so the BLOB tables are created via raw
|
|
189
|
+
// SQL. WITHOUT ROWID keeps the rows packed inside the b-tree leaves
|
|
190
|
+
// (no hidden rowid + secondary index pair), which matters for the blob
|
|
191
|
+
// table where a 32-byte hash PK + multi-KB body is the dominant row
|
|
192
|
+
// shape.
|
|
193
|
+
if (!(await instance.schema.hasTable('page_html_blobs'))) {
|
|
194
|
+
await instance.raw(`
|
|
195
|
+
CREATE TABLE page_html_blobs (
|
|
196
|
+
hash BLOB PRIMARY KEY,
|
|
197
|
+
body BLOB NOT NULL,
|
|
198
|
+
codec TEXT NOT NULL CHECK(codec IN ('zstd', 'none')),
|
|
199
|
+
size_raw INTEGER NOT NULL,
|
|
200
|
+
size_stored INTEGER NOT NULL
|
|
201
|
+
) WITHOUT ROWID
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
if (!(await instance.schema.hasTable('page_html_ref'))) {
|
|
205
|
+
await instance.raw(`
|
|
206
|
+
CREATE TABLE page_html_ref (
|
|
207
|
+
page_id INTEGER PRIMARY KEY REFERENCES content_items(id) ON DELETE CASCADE,
|
|
208
|
+
hash BLOB NOT NULL REFERENCES page_html_blobs(hash)
|
|
209
|
+
) WITHOUT ROWID
|
|
210
|
+
`);
|
|
211
|
+
await instance.raw('CREATE INDEX idx_page_html_ref_hash ON page_html_ref(hash)');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the 6 core entity and edge tables of the 0.13 format (issue #192).
|
|
4
|
+
*
|
|
5
|
+
* These are the normalised entity / edge tables that replace the legacy
|
|
6
|
+
* write model (`pages`, `anchors`, `images`, `resources`, `resources-referrers`)
|
|
7
|
+
* in the 0.13 format. This migration is purely additive DDL — no existing table
|
|
8
|
+
* is modified and no row is inserted; the populate step
|
|
9
|
+
* (`populateEntityTables`) fills the tables from the legacy sources.
|
|
10
|
+
*
|
|
11
|
+
* Tables created:
|
|
12
|
+
*
|
|
13
|
+
* - `content_items` — replaces `pages` (core columns). The remaining
|
|
14
|
+
* per-page metadata splits into `page_meta`.
|
|
15
|
+
* - `page_meta` — page-specific metadata (title, description, meta tags,
|
|
16
|
+
* OpenGraph, Twitter, robots, denormalised aggregates, meta_extras JSON
|
|
17
|
+
* pointer). Split from `pages` so that filter / cursor queries against
|
|
18
|
+
* `content_items` scan a narrower row.
|
|
19
|
+
* - `resource_items` — replaces `resources`. Identity URL splits into
|
|
20
|
+
* `url_id` (regular URLs) vs `url_blob_id` (large `data:` URIs, routed
|
|
21
|
+
* via `blob_refs`) — a resource's own URL is captured verbatim from
|
|
22
|
+
* the network layer and, unlike a page's URL, can legally be a large
|
|
23
|
+
* inline `data:` URI (e.g. a CSS `background-image` sub-resource).
|
|
24
|
+
* - `anchor_edges` — replaces `anchors`. Deduped to distinct
|
|
25
|
+
* `(page_id, href_page_id)` pairs; `count` records how many instances
|
|
26
|
+
* were observed and `first_hash` / `first_text_id` capture the first
|
|
27
|
+
* instance's identity so the most important observable fact per link is
|
|
28
|
+
* preserved without every redundant row.
|
|
29
|
+
* - `resource_ref_edges` — replaces `resources-referrers`. Structural
|
|
30
|
+
* rename with an added `count` column; `WITHOUT ROWID` because the
|
|
31
|
+
* composite PK `(resource_id, page_id)` is the natural clustering key
|
|
32
|
+
* and every column is small — the same reasoning as `page_html_blobs`.
|
|
33
|
+
* - `image_items` — replaces `images`. `src` / `currentSrc` split into
|
|
34
|
+
* `*_url_id` (regular URLs) vs `*_blob_id` (large `data:` URIs, routed
|
|
35
|
+
* via `blob_refs`); `sourceCode` is replaced by `dom_path_text_id`,
|
|
36
|
+
* which the populate step derives from the `outerHTML` string.
|
|
37
|
+
*
|
|
38
|
+
* ### Key invariants
|
|
39
|
+
*
|
|
40
|
+
* **Same PK values as legacy.** `content_items.id`, `resource_items.id`,
|
|
41
|
+
* and `image_items.id` reuse the exact PK values from `pages.id`,
|
|
42
|
+
* `resources.id`, and `images.id` respectively. The populate step inserts
|
|
43
|
+
* rows with explicit IDs so every existing FK reference in `page_errors`,
|
|
44
|
+
* `page_tags`, `page_jsonld`, `page_html_ref`, and `resources-referrers`
|
|
45
|
+
* (before it becomes `resource_ref_edges`) survives the switch without
|
|
46
|
+
* any per-row UPDATE. `AUTOINCREMENT` is nevertheless applied on all four
|
|
47
|
+
* entity PKs (`content_items` / `resource_items` / `anchor_edges` /
|
|
48
|
+
* `image_items`) to match the legacy contract (`t.increments()` on
|
|
49
|
+
* `pages` / `resources` / `anchors` / `images`) — this prevents rowid
|
|
50
|
+
* reuse after DELETE, so external systems (analysis outputs, viewer
|
|
51
|
+
* bookmarks, Sheets exports) keyed on `content_item.id` cannot be
|
|
52
|
+
* silently reassigned to a different record.
|
|
53
|
+
*
|
|
54
|
+
* **UNIQUE(url_id) on content_items and resource_items.** The legacy
|
|
55
|
+
* `pages.url UNIQUE` / `resources.url UNIQUE` guaranteed one row per
|
|
56
|
+
* URL string. Under the new model the URL string is stored once in
|
|
57
|
+
* `url_refs` and each entity references `url_refs.id` via `url_id` —
|
|
58
|
+
* but `url_refs.url UNIQUE` only guarantees "one URL string → one
|
|
59
|
+
* ref id", it does NOT prevent two entity rows from claiming the same
|
|
60
|
+
* ref id. `UNIQUE(url_id)` on both `content_items` and `resource_items`
|
|
61
|
+
* re-establishes that guarantee at the entity level — without it a
|
|
62
|
+
* populate bug could attach two entity rows to the same URL, and every
|
|
63
|
+
* by-URL reader would silently return an arbitrary one. The UNIQUE
|
|
64
|
+
* constraint's auto-index also serves the by-URL seek path, so no
|
|
65
|
+
* separate `CREATE INDEX ... ON content_items(url_id)` is needed.
|
|
66
|
+
* `resource_items.url_id` is nullable (unlike `content_items.url_id`)
|
|
67
|
+
* because a resource's identity URL can itself be blob-routed — see the
|
|
68
|
+
* `resource_items url / blob mutual-exclusion CHECK` invariant below.
|
|
69
|
+
* `UNIQUE` on a nullable SQLite column only dedups the non-NULL values,
|
|
70
|
+
* so the guarantee still holds for every resource that does have a
|
|
71
|
+
* `url_id`.
|
|
72
|
+
*
|
|
73
|
+
* **`redirect_dest_id` self-reference is DEFERRABLE INITIALLY DEFERRED.**
|
|
74
|
+
* `content_items.redirect_dest_id` references `content_items(id)` (not
|
|
75
|
+
* `pages(id)`), mirroring the legacy `pages.redirectDestId → pages.id`
|
|
76
|
+
* self-reference. In the real archive shape, a redirect source can be
|
|
77
|
+
* discovered as an anchor (assigned a low `pages.id`) BEFORE its
|
|
78
|
+
* destination is crawled (higher `pages.id`), so a straight
|
|
79
|
+
* `ORDER BY id ASC` populate would violate the FK on the source row.
|
|
80
|
+
* Making the FK deferred lets the populate step commit all `content_items`
|
|
81
|
+
* inserts inside one transaction without any per-row ordering
|
|
82
|
+
* discipline — SQLite validates the constraint only at COMMIT time.
|
|
83
|
+
*
|
|
84
|
+
* **`page_meta.page_id` PK == FK ON DELETE CASCADE.** `page_meta` uses
|
|
85
|
+
* `page_id` as both the primary key and the FK back to `content_items(id)`.
|
|
86
|
+
* This is a 1:1 relation (every content_item has at most one meta row),
|
|
87
|
+
* so a separate autoincrement id would only bloat the row. The cascade
|
|
88
|
+
* mirrors the legacy `page_html_ref` / `page_tags` / `page_jsonld` FKs
|
|
89
|
+
* to `pages(id)` so a future cleanup pass can DELETE from
|
|
90
|
+
* `content_items` without leaving orphan meta rows.
|
|
91
|
+
*
|
|
92
|
+
* **`content_items.source` and `resource_items.source` DEFAULT 'crawled'.**
|
|
93
|
+
* The legacy `pages.source` / `resources.source` columns were
|
|
94
|
+
* `NOT NULL DEFAULT 'crawled'`, and multiple existing writer paths rely
|
|
95
|
+
* on the default (redirect-source insert, per-chunk resource insert, and
|
|
96
|
+
* `markBrowserScrape`). Preserving the default keeps those callsites
|
|
97
|
+
* working when the 0.13 write path re-points them at the new tables — dropping
|
|
98
|
+
* the default would turn a routine crawl into an immediate hard failure
|
|
99
|
+
* the first time a callsite omits `source`.
|
|
100
|
+
*
|
|
101
|
+
* **`anchor_edges` dedup shape.** `unique(page_id, href_page_id)` enforces
|
|
102
|
+
* the collapse from ≈ 13M legacy `anchors` rows to ≈ 9.7M `anchor_edges`
|
|
103
|
+
* rows (~25 % reduction on the reference archive).
|
|
104
|
+
* `first_hash` and `first_text_id` capture the anchor `hash` and
|
|
105
|
+
* `textContent` of the FIRST instance encountered (lowest `anchors.id`
|
|
106
|
+
* for the pair); duplicate observations are counted via `count` without
|
|
107
|
+
* retaining their bodies. The UNIQUE constraint's auto-index on
|
|
108
|
+
* `(page_id, href_page_id)` also serves any `WHERE page_id = ?` seek via
|
|
109
|
+
* SQLite's leading-prefix rule, so no separate `CREATE INDEX ... ON
|
|
110
|
+
* anchor_edges(page_id)` is needed; only the reverse-direction
|
|
111
|
+
* `idx_anchor_edges_href` on `href_page_id` alone is added.
|
|
112
|
+
*
|
|
113
|
+
* **`image_items.dom_path_text_id NOT NULL`.** Every image row must
|
|
114
|
+
* resolve to a `text_refs` entry describing its DOM position. The
|
|
115
|
+
* image-items populate derives the path from `images.sourceCode` (the
|
|
116
|
+
* stored `outerHTML`); an
|
|
117
|
+
* image whose `sourceCode` is empty falls back to the synthetic label
|
|
118
|
+
* `img[unknown]` (via the image-items populate) so the FK is never violated.
|
|
119
|
+
*
|
|
120
|
+
* **`image_items` src / blob mutual-exclusion CHECK.** `src_url_id` and
|
|
121
|
+
* `src_blob_id` (and their `current_src_*` mirror) are separate nullable
|
|
122
|
+
* columns because a `<img>` value can be either a plain URL or a large
|
|
123
|
+
* `data:` URI. A single legacy `images.src` TEXT column could not
|
|
124
|
+
* express the ambiguity; the new schema splits the two but adds a CHECK
|
|
125
|
+
* so at most one slot per (src, currentSrc) pair is non-null. Without
|
|
126
|
+
* the CHECK a populate bug or future writer could silently write both,
|
|
127
|
+
* and the viewer would arbitrarily pick one to render.
|
|
128
|
+
*
|
|
129
|
+
* **`resource_items` url / blob mutual-exclusion CHECK.** Same rationale
|
|
130
|
+
* as the image CHECK above, but stricter: `(url_id IS NULL) !=
|
|
131
|
+
* (url_blob_id IS NULL)` requires EXACTLY one slot to be non-null (not
|
|
132
|
+
* "at most one") because a resource — unlike an `<img>` that can
|
|
133
|
+
* legitimately have neither `src` nor `currentSrc` — is always
|
|
134
|
+
* identified by some URL. `resolveUrlOrBlob` (writer) /
|
|
135
|
+
* `resolveUrlOrBlobFromMaps` (populate) are shared with `image_items`'
|
|
136
|
+
* routing so the two entities never disagree on which values count as
|
|
137
|
+
* "large data URI".
|
|
138
|
+
*
|
|
139
|
+
* ### Index rationale
|
|
140
|
+
*
|
|
141
|
+
* Every index below reflects a legacy-baseline single-column index that
|
|
142
|
+
* an existing hot path already relies on. `content_items` gets six
|
|
143
|
+
* indexes: `url_id` (via `UNIQUE` auto-index), `is_external`, `scraped`,
|
|
144
|
+
* `redirect_dest_id` (for the Page Detail inbound-redirect list),
|
|
145
|
+
* `content_type_id`, `crawl_order`, and `source` — all present on
|
|
146
|
+
* legacy `pages`. `page_meta` gets `og_type` and `robots_noindex`
|
|
147
|
+
* because both were indexed on legacy `pages` for the noindex /
|
|
148
|
+
* og:type filter hot paths; after the split those readers land on
|
|
149
|
+
* `page_meta` and need the indexes to remain sub-second. `resource_items` gets `url_id`
|
|
150
|
+
* (via `UNIQUE` auto-index) and `source`. `anchor_edges` gets one
|
|
151
|
+
* reverse-direction index (`idx_anchor_edges_href`); the UNIQUE
|
|
152
|
+
* auto-index covers the forward direction. `resource_ref_edges` needs
|
|
153
|
+
* an explicit reverse-direction index on `page_id` because the
|
|
154
|
+
* composite PK `(resource_id, page_id)` only satisfies the `resource_id`-
|
|
155
|
+
* first prefix; the legacy `resources-referrers` table had exactly
|
|
156
|
+
* this reverse-direction index. `image_items` gets one index on
|
|
157
|
+
* `page_id`. No summary / listfilter compound indexes are created here —
|
|
158
|
+
* they belong to the viewer read model built directly against these
|
|
159
|
+
* tables.
|
|
160
|
+
*
|
|
161
|
+
* ### Idempotency
|
|
162
|
+
*
|
|
163
|
+
* All statements use `CREATE TABLE IF NOT EXISTS` / `CREATE INDEX IF NOT
|
|
164
|
+
* EXISTS` so the primitive is safe to call multiple times against the
|
|
165
|
+
* same DB. Both call sites (`initSchema` and
|
|
166
|
+
* `migrateEntityTables`) still guard on their own sentinels,
|
|
167
|
+
* but the function itself no longer depends on the sentinel being
|
|
168
|
+
* checked first — this closes the partial-corruption gap where, say,
|
|
169
|
+
* `content_items` exists but `page_meta` was dropped by an external
|
|
170
|
+
* repair pass.
|
|
171
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
172
|
+
*/
|
|
173
|
+
export declare function createEntityTables(instance: Knex): Promise<void>;
|