@opencraw/core 0.1.2 → 0.1.4
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 +1 -1
- package/dist/access/access-broker.use-case.d.ts +43 -0
- package/dist/access/access-config.error.d.ts +5 -0
- package/dist/access/access-config.repository.d.ts +11 -0
- package/dist/access/access-json-schema.mapper.d.ts +8 -0
- package/dist/access/access-plugin.contract.d.ts +48 -0
- package/dist/access/access-preset.store.d.ts +19 -0
- package/dist/access/access-profile.contract.d.ts +95 -0
- package/dist/access/index.d.ts +11 -0
- package/dist/access/render-access.mapper.d.ts +41 -0
- package/dist/access/session-id.algorithm.d.ts +8 -0
- package/dist/api-steps/extract-from-document.use-case.d.ts +41 -0
- package/dist/api-steps/index.d.ts +4 -0
- package/dist/api-steps/run-api-step.use-case.d.ts +20 -0
- package/dist/api-steps/send-request.use-case.d.ts +23 -0
- package/dist/browser-session/browser-profile.store.d.ts +52 -0
- package/dist/browser-session/browser-session.config.d.ts +21 -0
- package/dist/browser-session/browser.client.d.ts +75 -0
- package/dist/browser-session/index.d.ts +6 -0
- package/dist/captcha/captcha-budget.model.d.ts +21 -0
- package/dist/captcha/captcha-detection.client.d.ts +28 -0
- package/dist/captcha/captcha-guard.use-case.d.ts +64 -0
- package/dist/captcha/captcha-solver-registry.store.d.ts +19 -0
- package/dist/captcha/captcha-solver.contract.d.ts +47 -0
- package/dist/captcha/captcha.error.d.ts +13 -0
- package/dist/captcha/index.d.ts +10 -0
- package/dist/captcha/resolve-captcha.use-case.d.ts +40 -0
- package/dist/crawl-events/crawl-event.contract.d.ts +169 -0
- package/dist/crawl-events/event-bus.store.d.ts +10 -0
- package/dist/crawl-events/index.d.ts +4 -0
- package/dist/crawl-events/trace-line.mapper.d.ts +14 -0
- package/dist/crawl-execution/bootstrap-session.use-case.d.ts +79 -0
- package/dist/crawl-execution/crawl-options.config.d.ts +67 -0
- package/dist/crawl-execution/crawl-report.model.d.ts +33 -0
- package/dist/crawl-execution/create-crawler.use-case.d.ts +20 -0
- package/dist/crawl-execution/index.d.ts +8 -0
- package/dist/crawl-execution/rotating-runner.use-case.d.ts +66 -0
- package/dist/crawl-execution/run-crawl.use-case.d.ts +17 -0
- package/dist/crawl-execution/run-input-recipe.use-case.d.ts +51 -0
- package/dist/deck-document/deck-document.model.d.ts +58 -0
- package/dist/deck-document/deck-table.algorithm.d.ts +35 -0
- package/dist/deck-document/index.d.ts +6 -0
- package/dist/deck-document/read-pptx.client.d.ts +16 -0
- package/dist/docx-document/index.d.ts +2 -0
- package/dist/docx-document/read-docx-html.client.d.ts +23 -0
- package/dist/extraction-scope/extraction-scope.model.d.ts +77 -0
- package/dist/extraction-scope/index.d.ts +5 -0
- package/dist/extraction-scope/live-element.model.d.ts +28 -0
- package/dist/hooks/hook-registry.store.d.ts +16 -0
- package/dist/hooks/hook.contract.d.ts +17 -0
- package/dist/hooks/hook.error.d.ts +7 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/http-session/http-response.contract.d.ts +58 -0
- package/dist/http-session/http.client.d.ts +42 -0
- package/dist/http-session/index.d.ts +5 -0
- package/dist/http-session/text-decoding.algorithm.d.ts +35 -0
- package/dist/index.esm.js +1410 -95
- package/dist/markdown-document/index.d.ts +3 -0
- package/dist/markdown-document/read-markdown.client.d.ts +39 -0
- package/dist/output-mapping/coerce-field.mapper.d.ts +19 -0
- package/dist/output-mapping/generated-field.mapper.d.ts +16 -0
- package/dist/output-mapping/index.d.ts +9 -0
- package/dist/output-mapping/map-record.use-case.d.ts +27 -0
- package/dist/output-mapping/mapping.error.d.ts +17 -0
- package/dist/output-mapping/missing-value.policy.d.ts +14 -0
- package/dist/output-mapping/output-field.validator.d.ts +10 -0
- package/dist/output-mapping/output-record.model.d.ts +20 -0
- package/dist/pdf-document/index.d.ts +7 -0
- package/dist/pdf-document/pdf-document.model.d.ts +51 -0
- package/dist/pdf-document/pdf-table.algorithm.d.ts +43 -0
- package/dist/pdf-document/read-pdf.client.d.ts +18 -0
- package/dist/pdf-document/row-assembly.algorithm.d.ts +26 -0
- package/dist/recipe-loading/index.d.ts +9 -0
- package/dist/recipe-loading/load-recipe-set.use-case.d.ts +45 -0
- package/dist/recipe-loading/read-recipe-source.use-case.d.ts +14 -0
- package/dist/recipe-loading/recipe-binding.error.d.ts +14 -0
- package/dist/recipe-loading/recipe-binding.validator.d.ts +34 -0
- package/dist/recipe-loading/recipe-file.repository.d.ts +11 -0
- package/dist/recipe-loading/recipe-set.model.d.ts +12 -0
- package/dist/recipe-loading/recipe-source.contract.d.ts +28 -0
- package/dist/recipe-loading/recipe-text.mapper.d.ts +14 -0
- package/dist/recipe-schema/index.d.ts +15 -0
- package/dist/recipe-schema/input-recipe.contract.d.ts +156 -0
- package/dist/recipe-schema/json-schema.mapper.d.ts +15 -0
- package/dist/recipe-schema/output-recipe.contract.d.ts +47 -0
- package/dist/recipe-schema/recipe-kind.enum.d.ts +35 -0
- package/dist/recipe-schema/recipe-validation.error.d.ts +17 -0
- package/dist/recipe-schema/recipe.validator.d.ts +28 -0
- package/dist/recipe-schema/step.contract.d.ts +206 -0
- package/dist/recipe-schema/transform-rule.contract.d.ts +120 -0
- package/dist/record-diff/index.d.ts +4 -0
- package/dist/record-diff/record-diff.algorithm.d.ts +82 -0
- package/dist/record-diff/records-file.repository.d.ts +10 -0
- package/dist/record-sink/dedupe.policy.d.ts +29 -0
- package/dist/record-sink/index.d.ts +9 -0
- package/dist/record-sink/json-lines-sink.repository.d.ts +19 -0
- package/dist/record-sink/memory-sink.repository.d.ts +9 -0
- package/dist/record-sink/record-sink.contract.d.ts +17 -0
- package/dist/selection/html-selector.algorithm.d.ts +19 -0
- package/dist/selection/index.d.ts +8 -0
- package/dist/selection/json-path.algorithm.d.ts +9 -0
- package/dist/selection/json-text.algorithm.d.ts +58 -0
- package/dist/selection/regex.algorithm.d.ts +12 -0
- package/dist/selection/take-value.mapper.d.ts +27 -0
- package/dist/src/access/access-profile.contract.d.ts +4 -0
- package/dist/src/access/index.d.ts +1 -1
- package/dist/src/api-steps/extract-from-document.use-case.d.ts +5 -5
- package/dist/src/api-steps/send-request.use-case.d.ts +3 -2
- package/dist/src/browser-session/browser-profile.store.d.ts +52 -0
- package/dist/src/browser-session/browser.client.d.ts +8 -0
- package/dist/src/browser-session/index.d.ts +1 -0
- package/dist/src/crawl-events/crawl-event.contract.d.ts +8 -0
- package/dist/src/crawl-execution/bootstrap-session.use-case.d.ts +23 -2
- package/dist/src/crawl-execution/crawl-options.config.d.ts +27 -0
- package/dist/src/crawl-execution/rotating-runner.use-case.d.ts +9 -0
- package/dist/src/crawl-execution/run-crawl.use-case.d.ts +6 -2
- package/dist/src/crawl-execution/run-input-recipe.use-case.d.ts +11 -3
- package/dist/src/docx-document/index.d.ts +2 -0
- package/dist/src/docx-document/read-docx-html.client.d.ts +23 -0
- package/dist/src/extraction-scope/extraction-scope.model.d.ts +2 -1
- package/dist/src/http-session/http-response.contract.d.ts +2 -1
- package/dist/src/index.d.ts +9 -4
- package/dist/src/markdown-document/index.d.ts +1 -1
- package/dist/src/markdown-document/read-markdown.client.d.ts +10 -0
- package/dist/src/recipe-schema/index.d.ts +2 -2
- package/dist/src/recipe-schema/input-recipe.contract.d.ts +24 -1
- package/dist/src/recipe-schema/recipe-kind.enum.d.ts +1 -1
- package/dist/src/recipe-schema/step.contract.d.ts +4 -0
- package/dist/src/record-diff/index.d.ts +4 -0
- package/dist/src/record-diff/record-diff.algorithm.d.ts +82 -0
- package/dist/src/record-diff/records-file.repository.d.ts +10 -0
- package/dist/src/record-sink/dedupe.policy.d.ts +19 -7
- package/dist/src/record-sink/index.d.ts +1 -0
- package/dist/src/selection/html-selector.algorithm.d.ts +2 -1
- package/dist/src/step-flow/for-each.use-case.d.ts +4 -2
- package/dist/src/step-flow/host-throttle.policy.d.ts +49 -0
- package/dist/src/step-flow/index.d.ts +5 -0
- package/dist/src/step-flow/run-gate.policy.d.ts +12 -1
- package/dist/src/step-flow/step-runner.contract.d.ts +13 -0
- package/dist/src/step-flow/transport-retry.policy.d.ts +76 -0
- package/dist/src/web-steps/navigate.use-case.d.ts +3 -2
- package/dist/src/web-steps/run-web-step.use-case.d.ts +8 -1
- package/dist/src/xml-document/index.d.ts +6 -0
- package/dist/src/xml-document/xml-document.model.d.ts +13 -0
- package/dist/src/xml-document/xml-parser.client.d.ts +49 -0
- package/dist/src/xml-document/xpath.algorithm.d.ts +30 -0
- package/dist/step-flow/block-rule.policy.d.ts +21 -0
- package/dist/step-flow/blocked.error.d.ts +9 -0
- package/dist/step-flow/for-each.use-case.d.ts +20 -0
- package/dist/step-flow/host-throttle.policy.d.ts +49 -0
- package/dist/step-flow/index.d.ts +15 -0
- package/dist/step-flow/paginate.use-case.d.ts +17 -0
- package/dist/step-flow/retry.policy.d.ts +21 -0
- package/dist/step-flow/run-gate.policy.d.ts +50 -0
- package/dist/step-flow/run-steps.use-case.d.ts +39 -0
- package/dist/step-flow/step-failure.error.d.ts +14 -0
- package/dist/step-flow/step-runner.contract.d.ts +52 -0
- package/dist/step-flow/transport-retry.policy.d.ts +76 -0
- package/dist/template/expression.algorithm.d.ts +53 -0
- package/dist/template/index.d.ts +7 -0
- package/dist/template/template.algorithm.d.ts +53 -0
- package/dist/template/value-path.algorithm.d.ts +29 -0
- package/dist/template/value-text.algorithm.d.ts +18 -0
- package/dist/transformation/apply-transform-chain.use-case.d.ts +17 -0
- package/dist/transformation/collection.algorithm.d.ts +15 -0
- package/dist/transformation/currency.algorithm.d.ts +15 -0
- package/dist/transformation/date.algorithm.d.ts +13 -0
- package/dist/transformation/index.d.ts +10 -0
- package/dist/transformation/lookup.algorithm.d.ts +24 -0
- package/dist/transformation/number.algorithm.d.ts +30 -0
- package/dist/transformation/string.algorithm.d.ts +18 -0
- package/dist/transformation/transform-registry.store.d.ts +36 -0
- package/dist/transformation/transform.error.d.ts +8 -0
- package/dist/transformation/url.algorithm.d.ts +20 -0
- package/dist/web-steps/evaluate-script.use-case.d.ts +10 -0
- package/dist/web-steps/extract-from-page.use-case.d.ts +10 -0
- package/dist/web-steps/index.d.ts +2 -0
- package/dist/web-steps/interact.use-case.d.ts +36 -0
- package/dist/web-steps/navigate.use-case.d.ts +15 -0
- package/dist/web-steps/run-web-step.use-case.d.ts +37 -0
- package/dist/web-steps/snapshot-elements.use-case.d.ts +13 -0
- package/dist/workbook-document/csv-parser.algorithm.d.ts +26 -0
- package/dist/workbook-document/csv-workbook.mapper.d.ts +24 -0
- package/dist/workbook-document/grid-table.algorithm.d.ts +53 -0
- package/dist/workbook-document/html-tables.mapper.d.ts +14 -0
- package/dist/workbook-document/index.d.ts +9 -0
- package/dist/workbook-document/read-xlsx.client.d.ts +18 -0
- package/dist/workbook-document/workbook-document.model.d.ts +51 -0
- package/dist/xml-document/index.d.ts +6 -0
- package/dist/xml-document/xml-document.model.d.ts +13 -0
- package/dist/xml-document/xml-parser.client.d.ts +49 -0
- package/dist/xml-document/xpath.algorithm.d.ts +30 -0
- package/dist/yaml-document/index.d.ts +3 -0
- package/dist/yaml-document/read-yaml.client.d.ts +25 -0
- package/package.json +4 -2
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { AccessBroker } from '../access/index.js';
|
|
2
2
|
import { BrowserClient } from '../browser-session/index.js';
|
|
3
|
+
import type { BrowserProfiles } from '../browser-session/index.js';
|
|
3
4
|
import { CaptchaSolverRegistry } from '../captcha/index.js';
|
|
4
5
|
import type { EventBus } from '../crawl-events/index.js';
|
|
5
6
|
import type { HookRegistry } from '../hooks/index.js';
|
|
6
|
-
import type { InputRecipe, OutputRecipe } from '../recipe-schema/index.js';
|
|
7
|
+
import type { InputRecipe, OutputRecipe, RetryRule } from '../recipe-schema/index.js';
|
|
7
8
|
import type { DedupePolicy, RecordSink } from '../record-sink/index.js';
|
|
9
|
+
import type { HostThrottle } from '../step-flow/index.js';
|
|
8
10
|
import type { RecipeReport } from './crawl-report.model.js';
|
|
9
11
|
export interface RecipeRunDependencies {
|
|
10
12
|
browser: () => Promise<BrowserClient>;
|
|
@@ -23,6 +25,12 @@ export interface RecipeRunDependencies {
|
|
|
23
25
|
access: AccessBroker;
|
|
24
26
|
/** The solvers recipes name; none when omitted. */
|
|
25
27
|
captchaSolvers?: CaptchaSolverRegistry;
|
|
28
|
+
/** The crawler's per-site throttle, shared by every recipe. */
|
|
29
|
+
hosts?: HostThrottle;
|
|
30
|
+
/** The runner's persistent browser profiles, for `session.browserProfile`. */
|
|
31
|
+
profiles?: BrowserProfiles;
|
|
32
|
+
/** The crawler's retry rule, under each recipe's `limits.retry`. */
|
|
33
|
+
retry?: RetryRule;
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Runs one input recipe end to end: session, runner, the step walk, and for
|
|
@@ -34,10 +42,10 @@ export interface RecipeRunDependencies {
|
|
|
34
42
|
* the sink sees one record at a time and `maxRecords` is exact: once reached,
|
|
35
43
|
* every later emit returns `stop` before mapping.
|
|
36
44
|
*
|
|
37
|
-
* @param
|
|
45
|
+
* @param recipe - The input recipe.
|
|
38
46
|
* @param output - The output recipe it feeds.
|
|
39
47
|
* @param deps - Shared browser, hooks, events, sink and de-duplication.
|
|
40
48
|
* @returns What happened.
|
|
41
49
|
*/
|
|
42
|
-
export declare function runInputRecipe(
|
|
50
|
+
export declare function runInputRecipe(recipe: InputRecipe, output: OutputRecipe, deps: RecipeRunDependencies): Promise<RecipeReport>;
|
|
43
51
|
//# sourceMappingURL=run-input-recipe.use-case.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a `.docx` Word document into HTML, through `@opencraw/office-reader`,
|
|
3
|
+
* so every selector that reads a page reads a Word document too:
|
|
4
|
+
*
|
|
5
|
+
* - headings become `<h1>`…`<h6>` inside `<section data-heading="…">`, as in
|
|
6
|
+
* rendered Markdown;
|
|
7
|
+
* - list items become nested `<ul>` / `<ol>`;
|
|
8
|
+
* - tables become `<table>`s with their merged cells as `colspan` / `rowspan`,
|
|
9
|
+
* so a `table` extract reads them like any HTML table;
|
|
10
|
+
* - a paragraph keeps its style as `data-style` and its links as `<a href>`;
|
|
11
|
+
* - headers, footers and notes follow the body, in `<header>`, `<footer>`
|
|
12
|
+
* and `<aside data-part="notes">`; the title goes to `<title>`.
|
|
13
|
+
*
|
|
14
|
+
* The reader is imported on first use.
|
|
15
|
+
*
|
|
16
|
+
* @param bytes - The file.
|
|
17
|
+
* @param source - Where it came from, for messages.
|
|
18
|
+
* @returns The HTML document.
|
|
19
|
+
* @throws Error naming the source, and saying what to do, for a file that is
|
|
20
|
+
* not a readable Word document (a legacy `.doc`, a password-protected file, an `.odt`…).
|
|
21
|
+
*/
|
|
22
|
+
export declare function readDocxHtml(bytes: Uint8Array, source: string): Promise<string>;
|
|
23
|
+
//# sourceMappingURL=read-docx-html.client.d.ts.map
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
* Page state (the current URL, page number and the document `extract` reads by
|
|
8
8
|
* default) is scope state too, bound in the innermost scope that navigated.
|
|
9
9
|
*/
|
|
10
|
+
import type { XmlDocument } from '../xml-document/index.js';
|
|
10
11
|
import type { DeckDocument } from '../deck-document/index.js';
|
|
11
12
|
import type { PdfDocument } from '../pdf-document/index.js';
|
|
12
13
|
import type { WorkbookDocument } from '../workbook-document/index.js';
|
|
13
14
|
/** A fetched or rendered document a later `extract` can read. */
|
|
14
|
-
export type ScopeDocument = PdfDocument | WorkbookDocument | DeckDocument | {
|
|
15
|
+
export type ScopeDocument = PdfDocument | WorkbookDocument | DeckDocument | XmlDocument | {
|
|
15
16
|
kind: 'json';
|
|
16
17
|
data: unknown;
|
|
17
18
|
} | {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DeckDocument } from '../deck-document/index.js';
|
|
2
2
|
import type { PdfDocument } from '../pdf-document/index.js';
|
|
3
3
|
import type { WorkbookDocument } from '../workbook-document/index.js';
|
|
4
|
+
import type { XmlDocument } from '../xml-document/index.js';
|
|
4
5
|
import type { BodyKind, HttpMethod } from '../recipe-schema/index.js';
|
|
5
6
|
/** One HTTP request as the api runner sends it, templates already rendered. */
|
|
6
7
|
export interface HttpRequest {
|
|
@@ -20,7 +21,7 @@ export interface HttpRequest {
|
|
|
20
21
|
timeoutMs?: number;
|
|
21
22
|
}
|
|
22
23
|
/** A parsed response body. Structurally the same as a scope document, on purpose. */
|
|
23
|
-
export type HttpBody = PdfDocument | WorkbookDocument | DeckDocument | {
|
|
24
|
+
export type HttpBody = PdfDocument | WorkbookDocument | DeckDocument | XmlDocument | {
|
|
24
25
|
kind: 'json';
|
|
25
26
|
data: unknown;
|
|
26
27
|
} | {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { createCrawler } from './crawl-execution/index.js';
|
|
2
|
-
export { AccessBroker, AccessConfigError, ACCESS_PRESETS, loadAccessConfig, accessConfigSchema, accessConfigJsonSchema } from './access/index.js';
|
|
2
|
+
export { AccessBroker, AccessConfigError, ACCESS_PRESETS, loadAccessConfig, accessConfigSchema, accessConfigJsonSchema, throttleConfigSchema } from './access/index.js';
|
|
3
3
|
export type { AccessConfig, AccessProfile, AccessPlugin, AccessLease, LeaseRequest, PluginLeaseRequest, ProxySettings, AccessPreset } from './access/index.js';
|
|
4
4
|
export type { Crawler, CrawlOptions, CrawlReport, RecipeReport } from './crawl-execution/index.js';
|
|
5
5
|
export { loadRecipeSet, loadRecipes, readRecipeSource, bindRecipeSet, RecipeSet, RecipeBindingError, validateBinding } from './recipe-loading/index.js';
|
|
6
6
|
export type { RecipeSetSource, RecipeSource, RecipeBytes, RecipeDocument, BindingIssue } from './recipe-loading/index.js';
|
|
7
|
-
export { parseInputRecipe, parseOutputRecipe, RecipeValidationError, inputRecipeJsonSchema, outputRecipeJsonSchema, inputRecipeSchema, outputRecipeSchema } from './recipe-schema/index.js';
|
|
8
|
-
export type { InputRecipe, OutputRecipe, FieldSpec, Step, StepType, MappingRule, TransformRule, ErrorPolicy, PaginateNext, SessionSpec, SessionAccess, CaptchaSettings, CaptchaStep, RecipeIssue } from './recipe-schema/index.js';
|
|
7
|
+
export { parseInputRecipe, parseOutputRecipe, RecipeValidationError, inputRecipeJsonSchema, outputRecipeJsonSchema, inputRecipeSchema, outputRecipeSchema, retryRuleSchema } from './recipe-schema/index.js';
|
|
8
|
+
export type { InputRecipe, OutputRecipe, FieldSpec, Step, StepType, MappingRule, TransformRule, ErrorPolicy, PaginateNext, SessionSpec, SessionAccess, CaptchaSettings, CaptchaStep, RetryRule, RecipeIssue } from './recipe-schema/index.js';
|
|
9
9
|
export type { Hook, HookMap, HookContext } from './hooks/index.js';
|
|
10
10
|
export { UnknownHookError } from './hooks/index.js';
|
|
11
11
|
export type { OutputRecord } from './output-mapping/index.js';
|
|
@@ -24,11 +24,16 @@ export type { PdfDocument, PdfPage, PdfRow, PdfCell, PdfTable, TableQuery, Table
|
|
|
24
24
|
export { parseCsv, detectDelimiter, csvWorkbook, findGridTables, fillDown, workbookText, isWorkbookDocument, htmlTableSheets } from './workbook-document/index.js';
|
|
25
25
|
export { readMarkdown } from './markdown-document/index.js';
|
|
26
26
|
export { readYaml } from './yaml-document/index.js';
|
|
27
|
+
export { parseXml, selectXpath, takeFromXml, isXmlDocument } from './xml-document/index.js';
|
|
28
|
+
export type { XmlDocument, XpathOptions, XpathValue } from './xml-document/index.js';
|
|
27
29
|
export { findDeckTables, deckText, isDeckDocument } from './deck-document/index.js';
|
|
28
30
|
export type { DeckDocument, DeckSlide, DeckShape, DeckChart, DeckTable, DeckTableQuery } from './deck-document/index.js';
|
|
29
31
|
export type { WorkbookDocument, WorkbookCell, Sheet, CsvFormat, GridTable, GridTableQuery } from './workbook-document/index.js';
|
|
30
|
-
export { StepFailure } from './step-flow/index.js';
|
|
32
|
+
export { StepFailure, HostThrottle, DEFAULT_RETRY_RULE } from './step-flow/index.js';
|
|
33
|
+
export type { ThrottleConfig, HostRule } from './step-flow/index.js';
|
|
31
34
|
export { TransformError } from './transformation/index.js';
|
|
35
|
+
export { diffRecords, diffOptionsFor, readableKey, readRecordsFile } from './record-diff/index.js';
|
|
36
|
+
export type { RecordDiff, RecordChange, FieldChange, DiffOptions, StoredRecord } from './record-diff/index.js';
|
|
32
37
|
export { CaptchaError, DEFAULT_CAPTCHA_SELECTOR, detectChallenge } from './captcha/index.js';
|
|
33
38
|
export type { CaptchaSolver, CaptchaChallenge, CaptchaContext, CaptchaOutcome, CaptchaKind, CaptchaLog } from './captcha/index.js';
|
|
34
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -26,4 +26,14 @@ export interface MarkdownRead {
|
|
|
26
26
|
* @throws Error naming the source when the front matter is not YAML.
|
|
27
27
|
*/
|
|
28
28
|
export declare function readMarkdown(text: string, source: string): Promise<MarkdownRead>;
|
|
29
|
+
/**
|
|
30
|
+
* Wraps each heading and what follows it, up to the next heading of the same
|
|
31
|
+
* or a higher level, in `<section data-heading="…" data-level="…">`, sections
|
|
32
|
+
* nesting; headings get slug ids. Rendered Markdown and Word documents both go
|
|
33
|
+
* through it, so one selector finds "the table under *Prezzi*" in either.
|
|
34
|
+
*
|
|
35
|
+
* @param html - Top-level HTML: headings among paragraphs, lists, tables.
|
|
36
|
+
* @returns The same content, sectioned.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sectioned(html: string): string;
|
|
29
39
|
//# sourceMappingURL=read-markdown.client.d.ts.map
|
|
@@ -5,8 +5,8 @@ export { stepSchema, errorPolicySchema, paginateNextSchema } from './step.contra
|
|
|
5
5
|
export type { Step, StepType, StepBaseFields, TargetFields, ErrorPolicy, PaginateNext, TakeKind, GotoStep, ClickStep, FillStep, PressStep, SelectStep, ScrollStep, WaitStep, EvaluateStep, ScreenshotStep, RequestStep, ExtractStep, SetStep, CollectStep, ForEachStep, IfStep, PaginateStep, EmitStep, HookStep, CaptchaStep, CaptchaCheck, } from './step.contract.js';
|
|
6
6
|
export { transformRuleSchema, mappingRuleSchema } from './transform-rule.contract.js';
|
|
7
7
|
export type { TransformRule, TransformOp, MappingRule, FromRule, EachRule } from './transform-rule.contract.js';
|
|
8
|
-
export { inputRecipeSchema, sessionSpecSchema, startPointSchema } from './input-recipe.contract.js';
|
|
9
|
-
export type { InputRecipe, SessionSpec, SessionBootstrap, SessionAccess, BlockRule, BlockRotation, CaptchaSettings, StartPoint, CrawlLimits, RecipeCookie } from './input-recipe.contract.js';
|
|
8
|
+
export { inputRecipeSchema, sessionSpecSchema, startPointSchema, retryRuleSchema } from './input-recipe.contract.js';
|
|
9
|
+
export type { InputRecipe, SessionSpec, SessionBootstrap, SessionAccess, BlockRule, BlockRotation, CaptchaSettings, RetryRule, StartPoint, CrawlLimits, RecipeCookie } from './input-recipe.contract.js';
|
|
10
10
|
export { parseInputRecipe, parseOutputRecipe, recipeKindOf } from './recipe.validator.js';
|
|
11
11
|
export { RecipeValidationError } from './recipe-validation.error.js';
|
|
12
12
|
export type { RecipeIssue } from './recipe-validation.error.js';
|
|
@@ -99,14 +99,36 @@ export interface SessionSpec {
|
|
|
99
99
|
blockedWhen?: BlockRule;
|
|
100
100
|
onBlock?: BlockRotation;
|
|
101
101
|
captcha?: CaptchaSettings;
|
|
102
|
+
/**
|
|
103
|
+
* A browser profile of the runner that persists between runs (cookies,
|
|
104
|
+
* storage, cache): web recipes and bootstraps run in it. A name; the runner
|
|
105
|
+
* decides where profiles live.
|
|
106
|
+
*/
|
|
107
|
+
browserProfile?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* How a request that fails in passing (a dropped connection, a timeout, a
|
|
111
|
+
* 503, a 429) is sent again. On by default: three tries in all.
|
|
112
|
+
*/
|
|
113
|
+
export interface RetryRule {
|
|
114
|
+
/** Tries per request, the first included; `1` turns retrying off. Default 3. */
|
|
115
|
+
attempts?: number;
|
|
116
|
+
/** The first pause; it doubles on every retry. Default 1000. */
|
|
117
|
+
backoffMs?: number;
|
|
118
|
+
/** The longest pause, `Retry-After` included; a server asking for longer is not retried. Default 30000. */
|
|
119
|
+
maxDelayMs?: number;
|
|
120
|
+
/** The statuses retried. Default `[408, 425, 429, 500, 502, 503, 504]`. */
|
|
121
|
+
statuses?: number[];
|
|
102
122
|
}
|
|
103
123
|
export interface CrawlLimits {
|
|
104
124
|
maxRecords?: number;
|
|
105
125
|
/** Minimum interval between two request starts across the recipe, whatever runs in parallel. */
|
|
106
126
|
delayMs?: number;
|
|
107
127
|
timeoutMs?: number;
|
|
108
|
-
/** How many `forEach` iterations may run at once
|
|
128
|
+
/** How many `forEach` iterations over a list may run at once: requests in api mode, tabs in web mode. Default 1. */
|
|
109
129
|
concurrency?: number;
|
|
130
|
+
/** How requests that fail in passing are sent again; the crawler's `retry`, else three tries, when omitted. */
|
|
131
|
+
retry?: RetryRule;
|
|
110
132
|
}
|
|
111
133
|
/** Where to start, how to navigate, what to extract, and how it maps to one output recipe. */
|
|
112
134
|
export interface InputRecipe {
|
|
@@ -129,5 +151,6 @@ export interface InputRecipe {
|
|
|
129
151
|
}
|
|
130
152
|
export declare const startPointSchema: z.ZodType<StartPoint>;
|
|
131
153
|
export declare const sessionSpecSchema: z.ZodType<SessionSpec>;
|
|
154
|
+
export declare const retryRuleSchema: z.ZodType<RetryRule>;
|
|
132
155
|
export declare const inputRecipeSchema: z.ZodType<InputRecipe>;
|
|
133
156
|
//# sourceMappingURL=input-recipe.contract.d.ts.map
|
|
@@ -4,7 +4,7 @@ export declare const CRAWL_MODES: readonly ["web", "api"];
|
|
|
4
4
|
export declare const SELECTOR_KINDS: readonly ["css", "xpath", "jsonpath", "regex", "table"];
|
|
5
5
|
/** `take` also accepts `attr:<name>`, which is validated by pattern rather than listed. */
|
|
6
6
|
export declare const TAKE_KINDS: readonly ["text", "html", "value", "json"];
|
|
7
|
-
export declare const BODY_KINDS: readonly ["json", "jsonl", "html", "text", "pdf", "csv", "xlsx", "pptx", "yaml", "markdown"];
|
|
7
|
+
export declare const BODY_KINDS: readonly ["json", "jsonl", "html", "text", "pdf", "csv", "xlsx", "pptx", "yaml", "markdown", "xml", "docx"];
|
|
8
8
|
export declare const YAML_SCALARS: readonly ["typed", "text"];
|
|
9
9
|
/** How a PDF table aligns a row's values against a cell wrapped over several lines. */
|
|
10
10
|
export declare const TABLE_ALIGNS: readonly ["auto", "top", "center", "bottom"];
|
|
@@ -119,6 +119,10 @@ export interface ExtractStep extends StepBaseFields {
|
|
|
119
119
|
slide?: string;
|
|
120
120
|
/** `table` only: read text boxes laid out as a table instead of native tables (deck). */
|
|
121
121
|
shapes?: boolean;
|
|
122
|
+
/** `xpath` on XML only: prefix to namespace URI (`{ "atom": "http://www.w3.org/2005/Atom" }`). Prefixes the root declares are known already. */
|
|
123
|
+
namespaces?: Record<string, string>;
|
|
124
|
+
/** `xpath` on XML only: drop the document's namespaces, so `//entry/title` matches `<entry xmlns="…">`. */
|
|
125
|
+
ignoreNamespaces?: boolean;
|
|
122
126
|
}
|
|
123
127
|
export interface SetStep extends StepBaseFields {
|
|
124
128
|
type: 'set';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { diffRecords, diffOptionsFor, readableKey } from './record-diff.algorithm.js';
|
|
2
|
+
export type { RecordDiff, RecordChange, FieldChange, DiffOptions, StoredRecord } from './record-diff.algorithm.js';
|
|
3
|
+
export { readRecordsFile } from './records-file.repository.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { OutputRecipe } from '../recipe-schema/index.js';
|
|
2
|
+
/** A record as a JSON Lines file holds it: the data, plus the sink's `_source` (and `_key` in append mode). */
|
|
3
|
+
export type StoredRecord = Record<string, unknown>;
|
|
4
|
+
/** One field whose value changed; nested objects are compared field by field (`price.amount`). */
|
|
5
|
+
export interface FieldChange {
|
|
6
|
+
field: string;
|
|
7
|
+
before: unknown;
|
|
8
|
+
after: unknown;
|
|
9
|
+
}
|
|
10
|
+
export type RecordChange = {
|
|
11
|
+
change: 'added';
|
|
12
|
+
key: string;
|
|
13
|
+
after: StoredRecord;
|
|
14
|
+
} | {
|
|
15
|
+
change: 'removed';
|
|
16
|
+
key: string;
|
|
17
|
+
before: StoredRecord;
|
|
18
|
+
} | {
|
|
19
|
+
change: 'changed';
|
|
20
|
+
key: string;
|
|
21
|
+
before: StoredRecord;
|
|
22
|
+
after: StoredRecord;
|
|
23
|
+
fields: FieldChange[];
|
|
24
|
+
};
|
|
25
|
+
/** How two runs differ, by record key. */
|
|
26
|
+
export interface RecordDiff {
|
|
27
|
+
added: number;
|
|
28
|
+
removed: number;
|
|
29
|
+
changed: number;
|
|
30
|
+
unchanged: number;
|
|
31
|
+
/** Every change, removed first, then changed, then added, each in file order. */
|
|
32
|
+
changes: RecordChange[];
|
|
33
|
+
/** Records on either side the key cannot tell apart from an earlier one: only the first counts. */
|
|
34
|
+
repeated: number;
|
|
35
|
+
/** How many records each side holds. */
|
|
36
|
+
counts: {
|
|
37
|
+
previous: number;
|
|
38
|
+
current: number;
|
|
39
|
+
};
|
|
40
|
+
/** Set when the current run holds far fewer records: the usual sign a site changed and a recipe broke quietly. */
|
|
41
|
+
shrunk?: {
|
|
42
|
+
previous: number;
|
|
43
|
+
current: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface DiffOptions {
|
|
47
|
+
/** The fields that identify a record. Default: the `_key` each line carries (a sink in append mode writes it). */
|
|
48
|
+
key?: readonly string[];
|
|
49
|
+
/** Fields not compared (their dotted paths match nested ones too). `_source` and `_key` never are. */
|
|
50
|
+
ignore?: readonly string[];
|
|
51
|
+
/** The share of records a run may lose before `shrunk` is set; default 0.5 (half). */
|
|
52
|
+
shrink?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compares two runs' records by key: what was added, what was removed, and
|
|
56
|
+
* for the records in both, which fields changed, before and after. Like a
|
|
57
|
+
* `git diff` of a price list, but row by row instead of line by line, so a
|
|
58
|
+
* reordered file is not a change.
|
|
59
|
+
*
|
|
60
|
+
* @param previous - The earlier run's records.
|
|
61
|
+
* @param current - The later run's records.
|
|
62
|
+
* @param options - The key fields, the fields to ignore, the shrink threshold.
|
|
63
|
+
* @returns The differences.
|
|
64
|
+
* @throws Error when records carry no key: without `key`, every line needs `_key`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function diffRecords(previous: readonly StoredRecord[], current: readonly StoredRecord[], options?: DiffOptions): RecordDiff;
|
|
67
|
+
/**
|
|
68
|
+
* The diff options an output recipe implies: its key fields, and its fields
|
|
69
|
+
* the engine fills differently every run (`generated: now`, `uuid`).
|
|
70
|
+
*
|
|
71
|
+
* @param output - The output recipe.
|
|
72
|
+
* @returns The key and the fields to ignore.
|
|
73
|
+
*/
|
|
74
|
+
export declare function diffOptionsFor(output: OutputRecipe): Required<Pick<DiffOptions, 'key' | 'ignore'>>;
|
|
75
|
+
/**
|
|
76
|
+
* A key as people read it: the key fields' values joined (`Pandina · 1.0 Hybrid`).
|
|
77
|
+
*
|
|
78
|
+
* @param key - A record key (a JSON array of the key values).
|
|
79
|
+
* @returns The readable form.
|
|
80
|
+
*/
|
|
81
|
+
export declare function readableKey(key: string): string;
|
|
82
|
+
//# sourceMappingURL=record-diff.algorithm.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoredRecord } from './record-diff.algorithm.js';
|
|
2
|
+
/**
|
|
3
|
+
* The records of a JSON Lines file, as a sink wrote them.
|
|
4
|
+
*
|
|
5
|
+
* @param path - The file.
|
|
6
|
+
* @returns One record per non-empty line.
|
|
7
|
+
* @throws Error naming the file and the line that is not a JSON object.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readRecordsFile(path: string): Promise<StoredRecord[]>;
|
|
10
|
+
//# sourceMappingURL=records-file.repository.d.ts.map
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import type { OutputRecord } from '../output-mapping/index.js';
|
|
2
2
|
/** How far de-duplication reaches: the whole run, one input recipe, or not at all. */
|
|
3
3
|
export type DedupeScope = 'run' | 'recipe' | 'off';
|
|
4
|
-
/**
|
|
4
|
+
/** One input recipe's view of de-duplication: whether a record repeats a key already seen. */
|
|
5
|
+
export interface RecipeDedupe {
|
|
6
|
+
/**
|
|
7
|
+
* @param record - A validated record.
|
|
8
|
+
* @returns `true` when the record repeats an earlier key and must be dropped.
|
|
9
|
+
*/
|
|
10
|
+
isDuplicate: (record: OutputRecord) => boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Drops records whose key was already seen. First record wins; keyless
|
|
14
|
+
* records always pass. Recipes running in parallel each get their own view:
|
|
15
|
+
* under `recipe` scope they never see each other's keys, under `run` scope
|
|
16
|
+
* they share them (and whichever emits a key first keeps it).
|
|
17
|
+
*/
|
|
5
18
|
export declare class DedupePolicy {
|
|
6
19
|
readonly scope: DedupeScope;
|
|
7
|
-
private
|
|
20
|
+
private readonly shared;
|
|
8
21
|
constructor(scope?: DedupeScope);
|
|
9
|
-
/** Called when an input recipe starts; forgets keys under `recipe` scope. */
|
|
10
|
-
startRecipe(): void;
|
|
11
22
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
23
|
+
* The de-duplication one input recipe run uses.
|
|
24
|
+
*
|
|
25
|
+
* @returns Its view: keys shared with the run, its own, or none checked.
|
|
14
26
|
*/
|
|
15
|
-
|
|
27
|
+
forRecipe(): RecipeDedupe;
|
|
16
28
|
}
|
|
17
29
|
//# sourceMappingURL=dedupe.policy.d.ts.map
|
|
@@ -4,5 +4,6 @@ export type { MemorySink } from './memory-sink.repository.js';
|
|
|
4
4
|
export { jsonLinesSink } from './json-lines-sink.repository.js';
|
|
5
5
|
export type { JsonLinesSinkOptions } from './json-lines-sink.repository.js';
|
|
6
6
|
export { DedupePolicy } from './dedupe.policy.js';
|
|
7
|
+
export type { RecipeDedupe } from './dedupe.policy.js';
|
|
7
8
|
export type { DedupeScope } from './dedupe.policy.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -12,7 +12,8 @@ export interface HtmlMatch {
|
|
|
12
12
|
*
|
|
13
13
|
* @param html - The markup (a whole document or a fragment).
|
|
14
14
|
* @param selector - A CSS selector.
|
|
15
|
+
* @param xml - Read the markup as XML: names keep their case, `take: "html"` gives XML.
|
|
15
16
|
* @returns Every match, in document order.
|
|
16
17
|
*/
|
|
17
|
-
export declare function selectHtml(html: string, selector: string): HtmlMatch[];
|
|
18
|
+
export declare function selectHtml(html: string, selector: string, xml?: boolean): HtmlMatch[];
|
|
18
19
|
//# sourceMappingURL=html-selector.algorithm.d.ts.map
|
|
@@ -6,8 +6,10 @@ import type { EmitOutcome, StepWalk } from './run-steps.use-case.js';
|
|
|
6
6
|
* matching `selector`, each in a fresh child scope with the item bound under
|
|
7
7
|
* `as`; emits a record per iteration when asked.
|
|
8
8
|
*
|
|
9
|
-
* With a concurrent gate, iterations run as permits allow and
|
|
10
|
-
* out in completion order; without one, in list order.
|
|
9
|
+
* With a concurrent gate, iterations of a list run as permits allow and
|
|
10
|
+
* records come out in completion order; without one, in list order. In web
|
|
11
|
+
* mode each parallel iteration runs in a tab of its own (`runner.fork`); a
|
|
12
|
+
* loop over live elements stays sequential, since its elements live on one page.
|
|
11
13
|
*
|
|
12
14
|
* @param step - The forEach step.
|
|
13
15
|
* @param scope - The scope the list lives in.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** How gently one site is crawled. */
|
|
2
|
+
export interface HostRule {
|
|
3
|
+
/** Minimum time between two request starts to the site, whatever recipe sends them. */
|
|
4
|
+
delayMs?: number;
|
|
5
|
+
/** Requests to the site in flight at once. */
|
|
6
|
+
concurrency?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The crawler's politeness towards each site, across every recipe and run it
|
|
10
|
+
* executes: a default rule for any host, and rules by domain (`example.com`
|
|
11
|
+
* also covers `www.example.com`; the longest match wins).
|
|
12
|
+
*/
|
|
13
|
+
export interface ThrottleConfig extends HostRule {
|
|
14
|
+
domains?: Record<string, HostRule>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Spaces and bounds requests per site, shared by every recipe of a crawler,
|
|
18
|
+
* so two recipes (or two parallel iterations) that hit one site add up to one
|
|
19
|
+
* polite client rather than two. A recipe's own `limits.delayMs` still applies
|
|
20
|
+
* on top, per recipe.
|
|
21
|
+
*
|
|
22
|
+
* Like a single-lane bridge with a traffic light: whoever arrives waits for
|
|
23
|
+
* the car ahead to be far enough, and for a free lane.
|
|
24
|
+
*/
|
|
25
|
+
export declare class HostThrottle {
|
|
26
|
+
private readonly config;
|
|
27
|
+
private readonly buckets;
|
|
28
|
+
private readonly domains;
|
|
29
|
+
constructor(config?: ThrottleConfig);
|
|
30
|
+
private bucketFor;
|
|
31
|
+
/** Whether any rule can hold a request back. */
|
|
32
|
+
get active(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Waits until a request to `url` may start, then holds one of its site's
|
|
35
|
+
* lanes until the returned release is called.
|
|
36
|
+
*
|
|
37
|
+
* @param url - Where the request goes; anything but `http(s):` passes at once.
|
|
38
|
+
* @returns The release: call it once, when the response arrived or the request failed.
|
|
39
|
+
*/
|
|
40
|
+
slot(url: string): Promise<() => void>;
|
|
41
|
+
/**
|
|
42
|
+
* Holds every request to the site of `url` back until `untilMs` (a `Retry-After`).
|
|
43
|
+
*
|
|
44
|
+
* @param url - A URL of the site.
|
|
45
|
+
* @param untilMs - An epoch time.
|
|
46
|
+
*/
|
|
47
|
+
pause(url: string, untilMs: number): void;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=host-throttle.policy.d.ts.map
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export { runSteps } from './run-steps.use-case.js';
|
|
2
2
|
export type { StepWalkOptions, EmitOutcome } from './run-steps.use-case.js';
|
|
3
3
|
export type { StepRunner, NextPageResult } from './step-runner.contract.js';
|
|
4
|
+
export { disposeQuietly } from './step-runner.contract.js';
|
|
4
5
|
export { StepFailure, NoMatchError } from './step-failure.error.js';
|
|
5
6
|
export { resolveErrorPolicy, backoffFor, sleep } from './retry.policy.js';
|
|
6
7
|
export { RunGate } from './run-gate.policy.js';
|
|
8
|
+
export { HostThrottle } from './host-throttle.policy.js';
|
|
9
|
+
export { withTransportRetry, resolveRetryRule, transientError, retryDelay, DEFAULT_RETRY_RULE, RETRY_STATUSES } from './transport-retry.policy.js';
|
|
10
|
+
export type { ResolvedRetryRule, Transient, TransportAttempt, RetryContext } from './transport-retry.policy.js';
|
|
11
|
+
export type { HostRule, ThrottleConfig } from './host-throttle.policy.js';
|
|
7
12
|
export { BlockedError } from './blocked.error.js';
|
|
8
13
|
export { detectBlock, DEFAULT_BLOCK_RULE } from './block-rule.policy.js';
|
|
9
14
|
export type { ObservedResponse } from './block-rule.policy.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HostThrottle } from './host-throttle.policy.js';
|
|
1
2
|
/**
|
|
2
3
|
* What bounds a recipe run: how many `forEach` iterations may be in flight and
|
|
3
4
|
* how close together requests may start. One gate per recipe run, shared by
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
export declare class RunGate {
|
|
11
12
|
readonly permits: number;
|
|
12
13
|
readonly minIntervalMs: number;
|
|
14
|
+
readonly hosts?: HostThrottle | undefined;
|
|
13
15
|
private readonly shared?;
|
|
14
16
|
private inFlight;
|
|
15
17
|
private readonly waiting;
|
|
@@ -17,9 +19,10 @@ export declare class RunGate {
|
|
|
17
19
|
/**
|
|
18
20
|
* @param permits - Iterations allowed in flight; 1 is sequential.
|
|
19
21
|
* @param minIntervalMs - Minimum time between two request starts across the run.
|
|
22
|
+
* @param hosts - The crawler's per-site throttle, shared with every other recipe.
|
|
20
23
|
* @param shared - The throttle state to share (internal: `nested` gates keep their parent's).
|
|
21
24
|
*/
|
|
22
|
-
constructor(permits: number, minIntervalMs: number, shared?: RunGate | undefined);
|
|
25
|
+
constructor(permits: number, minIntervalMs: number, hosts?: HostThrottle | undefined, shared?: RunGate | undefined);
|
|
23
26
|
/** Whether this gate lets more than one iteration run at once. */
|
|
24
27
|
get concurrent(): boolean;
|
|
25
28
|
/**
|
|
@@ -33,6 +36,14 @@ export declare class RunGate {
|
|
|
33
36
|
* whichever loop started it. Returns at once when the interval has passed.
|
|
34
37
|
*/
|
|
35
38
|
throttle(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Waits until a request to `url` may start: the recipe's interval, then its
|
|
41
|
+
* site's turn in the crawler's per-site throttle.
|
|
42
|
+
*
|
|
43
|
+
* @param url - Where the request goes.
|
|
44
|
+
* @returns The release of the site's lane: call it once the response arrived or the request failed.
|
|
45
|
+
*/
|
|
46
|
+
request(url: string): Promise<() => void>;
|
|
36
47
|
/** The gate for a body running inside an iteration that holds a permit: sequential, same throttle. */
|
|
37
48
|
nested(): RunGate;
|
|
38
49
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { ExtractionScope, LiveElement } from '../extraction-scope/index.js';
|
|
2
2
|
import type { PaginateNext, Step } from '../recipe-schema/index.js';
|
|
3
3
|
import type { BlockedError } from './blocked.error.js';
|
|
4
|
+
/**
|
|
5
|
+
* Disposes a runner, ignoring a failure: a tab whose browser already went
|
|
6
|
+
* away (a rotation, a crash) has nothing left to close.
|
|
7
|
+
*
|
|
8
|
+
* @param runner - The runner.
|
|
9
|
+
*/
|
|
10
|
+
export declare function disposeQuietly(runner: StepRunner): Promise<void>;
|
|
4
11
|
/** What `paginate` learns from the runner after a page body ran. */
|
|
5
12
|
export type NextPageResult =
|
|
6
13
|
/** The next page is at this URL (the runner already navigated in web mode). */
|
|
@@ -34,6 +41,12 @@ export interface StepRunner {
|
|
|
34
41
|
* `false` means it cannot, and the block fails the step like any error.
|
|
35
42
|
*/
|
|
36
43
|
rotate?: (error: BlockedError) => Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* A runner of its own for one parallel `forEach` iteration: a new tab in the
|
|
46
|
+
* same browser context (same cookies, its own page), disposed when the
|
|
47
|
+
* iteration ends. Web mode; an api runner is shared as it is.
|
|
48
|
+
*/
|
|
49
|
+
fork?: () => Promise<StepRunner>;
|
|
37
50
|
dispose: () => Promise<void>;
|
|
38
51
|
}
|
|
39
52
|
//# sourceMappingURL=step-runner.contract.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { EventBus } from '../crawl-events/index.js';
|
|
2
|
+
import type { RetryRule } from '../recipe-schema/index.js';
|
|
3
|
+
import type { RunGate } from './run-gate.policy.js';
|
|
4
|
+
/** A retry rule with every default filled in. */
|
|
5
|
+
export type ResolvedRetryRule = Required<RetryRule>;
|
|
6
|
+
/** Statuses a server uses for "not now": timeout, too early, too many requests, and the 5xx that pass. */
|
|
7
|
+
export declare const RETRY_STATUSES: readonly number[];
|
|
8
|
+
/** Three tries, one second then two apart, never a wait over 30 seconds. */
|
|
9
|
+
export declare const DEFAULT_RETRY_RULE: ResolvedRetryRule;
|
|
10
|
+
/** Why an attempt may be worth repeating, and the server's own `Retry-After`, if it sent one. */
|
|
11
|
+
export interface Transient {
|
|
12
|
+
reason: string;
|
|
13
|
+
retryAfter?: string;
|
|
14
|
+
}
|
|
15
|
+
/** One try of a request, and how to tell a passing failure in what it gave. */
|
|
16
|
+
export interface TransportAttempt<T> {
|
|
17
|
+
run: () => Promise<T>;
|
|
18
|
+
/** A transient problem in the outcome (a retry status, a connection error), or `undefined` when the outcome stands. */
|
|
19
|
+
problem: (outcome: {
|
|
20
|
+
value: T;
|
|
21
|
+
} | {
|
|
22
|
+
error: unknown;
|
|
23
|
+
}) => Transient | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface RetryContext {
|
|
26
|
+
recipeId: string;
|
|
27
|
+
gate: RunGate;
|
|
28
|
+
events: EventBus;
|
|
29
|
+
rule: ResolvedRetryRule;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The retry rule a recipe runs with: its `limits.retry` over the crawler's
|
|
33
|
+
* default over `DEFAULT_RETRY_RULE`.
|
|
34
|
+
*
|
|
35
|
+
* @param own - The recipe's `limits.retry`.
|
|
36
|
+
* @param crawler - The crawler's `retry` option.
|
|
37
|
+
* @returns The rule.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveRetryRule(own?: RetryRule, crawler?: RetryRule): ResolvedRetryRule;
|
|
40
|
+
/**
|
|
41
|
+
* Whether an error is a connection failure worth another try.
|
|
42
|
+
*
|
|
43
|
+
* @param error - What the request threw.
|
|
44
|
+
* @returns The reason, or `undefined`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function transientError(error: unknown): Transient | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* How long to wait before attempt `attempt + 1`: the server's `Retry-After`
|
|
49
|
+
* when it gave one, else `backoffMs` doubling per attempt with a little
|
|
50
|
+
* jitter; `undefined` when the server asks for longer than `maxDelayMs` (it
|
|
51
|
+
* means "come back much later", which a crawl cannot wait for).
|
|
52
|
+
*
|
|
53
|
+
* @param rule - The retry rule.
|
|
54
|
+
* @param attempt - The attempt that just failed, from 1.
|
|
55
|
+
* @param retryAfter - The `Retry-After` header: seconds, or an HTTP date.
|
|
56
|
+
* @param now - The current time, for dates.
|
|
57
|
+
* @returns Milliseconds, or `undefined` for no retry.
|
|
58
|
+
*/
|
|
59
|
+
export declare function retryDelay(rule: ResolvedRetryRule, attempt: number, retryAfter?: string, now?: number): number | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Sends a request through the gate (the recipe's rate, the site's lane), and
|
|
62
|
+
* sends it again after a pause while it fails in a passing way, up to
|
|
63
|
+
* `rule.attempts` tries in all. A `Retry-After` holds back every request to
|
|
64
|
+
* that site, not only this one. Each retry is reported as `request:retry`.
|
|
65
|
+
*
|
|
66
|
+
* Like redialling a busy number: wait a moment, dial again, give up after a
|
|
67
|
+
* few tries; and if the other end said "call back in a minute", wait that minute.
|
|
68
|
+
*
|
|
69
|
+
* @param url - Where the request goes.
|
|
70
|
+
* @param attempt - How to send it and how to judge the outcome.
|
|
71
|
+
* @param context - The recipe, gate, events and rule.
|
|
72
|
+
* @returns What the last try gave.
|
|
73
|
+
* @throws What the last try threw.
|
|
74
|
+
*/
|
|
75
|
+
export declare function withTransportRetry<T>(url: string, attempt: TransportAttempt<T>, context: RetryContext): Promise<T>;
|
|
76
|
+
//# sourceMappingURL=transport-retry.policy.d.ts.map
|
|
@@ -5,8 +5,9 @@ import type { GotoStep, InputRecipe } from '../recipe-schema/index.js';
|
|
|
5
5
|
import type { RunGate } from '../step-flow/index.js';
|
|
6
6
|
/**
|
|
7
7
|
* Runs a `goto` step: renders the URL (relative to the current page), waits for
|
|
8
|
-
* the gate's throttle (`delayMs`), navigates,
|
|
9
|
-
*
|
|
8
|
+
* the gate's throttle (`delayMs`), navigates (again, after a pause, while it
|
|
9
|
+
* fails in passing: `limits.retry`), records the page's real URL in the scope,
|
|
10
|
+
* and checks the response against the recipe's block rule.
|
|
10
11
|
*
|
|
11
12
|
* @throws BlockedError when the response is a block.
|
|
12
13
|
*/
|