@nitpicker/crawler 0.14.0 → 0.16.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/lib/archive/archive.d.ts +136 -10
- package/lib/archive/archive.js +147 -9
- package/lib/archive/body-hash/compute-body-hash.d.ts +22 -0
- package/lib/archive/body-hash/compute-body-hash.js +31 -0
- package/lib/archive/body-hash/extract-body.d.ts +18 -0
- package/lib/archive/body-hash/extract-body.js +29 -0
- package/lib/archive/body-hash/mask-dynamic-ids.d.ts +33 -0
- package/lib/archive/body-hash/mask-dynamic-ids.js +44 -0
- package/lib/archive/body-hash/normalize-url-like-strings.d.ts +16 -0
- package/lib/archive/body-hash/normalize-url-like-strings.js +19 -0
- package/lib/archive/cache/clear-archive-cache-entry.d.ts +19 -0
- package/lib/archive/cache/clear-archive-cache-entry.js +25 -0
- package/lib/archive/cache/clear-archive-cache-root.d.ts +26 -0
- package/lib/archive/cache/clear-archive-cache-root.js +32 -0
- package/lib/archive/cache/list-archive-cache-entries.d.ts +23 -0
- package/lib/archive/cache/list-archive-cache-entries.js +125 -0
- package/lib/archive/cache/path-exists.d.ts +9 -0
- package/lib/archive/cache/path-exists.js +18 -0
- package/lib/archive/cache/types.d.ts +33 -0
- package/lib/archive/cache/types.js +1 -0
- package/lib/archive/create-adjunct-tables.d.ts +14 -0
- package/lib/archive/create-adjunct-tables.js +169 -0
- package/lib/archive/create-entity-tables.js +21 -1
- package/lib/archive/database.d.ts +67 -2
- package/lib/archive/database.js +92 -3
- package/lib/archive/db-ops/_shared/clear-write-ref-caches.js +1 -0
- package/lib/archive/db-ops/_shared/compress-payload.d.ts +26 -0
- package/lib/archive/db-ops/_shared/compress-payload.js +30 -0
- package/lib/archive/db-ops/_shared/create-write-ref-caches.js +1 -0
- package/lib/archive/db-ops/_shared/types.d.ts +2 -0
- package/lib/archive/db-ops/_shared/upsert-json-ref.js +3 -3
- package/lib/archive/db-ops/analysis/replace-page-templates.d.ts +12 -3
- package/lib/archive/db-ops/analysis/replace-page-templates.js +35 -3
- package/lib/archive/db-ops/analysis/types.d.ts +61 -0
- package/lib/archive/db-ops/analysis/types.js +1 -0
- package/lib/archive/db-ops/console-logs/compute-console-log-hash.d.ts +19 -0
- package/lib/archive/db-ops/console-logs/compute-console-log-hash.js +30 -0
- package/lib/archive/db-ops/console-logs/replace-console-logs.d.ts +34 -0
- package/lib/archive/db-ops/console-logs/replace-console-logs.js +123 -0
- package/lib/archive/db-ops/console-logs/stringify-console-log-args.d.ts +16 -0
- package/lib/archive/db-ops/console-logs/stringify-console-log-args.js +26 -0
- package/lib/archive/db-ops/console-logs/types.d.ts +38 -0
- package/lib/archive/db-ops/console-logs/types.js +1 -0
- package/lib/archive/db-ops/console-logs/upsert-console-log-item.d.ts +29 -0
- package/lib/archive/db-ops/console-logs/upsert-console-log-item.js +52 -0
- package/lib/archive/db-ops/dedupe-cap/accumulate-dedupe-cap-rejected-count.d.ts +18 -0
- package/lib/archive/db-ops/dedupe-cap/accumulate-dedupe-cap-rejected-count.js +23 -0
- package/lib/archive/db-ops/dedupe-cap/finalize-dedupe-cap-event.d.ts +12 -0
- package/lib/archive/db-ops/dedupe-cap/finalize-dedupe-cap-event.js +15 -0
- package/lib/archive/db-ops/dedupe-cap/insert-dedupe-cap-event.d.ts +14 -0
- package/lib/archive/db-ops/dedupe-cap/insert-dedupe-cap-event.js +30 -0
- package/lib/archive/db-ops/dedupe-cap/list-dedupe-cap-shape-keys.d.ts +21 -0
- package/lib/archive/db-ops/dedupe-cap/list-dedupe-cap-shape-keys.js +27 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.d.ts +11 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.js +21 -4
- package/lib/archive/db-ops/inventory/record-inventory-run.js +1 -0
- package/lib/archive/db-ops/lifecycle/init.d.ts +11 -2
- package/lib/archive/db-ops/lifecycle/init.js +21 -2
- package/lib/archive/db-ops/outages/close-network-outage.d.ts +12 -0
- package/lib/archive/db-ops/outages/close-network-outage.js +15 -0
- package/lib/archive/db-ops/outages/close-stale-open-network-outages.d.ts +26 -0
- package/lib/archive/db-ops/outages/close-stale-open-network-outages.js +42 -0
- package/lib/archive/db-ops/outages/compute-outage-clamp-timestamp.d.ts +26 -0
- package/lib/archive/db-ops/outages/compute-outage-clamp-timestamp.js +31 -0
- package/lib/archive/db-ops/outages/insert-network-outage.d.ts +14 -0
- package/lib/archive/db-ops/outages/insert-network-outage.js +29 -0
- package/lib/archive/db-ops/outages/list-network-outages.d.ts +28 -0
- package/lib/archive/db-ops/outages/list-network-outages.js +42 -0
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.d.ts +13 -0
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.js +35 -7
- package/lib/archive/db-ops/pages/write/update-page.js +12 -0
- package/lib/archive/db-ops/pages/write/write-page-html-blob.js +6 -6
- package/lib/archive/filesystem/output-binary.d.ts +12 -0
- package/lib/archive/filesystem/output-binary.js +17 -0
- package/lib/archive/get-failed-page-messages.d.ts +20 -8
- package/lib/archive/get-failed-page-messages.js +29 -15
- package/lib/archive/migrate-content-items-alias-of-id.d.ts +47 -0
- package/lib/archive/migrate-content-items-alias-of-id.js +58 -0
- package/lib/archive/migrate-inventory-runs-invalid-skipped.d.ts +11 -0
- package/lib/archive/migrate-inventory-runs-invalid-skipped.js +24 -0
- package/lib/archive/migrate-page-meta-body-hash.d.ts +39 -0
- package/lib/archive/migrate-page-meta-body-hash.js +52 -0
- package/lib/archive/migrate-page-meta-console-error-count.d.ts +22 -0
- package/lib/archive/migrate-page-meta-console-error-count.js +34 -0
- package/lib/archive/page.d.ts +1 -1
- package/lib/archive/types.d.ts +60 -2
- package/lib/archive/url-alias/compute-tier-a-alias-key.d.ts +31 -0
- package/lib/archive/url-alias/compute-tier-a-alias-key.js +36 -0
- package/lib/archive/url-alias/compute-tier-b-alias-key.d.ts +19 -0
- package/lib/archive/url-alias/compute-tier-b-alias-key.js +30 -0
- package/lib/archive/url-alias/format-alias-key.d.ts +13 -0
- package/lib/archive/url-alias/format-alias-key.js +14 -0
- package/lib/archive/url-alias/parse-alias-key-parts.d.ts +15 -0
- package/lib/archive/url-alias/parse-alias-key-parts.js +40 -0
- package/lib/archive/url-alias/types.d.ts +7 -0
- package/lib/archive/url-alias/types.js +1 -0
- package/lib/classify-error-kind.d.ts +1 -0
- package/lib/classify-error-kind.js +14 -0
- package/lib/crawler/assert-chrome-installed.d.ts +24 -0
- package/lib/crawler/assert-chrome-installed.js +43 -0
- package/lib/crawler/choose-probe-host.d.ts +24 -0
- package/lib/crawler/choose-probe-host.js +38 -0
- package/lib/crawler/clear-dns-burned-host-cache.js +2 -0
- package/lib/crawler/crawler.d.ts +12 -0
- package/lib/crawler/crawler.js +496 -29
- package/lib/crawler/decode-auth-credential.d.ts +29 -0
- package/lib/crawler/decode-auth-credential.js +39 -0
- package/lib/crawler/dedupe/compute-meta-signature.d.ts +30 -0
- package/lib/crawler/dedupe/compute-meta-signature.js +0 -0
- package/lib/crawler/dedupe/compute-shape-key.d.ts +37 -0
- package/lib/crawler/dedupe/compute-shape-key.js +56 -0
- package/lib/crawler/dedupe/dedupe-cap-tracker.d.ts +84 -0
- package/lib/crawler/dedupe/dedupe-cap-tracker.js +185 -0
- package/lib/crawler/dedupe/is-predicted-content-duplicate.d.ts +24 -0
- package/lib/crawler/dedupe/is-predicted-content-duplicate.js +26 -0
- package/lib/crawler/dedupe/is-shape-capped.d.ts +10 -0
- package/lib/crawler/dedupe/is-shape-capped.js +12 -0
- package/lib/crawler/dedupe/resolve-og-url-mismatch.d.ts +31 -0
- package/lib/crawler/dedupe/resolve-og-url-mismatch.js +40 -0
- package/lib/crawler/dedupe/types.d.ts +42 -0
- package/lib/crawler/dedupe/types.js +1 -0
- package/lib/crawler/dns-burned-host-burn-timestamps.d.ts +17 -0
- package/lib/crawler/dns-burned-host-burn-timestamps.js +17 -0
- package/lib/crawler/evict-network-classified-destination-cache-entries.d.ts +26 -0
- package/lib/crawler/evict-network-classified-destination-cache-entries.js +34 -0
- package/lib/crawler/evict-outage-tainted-dns-burns.d.ts +23 -0
- package/lib/crawler/evict-outage-tainted-dns-burns.js +26 -0
- package/lib/crawler/fetch-destination.js +14 -2
- package/lib/crawler/generate-predicted-urls.d.ts +12 -0
- package/lib/crawler/generate-predicted-urls.js +33 -2
- package/lib/crawler/is-puppeteer-fallback-candidate.js +3 -0
- package/lib/crawler/network-gate.d.ts +49 -0
- package/lib/crawler/network-gate.js +78 -0
- package/lib/crawler/network-outage-detector.d.ts +51 -0
- package/lib/crawler/network-outage-detector.js +81 -0
- package/lib/crawler/network-outage-summary-counter.d.ts +21 -0
- package/lib/crawler/network-outage-summary-counter.js +18 -0
- package/lib/crawler/probe-network.d.ts +26 -0
- package/lib/crawler/probe-network.js +21 -0
- package/lib/crawler/types.d.ts +185 -1
- package/lib/crawler-orchestrator.d.ts +74 -18
- package/lib/crawler-orchestrator.js +267 -27
- package/lib/crawler.d.ts +22 -0
- package/lib/crawler.js +18 -0
- package/lib/is-within-outage-window.d.ts +49 -0
- package/lib/is-within-outage-window.js +33 -0
- package/lib/network-related-error-kinds.d.ts +23 -0
- package/lib/network-related-error-kinds.js +28 -0
- package/lib/permanent-error-kinds.d.ts +9 -4
- package/lib/permanent-error-kinds.js +10 -4
- package/lib/types.d.ts +11 -2
- package/lib/utils/array/each-splitted.d.ts +1 -1
- package/lib/utils/compute-file-sha256.d.ts +17 -17
- package/lib/utils/compute-file-sha256.js +18 -47
- package/package.json +3 -3
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
4
|
+
/**
|
|
5
|
+
* Verifies that Puppeteer can resolve an installed Chrome/Chromium executable
|
|
6
|
+
* before a crawl starts.
|
|
7
|
+
*
|
|
8
|
+
* A crawl otherwise only discovers a missing browser deep inside the
|
|
9
|
+
* per-URL scrape loop (`Crawler#_launchBrowserAndScrape`), where it surfaces
|
|
10
|
+
* as one more scrape error among many — the CLI still prints "Crawl
|
|
11
|
+
* completed" and writes an archive, so a missing Chrome (a fatal
|
|
12
|
+
* precondition, not a per-page failure) is easy to miss. Calling this once,
|
|
13
|
+
* before any archive I/O begins, turns it into an immediate, actionable
|
|
14
|
+
* failure instead.
|
|
15
|
+
* @param executablePath - Explicit override, matching
|
|
16
|
+
* {@link CrawlerOptions.executablePath}. Pass `null` (or omit) to check
|
|
17
|
+
* Puppeteer's own pinned Chrome resolution instead.
|
|
18
|
+
* @throws {Error} When the resolved executable path does not exist on disk.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { assertChromeIsInstalled } from '@nitpicker/crawler';
|
|
22
|
+
*
|
|
23
|
+
* // Throws with install instructions before any crawl work starts.
|
|
24
|
+
* await assertChromeIsInstalled();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export async function assertChromeIsInstalled(executablePath) {
|
|
28
|
+
if (executablePath) {
|
|
29
|
+
const execPath = path.resolve(executablePath);
|
|
30
|
+
if (existsSync(execPath)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Executable path does not exist: ${execPath}`);
|
|
34
|
+
}
|
|
35
|
+
const puppeteer = await import('puppeteer');
|
|
36
|
+
const resolvedPath = await puppeteer.executablePath();
|
|
37
|
+
if (existsSync(resolvedPath)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const puppeteerVersion = pkg.dependencies.puppeteer;
|
|
41
|
+
throw new Error(`Chrome executable not found at: ${resolvedPath}\n` +
|
|
42
|
+
`Run \`npx puppeteer@${puppeteerVersion} browsers install chrome\` to install the Chrome build Puppeteer expects, then retry.`);
|
|
43
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pick the hostname a network-outage probe should target.
|
|
3
|
+
*
|
|
4
|
+
* Prefers a host that has already answered successfully during this crawl
|
|
5
|
+
* session (`Crawler.#successfulHosts` — the same "proven alive" evidence
|
|
6
|
+
* `shouldBurnHost` uses) over a root URL's hostname, and never falls back to
|
|
7
|
+
* a hardcoded external address (e.g. `1.1.1.1`): the probe should depend
|
|
8
|
+
* only on infrastructure the crawl is already touching. `ReadonlySet`
|
|
9
|
+
* iteration order in JS is insertion order, so this deterministically picks
|
|
10
|
+
* the first host to have succeeded this session.
|
|
11
|
+
* @param successfulHosts - Hostnames observed to respond in this session.
|
|
12
|
+
* @param roots - The crawl's configured root URLs (`CrawlerOptions.roots`),
|
|
13
|
+
* used as a fallback before any host has succeeded yet.
|
|
14
|
+
* @returns A probe target hostname, or `null` if neither source yields one
|
|
15
|
+
* (e.g. a fresh session with a malformed/empty roots list and no
|
|
16
|
+
* successes yet — the caller should treat this as "cannot probe").
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* chooseProbeHost(new Set(['a.example']), ['https://b.example/']); // 'a.example'
|
|
20
|
+
* chooseProbeHost(new Set(), ['https://b.example/']); // 'b.example'
|
|
21
|
+
* chooseProbeHost(new Set(), []); // null
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function chooseProbeHost(successfulHosts: ReadonlySet<string>, roots: readonly string[]): string | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pick the hostname a network-outage probe should target.
|
|
3
|
+
*
|
|
4
|
+
* Prefers a host that has already answered successfully during this crawl
|
|
5
|
+
* session (`Crawler.#successfulHosts` — the same "proven alive" evidence
|
|
6
|
+
* `shouldBurnHost` uses) over a root URL's hostname, and never falls back to
|
|
7
|
+
* a hardcoded external address (e.g. `1.1.1.1`): the probe should depend
|
|
8
|
+
* only on infrastructure the crawl is already touching. `ReadonlySet`
|
|
9
|
+
* iteration order in JS is insertion order, so this deterministically picks
|
|
10
|
+
* the first host to have succeeded this session.
|
|
11
|
+
* @param successfulHosts - Hostnames observed to respond in this session.
|
|
12
|
+
* @param roots - The crawl's configured root URLs (`CrawlerOptions.roots`),
|
|
13
|
+
* used as a fallback before any host has succeeded yet.
|
|
14
|
+
* @returns A probe target hostname, or `null` if neither source yields one
|
|
15
|
+
* (e.g. a fresh session with a malformed/empty roots list and no
|
|
16
|
+
* successes yet — the caller should treat this as "cannot probe").
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* chooseProbeHost(new Set(['a.example']), ['https://b.example/']); // 'a.example'
|
|
20
|
+
* chooseProbeHost(new Set(), ['https://b.example/']); // 'b.example'
|
|
21
|
+
* chooseProbeHost(new Set(), []); // null
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function chooseProbeHost(successfulHosts, roots) {
|
|
25
|
+
const [firstSuccessfulHost] = successfulHosts;
|
|
26
|
+
if (firstSuccessfulHost !== undefined) {
|
|
27
|
+
return firstSuccessfulHost;
|
|
28
|
+
}
|
|
29
|
+
for (const root of roots) {
|
|
30
|
+
try {
|
|
31
|
+
return new URL(root).hostname;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dnsBurnedHostBurnTimestamps } from './dns-burned-host-burn-timestamps.js';
|
|
1
2
|
import { dnsBurnedHostCache } from './dns-burned-host-cache.js';
|
|
2
3
|
import { dnsBurnedHostShortCircuitCounter } from './dns-burned-host-short-circuit-counter.js';
|
|
3
4
|
/**
|
|
@@ -8,4 +9,5 @@ import { dnsBurnedHostShortCircuitCounter } from './dns-burned-host-short-circui
|
|
|
8
9
|
export function clearDnsBurnedHostCache() {
|
|
9
10
|
dnsBurnedHostCache.clear();
|
|
10
11
|
dnsBurnedHostShortCircuitCounter.count = 0;
|
|
12
|
+
dnsBurnedHostBurnTimestamps.clear();
|
|
11
13
|
}
|
package/lib/crawler/crawler.d.ts
CHANGED
|
@@ -37,6 +37,18 @@ export default class Crawler extends EventEmitter<CrawlerEventTypes> {
|
|
|
37
37
|
* {@link #runDeal}.
|
|
38
38
|
*/
|
|
39
39
|
abort(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Per-shape count of anchors the dedupe-cap enqueue gates rejected after
|
|
42
|
+
* that shape capped (opt-in `--dedupe-cap`). Read by
|
|
43
|
+
* `CrawlerOrchestrator` at `crawlEnd` to finalize each
|
|
44
|
+
* `dedupe_cap_events.rejected_count` exactly once — rejections are
|
|
45
|
+
* accumulated in memory rather than written to the archive per-rejection
|
|
46
|
+
* to avoid write amplification (a capped trap can generate an unbounded
|
|
47
|
+
* number of rejected anchors).
|
|
48
|
+
* @returns A snapshot of the per-shape rejection counts. Empty when
|
|
49
|
+
* `--dedupe-cap` was not enabled or no shape has capped yet.
|
|
50
|
+
*/
|
|
51
|
+
getDedupeCapRejections(): ReadonlyMap<string, number>;
|
|
40
52
|
/**
|
|
41
53
|
* Retrieve the list of Chromium process IDs that are still running.
|
|
42
54
|
*
|