@nitpicker/crawler 0.9.0 → 0.12.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-accessor.d.ts +87 -14
- package/lib/archive/archive-accessor.js +162 -36
- package/lib/archive/archive.d.ts +262 -24
- package/lib/archive/archive.js +397 -86
- 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/database.d.ts +411 -26
- package/lib/archive/database.js +1881 -540
- package/lib/archive/derive-lineage-from-parent.d.ts +37 -0
- package/lib/archive/derive-lineage-from-parent.js +42 -0
- package/lib/archive/filesystem/peek-tar-top-dir.d.ts +28 -0
- package/lib/archive/filesystem/peek-tar-top-dir.js +65 -0
- package/lib/archive/get-failed-page-messages.d.ts +43 -0
- package/lib/archive/get-failed-page-messages.js +131 -0
- package/lib/archive/init-schema.d.ts +53 -2
- package/lib/archive/init-schema.js +399 -15
- package/lib/archive/is-inventory-source.d.ts +21 -0
- package/lib/archive/is-inventory-source.js +22 -0
- package/lib/archive/meta/assert-compatible-version.d.ts +39 -0
- package/lib/archive/meta/assert-compatible-version.js +72 -0
- package/lib/archive/meta/classify-jsonld-type.d.ts +23 -0
- package/lib/archive/meta/classify-jsonld-type.js +43 -0
- package/lib/archive/meta/compare-semver.d.ts +23 -0
- package/lib/archive/meta/compare-semver.js +51 -0
- package/lib/archive/meta/compute-page-denormalized.d.ts +21 -0
- package/lib/archive/meta/compute-page-denormalized.js +35 -0
- package/lib/archive/meta/derive-flat-from-meta.d.ts +35 -0
- package/lib/archive/meta/derive-flat-from-meta.js +158 -0
- package/lib/archive/meta/derive-meta-extras.d.ts +20 -0
- package/lib/archive/meta/derive-meta-extras.js +23 -0
- package/lib/archive/meta/extract-tags-for-archive.d.ts +18 -0
- package/lib/archive/meta/extract-tags-for-archive.js +36 -0
- package/lib/archive/meta/summarize-jsonld.d.ts +17 -0
- package/lib/archive/meta/summarize-jsonld.js +29 -0
- package/lib/archive/meta/summarize-tags.d.ts +16 -0
- package/lib/archive/meta/summarize-tags.js +33 -0
- package/lib/archive/meta/types.d.ts +207 -0
- package/lib/archive/meta/types.js +33 -0
- package/lib/archive/migrate-crawl-errors.d.ts +20 -0
- package/lib/archive/migrate-crawl-errors.js +38 -0
- package/lib/archive/migrate-html-blob-tables.d.ts +24 -0
- package/lib/archive/migrate-html-blob-tables.js +53 -0
- package/lib/archive/migrate-inventory-runs.d.ts +29 -0
- package/lib/archive/migrate-inventory-runs.js +52 -0
- package/lib/archive/migrate-page-errors.d.ts +16 -0
- package/lib/archive/migrate-page-errors.js +35 -0
- package/lib/archive/migrate-pages-resources-source.d.ts +16 -0
- package/lib/archive/migrate-pages-resources-source.js +46 -0
- package/lib/archive/page.d.ts +187 -49
- package/lib/archive/page.js +258 -63
- package/lib/archive/peek-archive-lock.d.ts +40 -0
- package/lib/archive/peek-archive-lock.js +62 -0
- package/lib/archive/resolve-redirect-chain.d.ts +33 -0
- package/lib/archive/resolve-redirect-chain.js +27 -0
- package/lib/archive/types.d.ts +168 -26
- 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/clear-dns-burned-host-cache.d.ts +6 -0
- package/lib/crawler/clear-dns-burned-host-cache.js +11 -0
- package/lib/crawler/close-browser-safely.d.ts +64 -0
- package/lib/crawler/close-browser-safely.js +73 -0
- package/lib/crawler/crawler.d.ts +7 -2
- package/lib/crawler/crawler.js +919 -113
- package/lib/crawler/create-change-phase-handler.d.ts +54 -0
- package/lib/crawler/create-change-phase-handler.js +44 -0
- 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-page-source.d.ts +23 -0
- package/lib/crawler/derive-page-source.js +28 -0
- package/lib/crawler/derive-resource-source.d.ts +33 -0
- package/lib/crawler/derive-resource-source.js +37 -0
- 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/drain-phase-errors.d.ts +48 -0
- package/lib/crawler/drain-phase-errors.js +35 -0
- package/lib/crawler/fetch-destination.d.ts +12 -4
- package/lib/crawler/fetch-destination.js +132 -18
- package/lib/crawler/format-crawl-progress.d.ts +12 -3
- package/lib/crawler/format-crawl-progress.js +14 -6
- package/lib/crawler/handle-browser-close.d.ts +29 -0
- package/lib/crawler/handle-browser-close.js +28 -0
- package/lib/crawler/is-html-content-type.d.ts +17 -0
- package/lib/crawler/is-html-content-type.js +19 -0
- 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-likely-html-url.d.ts +22 -0
- package/lib/crawler/is-likely-html-url.js +65 -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/kill-process-tree.d.ts +94 -0
- package/lib/crawler/kill-process-tree.js +178 -0
- package/lib/crawler/link-list.d.ts +21 -1
- package/lib/crawler/link-list.js +25 -4
- package/lib/crawler/link-to-page-data.d.ts +13 -5
- package/lib/crawler/link-to-page-data.js +26 -5
- package/lib/crawler/log-undrained-phase-errors.d.ts +37 -0
- package/lib/crawler/log-undrained-phase-errors.js +34 -0
- package/lib/crawler/normalize-content-type.d.ts +14 -0
- package/lib/crawler/normalize-content-type.js +20 -0
- package/lib/crawler/partition-urls-by-html.d.ts +16 -0
- package/lib/crawler/partition-urls-by-html.js +23 -0
- 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/redirect-dest-key.d.ts +19 -0
- package/lib/crawler/redirect-dest-key.js +27 -0
- package/lib/crawler/resource-to-page-data.d.ts +28 -0
- package/lib/crawler/resource-to-page-data.js +59 -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 +229 -1
- package/lib/crawler-orchestrator.d.ts +105 -3
- package/lib/crawler-orchestrator.js +620 -20
- package/lib/crawler.d.ts +8 -2
- package/lib/crawler.js +6 -1
- package/lib/permanent-error-kinds.d.ts +43 -0
- package/lib/permanent-error-kinds.js +48 -0
- package/lib/resource-row-to-lookup-result.d.ts +13 -0
- package/lib/resource-row-to-lookup-result.js +20 -0
- package/lib/types.d.ts +95 -1
- package/lib/utils/compute-file-sha256.d.ts +23 -0
- package/lib/utils/compute-file-sha256.js +55 -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/lib/utils/object/parse-response-headers.d.ts +12 -0
- package/lib/utils/object/parse-response-headers.js +26 -0
- package/package.json +11 -11
- package/lib/utils/error/error-emitter.d.ts +0 -18
- package/lib/utils/error/error-emitter.js +0 -29
package/lib/crawler.d.ts
CHANGED
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
export * from './utils/types/types.js';
|
|
8
8
|
export { eachSplitted } from './utils/array/each-splitted.js';
|
|
9
9
|
export { DOMEvaluationError } from './utils/error/dom-evaluation-error.js';
|
|
10
|
-
export { ErrorEmitter } from './utils/error/error-emitter.js';
|
|
11
|
-
export type { ErrorEvent } from './utils/error/error-emitter.js';
|
|
12
10
|
export * from './utils/object/clean-object.js';
|
|
13
11
|
export { globalLog as log } from './utils/debug.js';
|
|
14
12
|
export { ArchiveAccessor } from './archive/archive-accessor.js';
|
|
@@ -17,6 +15,14 @@ export { default as Page } from './archive/page.js';
|
|
|
17
15
|
export { default as ArchiveResource } from './archive/resource.js';
|
|
18
16
|
export * from './archive/types.js';
|
|
19
17
|
export { default as Archive } from './archive/archive.js';
|
|
18
|
+
export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
|
|
19
|
+
export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
20
|
+
export type { ArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
21
|
+
export type { FlatPageMetaColumns, JsonLdRow, JsonLdRowForInsert, TagRow, TagRowForInsert, JsonLdSummary, TagsSummary, TagInventoryEntry, PageDenormalizedColumns, } from './archive/meta/types.js';
|
|
22
|
+
export { IncompatibleArchiveError } from './archive/meta/types.js';
|
|
23
|
+
export { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
|
|
20
24
|
export { DEFAULT_EXCLUDED_EXTERNAL_URLS, CrawlerOrchestrator, } from './crawler-orchestrator.js';
|
|
21
25
|
export * from './types.js';
|
|
22
26
|
export * from './crawler/types.js';
|
|
27
|
+
export { classifyErrorKind } from './classify-error-kind.js';
|
|
28
|
+
export { computeFileSha256 } from './utils/compute-file-sha256.js';
|
package/lib/crawler.js
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
export * from './utils/types/types.js';
|
|
9
9
|
export { eachSplitted } from './utils/array/each-splitted.js';
|
|
10
10
|
export { DOMEvaluationError } from './utils/error/dom-evaluation-error.js';
|
|
11
|
-
export { ErrorEmitter } from './utils/error/error-emitter.js';
|
|
12
11
|
export * from './utils/object/clean-object.js';
|
|
13
12
|
export { globalLog as log } from './utils/debug.js';
|
|
14
13
|
// Archive
|
|
@@ -17,7 +16,13 @@ export { default as Page } from './archive/page.js';
|
|
|
17
16
|
export { default as ArchiveResource } from './archive/resource.js';
|
|
18
17
|
export * from './archive/types.js';
|
|
19
18
|
export { default as Archive } from './archive/archive.js';
|
|
19
|
+
export { isArchiveCacheDisabled } from './archive/cache/is-archive-cache-disabled.js';
|
|
20
|
+
export { peekArchiveLockHolder } from './archive/peek-archive-lock.js';
|
|
21
|
+
export { IncompatibleArchiveError } from './archive/meta/types.js';
|
|
22
|
+
export { REQUIRED_FORMAT_VERSION } from './archive/meta/assert-compatible-version.js';
|
|
20
23
|
// Core
|
|
21
24
|
export { DEFAULT_EXCLUDED_EXTERNAL_URLS, CrawlerOrchestrator, } from './crawler-orchestrator.js';
|
|
22
25
|
export * from './types.js';
|
|
23
26
|
export * from './crawler/types.js';
|
|
27
|
+
export { classifyErrorKind } from './classify-error-kind.js';
|
|
28
|
+
export { computeFileSha256 } from './utils/compute-file-sha256.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ErrorKind } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error kinds whose failure mode is **persistent** — re-fetching the same URL
|
|
4
|
+
* (without changing the network, the certificate, the destination host, or the
|
|
5
|
+
* browser's block-list state) will almost certainly produce the same failure.
|
|
6
|
+
*
|
|
7
|
+
* Used by {@link resetFailedPages} to exclude pages whose latest recorded error
|
|
8
|
+
* falls in this set, so `--retry-failed` actually converges: without the
|
|
9
|
+
* exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
|
|
10
|
+
* `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
|
|
11
|
+
* iteration, the crawler would re-attempt them, they would fail again the
|
|
12
|
+
* same way, and the retry-target count would stay constant forever.
|
|
13
|
+
*
|
|
14
|
+
* Why these five and not others:
|
|
15
|
+
* - **dns** — `ENOTFOUND` / `ERR_NAME_NOT_RESOLVED` are authoritative DNS
|
|
16
|
+
* answers; the host is gone (or never existed). EAI_AGAIN is split out as
|
|
17
|
+
* `dns-transient` precisely so it is NOT in this set.
|
|
18
|
+
* - **tls** — cert expiry / SAN mismatch / SSL protocol errors require the
|
|
19
|
+
* server operator to fix something; retrying within the same archive run
|
|
20
|
+
* cannot succeed.
|
|
21
|
+
* - **client-blocked** — Chromium's `ERR_BLOCKED_*` family is a deliberate
|
|
22
|
+
* browser-side rejection; the request will be blocked identically every
|
|
23
|
+
* time the browser sees the same URL.
|
|
24
|
+
* - **parse-error** — the server's HTTP response is malformed (`Expected
|
|
25
|
+
* HTTP/, RTSP/ or ICE/`, `Unexpected end of stream`). Retrying the same
|
|
26
|
+
* request hits the same parser failure.
|
|
27
|
+
* - **connection-refused** — `ECONNREFUSED` is an authoritative TCP RST from
|
|
28
|
+
* the listener; either no process is listening on the port or its accept
|
|
29
|
+
* queue rejected the connection. Either way the answer is final until the
|
|
30
|
+
* server operator intervenes.
|
|
31
|
+
*
|
|
32
|
+
* Notably absent (intentionally retryable):
|
|
33
|
+
* - `connection-reset` / `connection-timeout` — could be middlebox or
|
|
34
|
+
* transient overload
|
|
35
|
+
* - `dns-transient` (EAI_AGAIN / EREFUSED) — local resolver hiccup
|
|
36
|
+
* - `local-network` — operator-side connectivity loss
|
|
37
|
+
* - `timeout` — slow but reachable server (HEAD-timeout escalation gives
|
|
38
|
+
* these a real chance)
|
|
39
|
+
* - `protocol` — puppeteer lifecycle race, often recovers on retry
|
|
40
|
+
* - `unknown` — by definition we don't know it's permanent, so we keep
|
|
41
|
+
* retrying (errs on the side of investigating)
|
|
42
|
+
*/
|
|
43
|
+
export declare const PERMANENT_ERROR_KINDS: ReadonlySet<ErrorKind>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error kinds whose failure mode is **persistent** — re-fetching the same URL
|
|
3
|
+
* (without changing the network, the certificate, the destination host, or the
|
|
4
|
+
* browser's block-list state) will almost certainly produce the same failure.
|
|
5
|
+
*
|
|
6
|
+
* Used by {@link resetFailedPages} to exclude pages whose latest recorded error
|
|
7
|
+
* falls in this set, so `--retry-failed` actually converges: without the
|
|
8
|
+
* exclusion, NXDOMAIN / TLS mismatch / `ERR_BLOCKED_BY_CLIENT` /
|
|
9
|
+
* `ECONNREFUSED` / HTTP parse-error pages would be reset to pending on every
|
|
10
|
+
* iteration, the crawler would re-attempt them, they would fail again the
|
|
11
|
+
* same way, and the retry-target count would stay constant forever.
|
|
12
|
+
*
|
|
13
|
+
* Why these five and not others:
|
|
14
|
+
* - **dns** — `ENOTFOUND` / `ERR_NAME_NOT_RESOLVED` are authoritative DNS
|
|
15
|
+
* answers; the host is gone (or never existed). EAI_AGAIN is split out as
|
|
16
|
+
* `dns-transient` precisely so it is NOT in this set.
|
|
17
|
+
* - **tls** — cert expiry / SAN mismatch / SSL protocol errors require the
|
|
18
|
+
* server operator to fix something; retrying within the same archive run
|
|
19
|
+
* cannot succeed.
|
|
20
|
+
* - **client-blocked** — Chromium's `ERR_BLOCKED_*` family is a deliberate
|
|
21
|
+
* browser-side rejection; the request will be blocked identically every
|
|
22
|
+
* time the browser sees the same URL.
|
|
23
|
+
* - **parse-error** — the server's HTTP response is malformed (`Expected
|
|
24
|
+
* HTTP/, RTSP/ or ICE/`, `Unexpected end of stream`). Retrying the same
|
|
25
|
+
* request hits the same parser failure.
|
|
26
|
+
* - **connection-refused** — `ECONNREFUSED` is an authoritative TCP RST from
|
|
27
|
+
* the listener; either no process is listening on the port or its accept
|
|
28
|
+
* queue rejected the connection. Either way the answer is final until the
|
|
29
|
+
* server operator intervenes.
|
|
30
|
+
*
|
|
31
|
+
* Notably absent (intentionally retryable):
|
|
32
|
+
* - `connection-reset` / `connection-timeout` — could be middlebox or
|
|
33
|
+
* transient overload
|
|
34
|
+
* - `dns-transient` (EAI_AGAIN / EREFUSED) — local resolver hiccup
|
|
35
|
+
* - `local-network` — operator-side connectivity loss
|
|
36
|
+
* - `timeout` — slow but reachable server (HEAD-timeout escalation gives
|
|
37
|
+
* these a real chance)
|
|
38
|
+
* - `protocol` — puppeteer lifecycle race, often recovers on retry
|
|
39
|
+
* - `unknown` — by definition we don't know it's permanent, so we keep
|
|
40
|
+
* retrying (errs on the side of investigating)
|
|
41
|
+
*/
|
|
42
|
+
export const PERMANENT_ERROR_KINDS = new Set([
|
|
43
|
+
'dns',
|
|
44
|
+
'tls',
|
|
45
|
+
'client-blocked',
|
|
46
|
+
'parse-error',
|
|
47
|
+
'connection-refused',
|
|
48
|
+
]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DB_Resource } from './archive/types.js';
|
|
2
|
+
import type { ResourceLookupResult } from './crawler/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert a raw `resources` table row into the minimal lookup result the
|
|
5
|
+
* crawler needs to reuse captured sub-resource data.
|
|
6
|
+
*
|
|
7
|
+
* Header parsing degrades to `null` on malformed JSON instead of throwing
|
|
8
|
+
* because a missing header set only loses fidelity — the reuse path stays
|
|
9
|
+
* valid.
|
|
10
|
+
* @param row - The raw database row.
|
|
11
|
+
* @returns The lookup result consumed by the crawler's resource-reuse hook.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resourceRowToLookupResult(row: DB_Resource): ResourceLookupResult;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseResponseHeaders } from './utils/object/parse-response-headers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a raw `resources` table row into the minimal lookup result the
|
|
4
|
+
* crawler needs to reuse captured sub-resource data.
|
|
5
|
+
*
|
|
6
|
+
* Header parsing degrades to `null` on malformed JSON instead of throwing
|
|
7
|
+
* because a missing header set only loses fidelity — the reuse path stays
|
|
8
|
+
* valid.
|
|
9
|
+
* @param row - The raw database row.
|
|
10
|
+
* @returns The lookup result consumed by the crawler's resource-reuse hook.
|
|
11
|
+
*/
|
|
12
|
+
export function resourceRowToLookupResult(row) {
|
|
13
|
+
return {
|
|
14
|
+
status: row.status,
|
|
15
|
+
statusText: row.statusText,
|
|
16
|
+
contentType: row.contentType,
|
|
17
|
+
contentLength: row.contentLength,
|
|
18
|
+
responseHeaders: parseResponseHeaders(row.responseHeaders),
|
|
19
|
+
};
|
|
20
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,88 @@
|
|
|
1
|
-
import type { CrawlerError } from './utils/types/types.js';
|
|
1
|
+
import type { CrawlerError, PageData } from './utils/types/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Aggregate counts captured during a `--inventory` invocation, forwarded to
|
|
4
|
+
* `#writeInventoryRunRow` so the audit log row is consistent between the
|
|
5
|
+
* HTML-seed branch and the non-HTML-only branch of
|
|
6
|
+
* {@link CrawlerOrchestrator.inventory}.
|
|
7
|
+
*
|
|
8
|
+
* Spelled out here (not inlined at the call site) so a new field added to
|
|
9
|
+
* the audit row has a single edit point and so each field's semantics are
|
|
10
|
+
* documented per-property rather than scattered across the two emit sites.
|
|
11
|
+
*/
|
|
12
|
+
export interface InventoryRunAggregates {
|
|
13
|
+
/** Total non-empty lines in the input list (= `inventoryUrls.length` before any filtering). Stored verbatim as `inventory_runs.total_lines`. */
|
|
14
|
+
inventoryUrlsCount: number;
|
|
15
|
+
/** Number of novel URLs classified as HTML and queued for render. Stored as `new_pages` (excludes anchor-discovered descendants — those add later via the crawler graph and are NOT counted here). */
|
|
16
|
+
htmlSeedsCount: number;
|
|
17
|
+
/** Number of novel URLs classified as non-HTML and written directly into `resources`. Stored as `new_resources`. */
|
|
18
|
+
nonHtmlCount: number;
|
|
19
|
+
/** URLs dropped because they fell outside the archived scope. Stored as `scope_skipped`. */
|
|
20
|
+
outOfScope: number;
|
|
21
|
+
/**
|
|
22
|
+
* SHA-256 hex digest of the source `.txt`, **pre-computed by the caller**
|
|
23
|
+
* (typically the CLI's `inventoryCrawl`). Stored verbatim as
|
|
24
|
+
* `inventory_runs.source_file_sha256`.
|
|
25
|
+
*
|
|
26
|
+
* Pre-computation lifts the absolute path off the orchestrator
|
|
27
|
+
* boundary entirely — the path is privacy-sensitive (leaks
|
|
28
|
+
* user-home / OS structure when archives are shared), and the
|
|
29
|
+
* orchestrator has no business handling it after the audit-row
|
|
30
|
+
* column was dropped. Pass `null` for programmatic callers that
|
|
31
|
+
* built `inventoryUrls` in-memory; the audit row's
|
|
32
|
+
* `source_file_sha256` will be `NULL`.
|
|
33
|
+
*/
|
|
34
|
+
sourceFileSha256: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Coarse cause of a crawl/scrape failure.
|
|
38
|
+
*
|
|
39
|
+
* The crawler stores only the raw error message (in `crawl_errors`,
|
|
40
|
+
* `page_errors`, or `error.log`); the cause is derived on read by
|
|
41
|
+
* `classifyErrorKind`, so existing archives gain classification without a
|
|
42
|
+
* re-crawl.
|
|
43
|
+
*
|
|
44
|
+
* Owned by the crawler package because both the crawler (for DNS-burned host
|
|
45
|
+
* caching) and `@nitpicker/query` (for `getErrorKinds` / `getSummary`) need to
|
|
46
|
+
* classify error messages, and crawler cannot depend on query.
|
|
47
|
+
*
|
|
48
|
+
* ### transient vs persistent
|
|
49
|
+
*
|
|
50
|
+
* | kind | transient? | DNS-burn? | notes |
|
|
51
|
+
* | --- | --- | --- | --- |
|
|
52
|
+
* | `dns` | no | yes | NXDOMAIN; the host does not resolve at all |
|
|
53
|
+
* | `dns-transient` | **yes** | no | `EAI_AGAIN`; local resolver hiccup, retry often recovers |
|
|
54
|
+
* | `tls` | no | no | certificate issue, usually persistent until cert rotates |
|
|
55
|
+
* | `connection-refused` | mostly persistent | no | server actively rejecting on this port |
|
|
56
|
+
* | `connection-reset` | yes | no | TCP reset mid-stream, often transient |
|
|
57
|
+
* | `connection-timeout` | yes | no | TCP-level timeout (`ETIMEDOUT`); slow but reachable |
|
|
58
|
+
* | `local-network` | **yes** | no | local machine's network is unreachable / changed (WiFi, sleep, ICMP-unreachable, …) |
|
|
59
|
+
* | `parse-error` | mostly persistent | no | HTTP response could not be parsed (proxy, garbage, MITM) |
|
|
60
|
+
* | `client-blocked` | persistent (per browser) | no | Chromium-side `ERR_BLOCKED_BY_*` family — the browser actively refused the request (ad/tracker heuristics, CSP, CORP, administrator block list, …) |
|
|
61
|
+
* | `protocol` | yes | no | puppeteer protocol layer (frame detached, target closed, …) |
|
|
62
|
+
* | `timeout` | yes | no | puppeteer navigation timeout or HEAD pre-flight race timeout (`Timeout: <url>`) |
|
|
63
|
+
* | `unknown` | unknown | no | catch-all for messages no matcher recognised |
|
|
64
|
+
*
|
|
65
|
+
* Only `dns` is mark-target for the DNS-burned host cache; everything else is
|
|
66
|
+
* either too transient to burn (network glitch / browser hiccup) or too
|
|
67
|
+
* server-specific to extrapolate to "this whole host is dead."
|
|
68
|
+
*
|
|
69
|
+
* ### Derived constants that MUST be reviewed when this union changes
|
|
70
|
+
*
|
|
71
|
+
* - `PERMANENT_ERROR_KINDS` (`permanent-error-kinds.ts`) — the set of kinds
|
|
72
|
+
* excluded from `--retry-failed` so retry iterations actually converge.
|
|
73
|
+
* A new kind that is deterministically permanent (server-state, cert,
|
|
74
|
+
* browser-block, …) likely belongs here.
|
|
75
|
+
* - `PUPPETEER_FALLBACK_KINDS` (`crawler/is-puppeteer-fallback-candidate.ts`)
|
|
76
|
+
* — the set of kinds where one puppeteer attempt has a realistic chance
|
|
77
|
+
* of succeeding after HEAD+GET pre-flight exhausted retries. A new kind
|
|
78
|
+
* modelling a middlebox / WAF / slow-server quirk likely belongs here.
|
|
79
|
+
*
|
|
80
|
+
* Adding a kind without reviewing both sets risks a silent regression:
|
|
81
|
+
* `--retry-failed` re-trying a permanent failure forever (no PERMANENT
|
|
82
|
+
* entry), or a recoverable URL never reaching the puppeteer fallback (no
|
|
83
|
+
* PUPPETEER_FALLBACK entry).
|
|
84
|
+
*/
|
|
85
|
+
export type ErrorKind = 'dns' | 'dns-transient' | 'connection-refused' | 'connection-reset' | 'connection-timeout' | 'tls' | 'local-network' | 'parse-error' | 'client-blocked' | 'timeout' | 'protocol' | 'unknown';
|
|
2
86
|
/**
|
|
3
87
|
* Event map for the `CrawlerOrchestrator` class.
|
|
4
88
|
*
|
|
@@ -24,4 +108,14 @@ export interface CrawlEvent {
|
|
|
24
108
|
* Emitted when an error occurs during crawling or archiving.
|
|
25
109
|
*/
|
|
26
110
|
error: CrawlerError;
|
|
111
|
+
/**
|
|
112
|
+
* Emitted when a URL redirects to a destination already rendered during this
|
|
113
|
+
* crawl, so only the redirect edge is recorded and the destination is not
|
|
114
|
+
* re-rendered (#73). Mirrors the crawler's `redirect` event; useful for
|
|
115
|
+
* observing how much redirect-convergence work was skipped.
|
|
116
|
+
*/
|
|
117
|
+
redirect: {
|
|
118
|
+
/** HEAD-resolved page data carrying the redirect chain (source → destination). */
|
|
119
|
+
result: PageData;
|
|
120
|
+
};
|
|
27
121
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the SHA-256 digest of a file's bytes, streaming so memory stays
|
|
3
|
+
* O(1) regardless of file size.
|
|
4
|
+
*
|
|
5
|
+
* Used by {@link CrawlerOrchestrator.inventory} to fingerprint the source
|
|
6
|
+
* URL list `.txt` and store the digest on the `inventory_runs` row.
|
|
7
|
+
* Phase 3 (`--refresh`) will key dedupe on this column; Phase 1 just
|
|
8
|
+
* records it for operator audit.
|
|
9
|
+
*
|
|
10
|
+
* Returns `null` instead of throwing when the file cannot be read (e.g.
|
|
11
|
+
* vanished mid-run, permissions issue) so the inventory run's audit row
|
|
12
|
+
* can still be written with a NULL digest. Hashing failure is an audit
|
|
13
|
+
* loss, not a correctness failure — the actual ingestion has already
|
|
14
|
+
* succeeded by the time this is called.
|
|
15
|
+
* @param filePath - Absolute or relative path to the file to hash.
|
|
16
|
+
* @returns Lower-case hex digest (64 chars), or `null` if reading failed.
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const sha = await computeFileSha256('/tmp/list.txt');
|
|
20
|
+
* if (sha) console.log(sha); // 64-char hex string
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function computeFileSha256(filePath: string): Promise<string | null>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
import { crawlerLog } from '../debug.js';
|
|
4
|
+
/**
|
|
5
|
+
* Compute the SHA-256 digest of a file's bytes, streaming so memory stays
|
|
6
|
+
* O(1) regardless of file size.
|
|
7
|
+
*
|
|
8
|
+
* Used by {@link CrawlerOrchestrator.inventory} to fingerprint the source
|
|
9
|
+
* URL list `.txt` and store the digest on the `inventory_runs` row.
|
|
10
|
+
* Phase 3 (`--refresh`) will key dedupe on this column; Phase 1 just
|
|
11
|
+
* records it for operator audit.
|
|
12
|
+
*
|
|
13
|
+
* Returns `null` instead of throwing when the file cannot be read (e.g.
|
|
14
|
+
* vanished mid-run, permissions issue) so the inventory run's audit row
|
|
15
|
+
* can still be written with a NULL digest. Hashing failure is an audit
|
|
16
|
+
* loss, not a correctness failure — the actual ingestion has already
|
|
17
|
+
* succeeded by the time this is called.
|
|
18
|
+
* @param filePath - Absolute or relative path to the file to hash.
|
|
19
|
+
* @returns Lower-case hex digest (64 chars), or `null` if reading failed.
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const sha = await computeFileSha256('/tmp/list.txt');
|
|
23
|
+
* if (sha) console.log(sha); // 64-char hex string
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export async function computeFileSha256(filePath) {
|
|
27
|
+
return await new Promise((resolve) => {
|
|
28
|
+
const hash = createHash('sha256');
|
|
29
|
+
const stream = createReadStream(filePath);
|
|
30
|
+
let settled = false;
|
|
31
|
+
const settle = (value) => {
|
|
32
|
+
if (settled) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
settled = true;
|
|
36
|
+
resolve(value);
|
|
37
|
+
};
|
|
38
|
+
stream.on('data', (chunk) => hash.update(chunk));
|
|
39
|
+
stream.on('end', () => settle(hash.digest('hex')));
|
|
40
|
+
stream.on('error', (error) => {
|
|
41
|
+
// Trace the failure so operators inspecting `--inventory`
|
|
42
|
+
// audit rows with `source_file_sha256 = NULL` can recover
|
|
43
|
+
// the underlying cause via `DEBUG=Nitpicker:Crawler:*`.
|
|
44
|
+
crawlerLog('compute-file-sha256 failed for %s: %s', filePath, error.message);
|
|
45
|
+
settle(null);
|
|
46
|
+
});
|
|
47
|
+
// `'close'` is the last-resort settler. If the stream is
|
|
48
|
+
// destroyed externally between `'data'` and `'end'` (e.g. a
|
|
49
|
+
// test or signal handler), neither `'end'` nor `'error'` may
|
|
50
|
+
// fire — leaving the promise pending forever. Falling back to
|
|
51
|
+
// `null` matches the documented contract ("hashing failure
|
|
52
|
+
// yields null").
|
|
53
|
+
stream.on('close', () => settle(null));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RetryCallOptions } from '@d-zero/shared/retry';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal object shape required by {@link emitErrorAndRetry}: an emitter
|
|
4
|
+
* able to publish an `'error'` event carrying an `Error` payload. Same
|
|
5
|
+
* contract as `emitError` — see {@link ./emit-error.js} for details.
|
|
6
|
+
*/
|
|
7
|
+
interface Emitter {
|
|
8
|
+
/**
|
|
9
|
+
* Emits the `'error'` event with the given `Error` payload.
|
|
10
|
+
* @param event - Event name; always `'error'` here.
|
|
11
|
+
* @param payload - The error instance to publish.
|
|
12
|
+
* @returns Anything; the caller ignores it.
|
|
13
|
+
*/
|
|
14
|
+
emit(event: 'error', payload: Error): unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Retries `fn` per `retryOptions`, then — if retries are exhausted with a
|
|
18
|
+
* final `Error` — logs and re-emits it as an `'error'` event on `emitter`
|
|
19
|
+
* before re-throwing. `label` is forwarded into `retryCall` so its own
|
|
20
|
+
* onWait / onGiveUp / timeout messages identify the call site (previously
|
|
21
|
+
* derived automatically by the `@retry` decorator via
|
|
22
|
+
* `ClassMethodDecoratorContext.name`).
|
|
23
|
+
*
|
|
24
|
+
* Inlined try/catch rather than composing {@link emitError} with a
|
|
25
|
+
* `() => retryCall(...)` closure to keep the per-invocation closure count
|
|
26
|
+
* at 1 — this method is called on the DB write hot path (`updatePage`,
|
|
27
|
+
* `insertResource`), where wrapping decorators previously ran with zero
|
|
28
|
+
* per-call allocation.
|
|
29
|
+
* @template T - The return type of `fn`.
|
|
30
|
+
* @param emitter - The event emitter that receives the `'error'` event.
|
|
31
|
+
* @param label - Human-readable label; forwarded into `retryCall`
|
|
32
|
+
* (visible in retry timeouts / onWait / onGiveUp) and used
|
|
33
|
+
* as the debug log prefix on final failure.
|
|
34
|
+
* @param fn - The async operation to retry.
|
|
35
|
+
* @param retryOptions - Retry configuration; `label` is overwritten
|
|
36
|
+
* with the `label` argument here.
|
|
37
|
+
* @returns The resolved value of `fn`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function emitErrorAndRetry<T>(emitter: Emitter, label: string, fn: () => Promise<T>, retryOptions: RetryCallOptions): Promise<T>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { retryCall } from '@d-zero/shared/retry';
|
|
2
|
+
import { log } from '../debug.js';
|
|
3
|
+
/**
|
|
4
|
+
* Debug logger for the ErrorEmitter helper family.
|
|
5
|
+
* Namespace: `Nitpicker:Utils:ErrorEmitter`. Kept identical to the namespace
|
|
6
|
+
* used by the deleted `@ErrorEmitter()` decorator so existing `DEBUG` env
|
|
7
|
+
* filters keep working after the decorator-to-HOF migration.
|
|
8
|
+
*/
|
|
9
|
+
const errorLog = log.extend('ErrorEmitter');
|
|
10
|
+
/**
|
|
11
|
+
* Retries `fn` per `retryOptions`, then — if retries are exhausted with a
|
|
12
|
+
* final `Error` — logs and re-emits it as an `'error'` event on `emitter`
|
|
13
|
+
* before re-throwing. `label` is forwarded into `retryCall` so its own
|
|
14
|
+
* onWait / onGiveUp / timeout messages identify the call site (previously
|
|
15
|
+
* derived automatically by the `@retry` decorator via
|
|
16
|
+
* `ClassMethodDecoratorContext.name`).
|
|
17
|
+
*
|
|
18
|
+
* Inlined try/catch rather than composing {@link emitError} with a
|
|
19
|
+
* `() => retryCall(...)` closure to keep the per-invocation closure count
|
|
20
|
+
* at 1 — this method is called on the DB write hot path (`updatePage`,
|
|
21
|
+
* `insertResource`), where wrapping decorators previously ran with zero
|
|
22
|
+
* per-call allocation.
|
|
23
|
+
* @template T - The return type of `fn`.
|
|
24
|
+
* @param emitter - The event emitter that receives the `'error'` event.
|
|
25
|
+
* @param label - Human-readable label; forwarded into `retryCall`
|
|
26
|
+
* (visible in retry timeouts / onWait / onGiveUp) and used
|
|
27
|
+
* as the debug log prefix on final failure.
|
|
28
|
+
* @param fn - The async operation to retry.
|
|
29
|
+
* @param retryOptions - Retry configuration; `label` is overwritten
|
|
30
|
+
* with the `label` argument here.
|
|
31
|
+
* @returns The resolved value of `fn`.
|
|
32
|
+
*/
|
|
33
|
+
export async function emitErrorAndRetry(emitter, label, fn, retryOptions) {
|
|
34
|
+
try {
|
|
35
|
+
return await retryCall(fn, { ...retryOptions, label });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error instanceof Error) {
|
|
39
|
+
errorLog('%s: %O', label, error);
|
|
40
|
+
void emitter.emit('error', error);
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal object shape required by {@link emitError}: an emitter able to
|
|
3
|
+
* publish an `'error'` event carrying an `Error` payload. Any class that
|
|
4
|
+
* extends `TypedAwaitEventEmitter<{ error: Error, ... }>` satisfies this,
|
|
5
|
+
* and so does Node's built-in `EventEmitter`.
|
|
6
|
+
*/
|
|
7
|
+
interface Emitter {
|
|
8
|
+
/**
|
|
9
|
+
* Emits the `'error'` event with the given `Error` payload.
|
|
10
|
+
* The return value is intentionally unspecified — callers ignore it.
|
|
11
|
+
* @param event - Event name; always `'error'` here.
|
|
12
|
+
* @param payload - The error instance to publish.
|
|
13
|
+
* @returns Anything; the caller ignores it.
|
|
14
|
+
*/
|
|
15
|
+
emit(event: 'error', payload: Error): unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wraps `fn` so that any thrown `Error` is logged with `label` and
|
|
19
|
+
* re-emitted as an `'error'` event on `emitter` before being re-thrown.
|
|
20
|
+
* Non-`Error` throws pass through unchanged — no log, no emit — matching
|
|
21
|
+
* the behaviour of the deleted `@ErrorEmitter()` decorator so that
|
|
22
|
+
* downstream `'error'` listeners (e.g. the crawler orchestrator that
|
|
23
|
+
* aborts on any emitted error) are only invoked with real `Error`
|
|
24
|
+
* instances.
|
|
25
|
+
*
|
|
26
|
+
* Kept as a standalone HOF (instead of a decorator) because Vite 8 /
|
|
27
|
+
* Vitest 4.1 switched from esbuild to Rolldown + oxc, which emit
|
|
28
|
+
* TC39 Stage 3 decorator syntax as-is and let it reach Node, causing
|
|
29
|
+
* `SyntaxError: Invalid or unexpected token` at test runtime.
|
|
30
|
+
* @template T - The return type of `fn`.
|
|
31
|
+
* @param emitter - The event emitter that receives the `'error'` event.
|
|
32
|
+
* @param label - Human-readable label included in the debug log line
|
|
33
|
+
* (typically `'ClassName.methodName'`). Also useful as the
|
|
34
|
+
* grep target when triaging failed crawls.
|
|
35
|
+
* @param fn - The async operation to wrap.
|
|
36
|
+
* @returns The resolved value of `fn`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function emitError<T>(emitter: Emitter, label: string, fn: () => Promise<T>): Promise<T>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { log } from '../debug.js';
|
|
2
|
+
/**
|
|
3
|
+
* Debug logger for the ErrorEmitter helper family.
|
|
4
|
+
* Namespace: `Nitpicker:Utils:ErrorEmitter`. Kept identical to the namespace
|
|
5
|
+
* used by the deleted `@ErrorEmitter()` decorator so existing `DEBUG` env
|
|
6
|
+
* filters keep working after the decorator-to-HOF migration.
|
|
7
|
+
*/
|
|
8
|
+
const errorLog = log.extend('ErrorEmitter');
|
|
9
|
+
/**
|
|
10
|
+
* Wraps `fn` so that any thrown `Error` is logged with `label` and
|
|
11
|
+
* re-emitted as an `'error'` event on `emitter` before being re-thrown.
|
|
12
|
+
* Non-`Error` throws pass through unchanged — no log, no emit — matching
|
|
13
|
+
* the behaviour of the deleted `@ErrorEmitter()` decorator so that
|
|
14
|
+
* downstream `'error'` listeners (e.g. the crawler orchestrator that
|
|
15
|
+
* aborts on any emitted error) are only invoked with real `Error`
|
|
16
|
+
* instances.
|
|
17
|
+
*
|
|
18
|
+
* Kept as a standalone HOF (instead of a decorator) because Vite 8 /
|
|
19
|
+
* Vitest 4.1 switched from esbuild to Rolldown + oxc, which emit
|
|
20
|
+
* TC39 Stage 3 decorator syntax as-is and let it reach Node, causing
|
|
21
|
+
* `SyntaxError: Invalid or unexpected token` at test runtime.
|
|
22
|
+
* @template T - The return type of `fn`.
|
|
23
|
+
* @param emitter - The event emitter that receives the `'error'` event.
|
|
24
|
+
* @param label - Human-readable label included in the debug log line
|
|
25
|
+
* (typically `'ClassName.methodName'`). Also useful as the
|
|
26
|
+
* grep target when triaging failed crawls.
|
|
27
|
+
* @param fn - The async operation to wrap.
|
|
28
|
+
* @returns The resolved value of `fn`.
|
|
29
|
+
*/
|
|
30
|
+
export async function emitError(emitter, label, fn) {
|
|
31
|
+
try {
|
|
32
|
+
return await fn();
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
errorLog('%s: %O', label, error);
|
|
37
|
+
void emitter.emit('error', error);
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a JSON-serialized HTTP response headers column from the archive
|
|
3
|
+
* database.
|
|
4
|
+
*
|
|
5
|
+
* The columns hold JSON produced by `JSON.stringify` at insert time; absent,
|
|
6
|
+
* malformed, or non-object JSON (the string `"null"`, arrays, primitives)
|
|
7
|
+
* degrades to `null` instead of throwing because a missing header set only
|
|
8
|
+
* loses fidelity — callers decide their own fallback (`?? {}` etc.).
|
|
9
|
+
* @param json - The raw column value.
|
|
10
|
+
* @returns The parsed header record, or `null` when absent or malformed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseResponseHeaders(json: string | null): Record<string, string | string[] | undefined> | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a JSON-serialized HTTP response headers column from the archive
|
|
3
|
+
* database.
|
|
4
|
+
*
|
|
5
|
+
* The columns hold JSON produced by `JSON.stringify` at insert time; absent,
|
|
6
|
+
* malformed, or non-object JSON (the string `"null"`, arrays, primitives)
|
|
7
|
+
* degrades to `null` instead of throwing because a missing header set only
|
|
8
|
+
* loses fidelity — callers decide their own fallback (`?? {}` etc.).
|
|
9
|
+
* @param json - The raw column value.
|
|
10
|
+
* @returns The parsed header record, or `null` when absent or malformed.
|
|
11
|
+
*/
|
|
12
|
+
export function parseResponseHeaders(json) {
|
|
13
|
+
if (json == null) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(json);
|
|
18
|
+
if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitpicker/crawler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Web crawler engine with headless browser rendering and archive storage",
|
|
5
5
|
"author": "D-ZERO",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,26 +27,26 @@
|
|
|
27
27
|
"clean": "tsc --build --clean"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@d-zero/beholder": "
|
|
31
|
-
"@d-zero/dealer": "1.
|
|
32
|
-
"@d-zero/fs": "0.2.
|
|
33
|
-
"@d-zero/shared": "0.
|
|
30
|
+
"@d-zero/beholder": "3.1.3",
|
|
31
|
+
"@d-zero/dealer": "1.9.3",
|
|
32
|
+
"@d-zero/fs": "0.2.5",
|
|
33
|
+
"@d-zero/shared": "0.22.1",
|
|
34
34
|
"ansi-colors": "4.1.3",
|
|
35
35
|
"debug": "4.4.3",
|
|
36
|
-
"follow-redirects": "1.
|
|
37
|
-
"fs-extra": "11.3.
|
|
38
|
-
"knex": "3.
|
|
36
|
+
"follow-redirects": "1.16.0",
|
|
37
|
+
"fs-extra": "11.3.5",
|
|
38
|
+
"knex": "3.2.10",
|
|
39
39
|
"libsql": "0.5.29",
|
|
40
40
|
"puppeteer": "24.37.5",
|
|
41
41
|
"robots-parser": "3.0.1",
|
|
42
|
-
"tar": "7.5.
|
|
42
|
+
"tar": "7.5.16"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/debug": "4.1.
|
|
45
|
+
"@types/debug": "4.1.13",
|
|
46
46
|
"@types/follow-redirects": "1.14.4",
|
|
47
47
|
"@types/fs-extra": "11.0.4",
|
|
48
48
|
"@types/tar": "7.0.87",
|
|
49
49
|
"@types/unzipper": "0.10.11"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "58b68416e0b6e3dcdd92772bee754f186a35505f"
|
|
52
52
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { TypedAwaitEventEmitter as EventEmitter } from '@d-zero/shared/typed-await-event-emitter';
|
|
2
|
-
/**
|
|
3
|
-
* Event payload type for error events emitted by classes using the {@link ErrorEmitter} decorator.
|
|
4
|
-
* @template E - The specific error type, defaults to `Error`.
|
|
5
|
-
*/
|
|
6
|
-
export type ErrorEvent<E extends Error = Error> = {
|
|
7
|
-
/** The error instance that was caught. */
|
|
8
|
-
error: E;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* A class method decorator factory that wraps the decorated method with error handling.
|
|
12
|
-
* When the method throws an `Error`, it emits an `'error'` event on the class instance
|
|
13
|
-
* (which must extend {@link EventEmitter}) with the caught error, then re-throws the error.
|
|
14
|
-
* @template C - The class type, which must be an EventEmitter capable of emitting error events.
|
|
15
|
-
* @template E - The error event type, defaults to {@link ErrorEvent}.
|
|
16
|
-
* @returns A decorator function that wraps the target method with error-emitting behavior.
|
|
17
|
-
*/
|
|
18
|
-
export declare function ErrorEmitter<C extends EventEmitter<E>, E extends ErrorEvent = ErrorEvent>(): (method: Function, context: ClassMethodDecoratorContext) => (this: C, ...args: unknown[]) => Promise<any>;
|