@opencraw/core 0.1.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.
Files changed (114) hide show
  1. package/README.md +67 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.esm.js +5302 -0
  4. package/dist/src/access/access-broker.use-case.d.ts +43 -0
  5. package/dist/src/access/access-config.error.d.ts +5 -0
  6. package/dist/src/access/access-config.repository.d.ts +11 -0
  7. package/dist/src/access/access-json-schema.mapper.d.ts +8 -0
  8. package/dist/src/access/access-plugin.contract.d.ts +48 -0
  9. package/dist/src/access/access-preset.store.d.ts +19 -0
  10. package/dist/src/access/access-profile.contract.d.ts +91 -0
  11. package/dist/src/access/index.d.ts +11 -0
  12. package/dist/src/access/render-access.mapper.d.ts +41 -0
  13. package/dist/src/access/session-id.algorithm.d.ts +8 -0
  14. package/dist/src/api-steps/extract-from-document.use-case.d.ts +27 -0
  15. package/dist/src/api-steps/index.d.ts +4 -0
  16. package/dist/src/api-steps/run-api-step.use-case.d.ts +20 -0
  17. package/dist/src/api-steps/send-request.use-case.d.ts +22 -0
  18. package/dist/src/browser-session/browser-session.config.d.ts +21 -0
  19. package/dist/src/browser-session/browser.client.d.ts +67 -0
  20. package/dist/src/browser-session/index.d.ts +5 -0
  21. package/dist/src/crawl-events/crawl-event.contract.d.ts +120 -0
  22. package/dist/src/crawl-events/event-bus.store.d.ts +10 -0
  23. package/dist/src/crawl-events/index.d.ts +4 -0
  24. package/dist/src/crawl-events/trace-line.mapper.d.ts +14 -0
  25. package/dist/src/crawl-execution/bootstrap-session.use-case.d.ts +55 -0
  26. package/dist/src/crawl-execution/crawl-options.config.d.ts +37 -0
  27. package/dist/src/crawl-execution/crawl-report.model.d.ts +25 -0
  28. package/dist/src/crawl-execution/create-crawler.use-case.d.ts +19 -0
  29. package/dist/src/crawl-execution/index.d.ts +8 -0
  30. package/dist/src/crawl-execution/rotating-runner.use-case.d.ts +57 -0
  31. package/dist/src/crawl-execution/run-crawl.use-case.d.ts +13 -0
  32. package/dist/src/crawl-execution/run-input-recipe.use-case.d.ts +40 -0
  33. package/dist/src/extraction-scope/extraction-scope.model.d.ts +73 -0
  34. package/dist/src/extraction-scope/index.d.ts +5 -0
  35. package/dist/src/extraction-scope/live-element.model.d.ts +28 -0
  36. package/dist/src/hooks/hook-registry.store.d.ts +16 -0
  37. package/dist/src/hooks/hook.contract.d.ts +17 -0
  38. package/dist/src/hooks/hook.error.d.ts +7 -0
  39. package/dist/src/hooks/index.d.ts +4 -0
  40. package/dist/src/http-session/http-response.contract.d.ts +44 -0
  41. package/dist/src/http-session/http.client.d.ts +42 -0
  42. package/dist/src/http-session/index.d.ts +5 -0
  43. package/dist/src/index.d.ts +24 -0
  44. package/dist/src/output-mapping/coerce-field.mapper.d.ts +19 -0
  45. package/dist/src/output-mapping/generated-field.mapper.d.ts +16 -0
  46. package/dist/src/output-mapping/index.d.ts +9 -0
  47. package/dist/src/output-mapping/map-record.use-case.d.ts +27 -0
  48. package/dist/src/output-mapping/mapping.error.d.ts +17 -0
  49. package/dist/src/output-mapping/missing-value.policy.d.ts +14 -0
  50. package/dist/src/output-mapping/output-field.validator.d.ts +10 -0
  51. package/dist/src/output-mapping/output-record.model.d.ts +20 -0
  52. package/dist/src/recipe-loading/index.d.ts +9 -0
  53. package/dist/src/recipe-loading/load-recipe-set.use-case.d.ts +45 -0
  54. package/dist/src/recipe-loading/read-recipe-source.use-case.d.ts +14 -0
  55. package/dist/src/recipe-loading/recipe-binding.error.d.ts +14 -0
  56. package/dist/src/recipe-loading/recipe-binding.validator.d.ts +32 -0
  57. package/dist/src/recipe-loading/recipe-file.repository.d.ts +11 -0
  58. package/dist/src/recipe-loading/recipe-set.model.d.ts +12 -0
  59. package/dist/src/recipe-loading/recipe-source.contract.d.ts +28 -0
  60. package/dist/src/recipe-loading/recipe-text.mapper.d.ts +14 -0
  61. package/dist/src/recipe-schema/index.d.ts +15 -0
  62. package/dist/src/recipe-schema/input-recipe.contract.d.ts +103 -0
  63. package/dist/src/recipe-schema/json-schema.mapper.d.ts +15 -0
  64. package/dist/src/recipe-schema/output-recipe.contract.d.ts +47 -0
  65. package/dist/src/recipe-schema/recipe-kind.enum.d.ts +31 -0
  66. package/dist/src/recipe-schema/recipe-validation.error.d.ts +17 -0
  67. package/dist/src/recipe-schema/recipe.validator.d.ts +28 -0
  68. package/dist/src/recipe-schema/step.contract.d.ts +152 -0
  69. package/dist/src/recipe-schema/transform-rule.contract.d.ts +120 -0
  70. package/dist/src/record-sink/dedupe.policy.d.ts +17 -0
  71. package/dist/src/record-sink/index.d.ts +8 -0
  72. package/dist/src/record-sink/json-lines-sink.repository.d.ts +19 -0
  73. package/dist/src/record-sink/memory-sink.repository.d.ts +9 -0
  74. package/dist/src/record-sink/record-sink.contract.d.ts +17 -0
  75. package/dist/src/selection/html-selector.algorithm.d.ts +18 -0
  76. package/dist/src/selection/index.d.ts +8 -0
  77. package/dist/src/selection/json-path.algorithm.d.ts +9 -0
  78. package/dist/src/selection/json-text.algorithm.d.ts +31 -0
  79. package/dist/src/selection/regex.algorithm.d.ts +12 -0
  80. package/dist/src/selection/take-value.mapper.d.ts +27 -0
  81. package/dist/src/step-flow/block-rule.policy.d.ts +21 -0
  82. package/dist/src/step-flow/blocked.error.d.ts +9 -0
  83. package/dist/src/step-flow/for-each.use-case.d.ts +18 -0
  84. package/dist/src/step-flow/index.d.ts +10 -0
  85. package/dist/src/step-flow/paginate.use-case.d.ts +17 -0
  86. package/dist/src/step-flow/retry.policy.d.ts +21 -0
  87. package/dist/src/step-flow/run-gate.policy.d.ts +39 -0
  88. package/dist/src/step-flow/run-steps.use-case.d.ts +39 -0
  89. package/dist/src/step-flow/step-failure.error.d.ts +14 -0
  90. package/dist/src/step-flow/step-runner.contract.d.ts +39 -0
  91. package/dist/src/template/expression.algorithm.d.ts +53 -0
  92. package/dist/src/template/index.d.ts +7 -0
  93. package/dist/src/template/template.algorithm.d.ts +53 -0
  94. package/dist/src/template/value-path.algorithm.d.ts +29 -0
  95. package/dist/src/template/value-text.algorithm.d.ts +18 -0
  96. package/dist/src/transformation/apply-transform-chain.use-case.d.ts +17 -0
  97. package/dist/src/transformation/collection.algorithm.d.ts +15 -0
  98. package/dist/src/transformation/currency.algorithm.d.ts +15 -0
  99. package/dist/src/transformation/date.algorithm.d.ts +13 -0
  100. package/dist/src/transformation/index.d.ts +10 -0
  101. package/dist/src/transformation/lookup.algorithm.d.ts +24 -0
  102. package/dist/src/transformation/number.algorithm.d.ts +30 -0
  103. package/dist/src/transformation/string.algorithm.d.ts +18 -0
  104. package/dist/src/transformation/transform-registry.store.d.ts +36 -0
  105. package/dist/src/transformation/transform.error.d.ts +8 -0
  106. package/dist/src/transformation/url.algorithm.d.ts +20 -0
  107. package/dist/src/web-steps/evaluate-script.use-case.d.ts +10 -0
  108. package/dist/src/web-steps/extract-from-page.use-case.d.ts +10 -0
  109. package/dist/src/web-steps/index.d.ts +2 -0
  110. package/dist/src/web-steps/interact.use-case.d.ts +36 -0
  111. package/dist/src/web-steps/navigate.use-case.d.ts +14 -0
  112. package/dist/src/web-steps/run-web-step.use-case.d.ts +22 -0
  113. package/dist/src/web-steps/snapshot-elements.use-case.d.ts +13 -0
  114. package/package.json +75 -0
@@ -0,0 +1,43 @@
1
+ import type { AccessLease, AccessPlugin, LeaseRequest } from './access-plugin.contract.js';
2
+ type Env = Record<string, string | undefined>;
3
+ /**
4
+ * Turns the runner's access config into leases: one per recipe run, shared by
5
+ * its bootstrap and its runner, and a new one on every rotation. The config is
6
+ * checked when the broker is built (profiles, presets, their parameters,
7
+ * plugin names); environment variables are checked when a profile is leased,
8
+ * so a config listing several providers only needs the variables of the one in
9
+ * use.
10
+ */
11
+ export declare class AccessBroker {
12
+ private readonly env;
13
+ private readonly config;
14
+ private readonly plugins;
15
+ private readonly poolCursor;
16
+ /**
17
+ * @param config - The access config; none means every recipe goes direct.
18
+ * @param plugins - Plugins `{ kind: 'plugin' }` profiles may name.
19
+ * @param env - Where `{{env.X}}` reads from; the process environment by default.
20
+ * @throws AccessConfigError when the config cannot work.
21
+ */
22
+ constructor(config?: unknown, plugins?: readonly AccessPlugin[], env?: Env);
23
+ /** The profile names, for messages and tools. */
24
+ get profileNames(): string[];
25
+ /**
26
+ * A lease for one recipe run.
27
+ *
28
+ * @param request - The recipe, the profile it asks for, country and stickiness.
29
+ * @returns How the run reaches the network.
30
+ * @throws AccessConfigError for an unknown profile or a missing environment variable.
31
+ */
32
+ lease(request: LeaseRequest): Promise<AccessLease>;
33
+ }
34
+ /**
35
+ * An endpoint as events may show it: scheme, host and path, without the
36
+ * credentials or tokens remote-browser URLs carry.
37
+ *
38
+ * @param endpoint - A proxy server or CDP endpoint.
39
+ * @returns The redacted form.
40
+ */
41
+ export declare function redactEndpoint(endpoint: string): string;
42
+ export {};
43
+ //# sourceMappingURL=access-broker.use-case.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** An access config that cannot work: a bad profile, an unknown preset or plugin, a missing parameter or environment variable. */
2
+ export declare class AccessConfigError extends Error {
3
+ readonly name = "AccessConfigError";
4
+ }
5
+ //# sourceMappingURL=access-config.error.d.ts.map
@@ -0,0 +1,11 @@
1
+ import type { AccessConfig } from './access-profile.contract.js';
2
+ /**
3
+ * Reads an access config file. Secrets stay out of it: profiles reference
4
+ * them as `{{env.NAME}}`, resolved when a profile is leased.
5
+ *
6
+ * @param path - A JSON file.
7
+ * @returns The validated config.
8
+ * @throws AccessConfigError when the file is not JSON or not a valid config.
9
+ */
10
+ export declare function loadAccessConfig(path: string): Promise<AccessConfig>;
11
+ //# sourceMappingURL=access-config.repository.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The JSON Schema for access config files, for editors: point `$schema` at
3
+ * `schemas/access-config.schema.json`.
4
+ *
5
+ * @returns A draft 2020-12 document.
6
+ */
7
+ export declare function accessConfigJsonSchema(): Record<string, unknown>;
8
+ //# sourceMappingURL=access-json-schema.mapper.d.ts.map
@@ -0,0 +1,48 @@
1
+ import type { BlockableResource, ProxySettings } from './access-profile.contract.js';
2
+ /** What a recipe run asks the access layer for. */
3
+ export interface LeaseRequest {
4
+ recipeId: string;
5
+ /** The profile to use; the config's default when omitted, `direct` when there is none. */
6
+ profile?: string;
7
+ /** ISO country code the recipe wants its traffic to come from. */
8
+ country?: string;
9
+ /** Overrides the profile's `session.rotate`: `true` keeps one IP for the run, `false` lets the provider rotate. */
10
+ sticky?: boolean;
11
+ /** 1 for the first lease of a run, higher after a rotation. */
12
+ attempt?: number;
13
+ }
14
+ /** How one recipe run reaches the network: applied to its browser context, its HTTP context and its bootstrap alike. */
15
+ export interface AccessLease {
16
+ profile: string;
17
+ kind: string;
18
+ proxy?: ProxySettings;
19
+ /** The sticky session id, when the lease has one. */
20
+ session?: string;
21
+ headers?: Record<string, string>;
22
+ ignoreHTTPSErrors?: boolean;
23
+ blockResources?: BlockableResource[];
24
+ /** A remote browser to connect to instead of launching one (web recipes and bootstraps only). */
25
+ cdp?: {
26
+ endpoint: string;
27
+ headers?: Record<string, string>;
28
+ };
29
+ /** Called when the run ends or rotates away from this lease. */
30
+ release?: () => Promise<void>;
31
+ }
32
+ /** What a plugin receives: the request plus its profile's options, every string rendered. */
33
+ export interface PluginLeaseRequest extends LeaseRequest {
34
+ profile: string;
35
+ options: Record<string, unknown>;
36
+ attempt: number;
37
+ }
38
+ /**
39
+ * The extension point for access that config cannot express: a remote browser
40
+ * whose URL comes from a REST call, a proxy list fetched from an API, a
41
+ * rotating credential. Registered on the crawler, referenced by name from a
42
+ * `{ kind: 'plugin', name }` profile.
43
+ */
44
+ export interface AccessPlugin {
45
+ name: string;
46
+ lease: (request: PluginLeaseRequest) => Promise<Omit<AccessLease, 'profile' | 'kind'>> | Omit<AccessLease, 'profile' | 'kind'>;
47
+ }
48
+ //# sourceMappingURL=access-plugin.contract.d.ts.map
@@ -0,0 +1,19 @@
1
+ import type { ProxyProfile } from './access-profile.contract.js';
2
+ /**
3
+ * Provider presets. Providers all speak plain HTTP proxy with basic auth; they
4
+ * differ in where targeting and session tokens go (username, password, headers)
5
+ * and in whether they intercept HTTPS. A preset is only that knowledge, as
6
+ * templates: adding a provider is adding an entry here, never code.
7
+ *
8
+ * Templates read `params.*` (the profile's parameters, which may themselves
9
+ * read `env.*`), `country` and `session` (absent when the lease is not sticky).
10
+ */
11
+ export interface AccessPreset {
12
+ /** One line for docs and error messages. */
13
+ description: string;
14
+ /** `params` the profile must set. */
15
+ requiredParams: string[];
16
+ profile: Omit<ProxyProfile, 'kind' | 'preset' | 'params'>;
17
+ }
18
+ export declare const ACCESS_PRESETS: Record<string, AccessPreset>;
19
+ //# sourceMappingURL=access-preset.store.d.ts.map
@@ -0,0 +1,91 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Where a crawl's traffic goes. Profiles live in the runner's access config,
4
+ * never in a recipe: they hold the user's accounts. Every string may use
5
+ * `{{ }}` templates over `env.*` (the process environment), `params.*` (the
6
+ * profile's own parameters), `session`, `country` and `recipe.id`.
7
+ */
8
+ /** A proxy in Playwright's shape; used for browser contexts and HTTP request contexts alike. */
9
+ export interface ProxySettings {
10
+ server: string;
11
+ username?: string;
12
+ password?: string;
13
+ /** Comma-separated hosts that skip the proxy. */
14
+ bypass?: string;
15
+ }
16
+ /** Resource types a page may skip loading, to save bandwidth on per-GB proxies. */
17
+ export declare const BLOCKABLE_RESOURCES: readonly ["image", "media", "font", "stylesheet", "script", "texttrack", "xhr", "fetch", "eventsource", "websocket", "manifest", "other"];
18
+ export type BlockableResource = typeof BLOCKABLE_RESOURCES[number];
19
+ /** How a sticky session id is generated: character class and length, such as `alnum8` or `digits6`. */
20
+ export declare const SESSION_ID_FORMAT: RegExp;
21
+ export interface ProxySessionSettings {
22
+ /** Default `alnum10`. Providers constrain it: IPRoyal wants exactly 8 characters, NetNut digits. */
23
+ idFormat?: string;
24
+ /** `per-recipe` (default): one sticky session per recipe run. `per-request`: no session id, the provider rotates. */
25
+ rotate?: 'per-recipe' | 'per-request';
26
+ }
27
+ interface ProfileCommon {
28
+ /** Headers sent with every request: provider controls such as `x-oxylabs-geo-location`. Templates allowed; empty values are dropped. */
29
+ headers?: Record<string, string>;
30
+ /** Needed by providers that intercept HTTPS (unblockers, Bright Data residential). */
31
+ ignoreHTTPSErrors?: boolean;
32
+ /** Resource types pages skip (web mode). */
33
+ blockResources?: BlockableResource[];
34
+ }
35
+ export interface DirectProfile {
36
+ kind: 'direct';
37
+ }
38
+ export interface ProxyProfile extends ProfileCommon {
39
+ kind: 'proxy';
40
+ /** A built-in preset that fills `server`, `username`, `password`, `headers` and defaults; explicit fields override it. */
41
+ preset?: string;
42
+ /** Values the preset's templates read as `params.*`. */
43
+ params?: Record<string, string>;
44
+ server?: string;
45
+ username?: string;
46
+ password?: string;
47
+ bypass?: string;
48
+ session?: ProxySessionSettings;
49
+ }
50
+ export interface PoolProfile extends ProfileCommon {
51
+ kind: 'pool';
52
+ proxies: ProxySettings[];
53
+ /** Default `round-robin`. The pool advances per lease: per recipe run, and on every rotation. */
54
+ rotate?: 'round-robin' | 'random';
55
+ }
56
+ /**
57
+ * A remote browser reached over the Chrome DevTools Protocol (Bright Data
58
+ * Browser API, Browserless, Oxylabs, Zyte...): web recipes and bootstraps run
59
+ * in it, and it handles IPs, fingerprints and challenges. Api recipes cannot
60
+ * use it.
61
+ */
62
+ export interface CdpProfile {
63
+ kind: 'cdp';
64
+ /** `wss://...` or `http://host:port`; a template, usually carrying the token or credentials. */
65
+ endpoint: string;
66
+ /** Headers sent with the connection, such as `Authorization`. Templates. */
67
+ headers?: Record<string, string>;
68
+ params?: Record<string, string>;
69
+ session?: {
70
+ idFormat?: string;
71
+ };
72
+ blockResources?: BlockableResource[];
73
+ }
74
+ export interface PluginProfile {
75
+ kind: 'plugin';
76
+ /** The name an `AccessPlugin` was registered under. */
77
+ name: string;
78
+ /** Passed to the plugin with every string rendered. */
79
+ options?: Record<string, unknown>;
80
+ }
81
+ export type AccessProfile = DirectProfile | ProxyProfile | PoolProfile | CdpProfile | PluginProfile;
82
+ /** The runner's access config: named profiles and the one used when a recipe names none. */
83
+ export interface AccessConfig {
84
+ $schema?: string;
85
+ profiles: Record<string, AccessProfile>;
86
+ default?: string;
87
+ }
88
+ export declare const accessProfileSchema: z.ZodType<AccessProfile>;
89
+ export declare const accessConfigSchema: z.ZodType<AccessConfig>;
90
+ export {};
91
+ //# sourceMappingURL=access-profile.contract.d.ts.map
@@ -0,0 +1,11 @@
1
+ export { AccessBroker, redactEndpoint } from './access-broker.use-case.js';
2
+ export { loadAccessConfig } from './access-config.repository.js';
3
+ export { AccessConfigError } from './access-config.error.js';
4
+ export { ACCESS_PRESETS } from './access-preset.store.js';
5
+ export type { AccessPreset } from './access-preset.store.js';
6
+ export { accessConfigSchema, accessProfileSchema, BLOCKABLE_RESOURCES } from './access-profile.contract.js';
7
+ export type { AccessConfig, AccessProfile, ProxyProfile, PoolProfile, CdpProfile, PluginProfile, DirectProfile, ProxySettings, BlockableResource } from './access-profile.contract.js';
8
+ export type { AccessPlugin, AccessLease, LeaseRequest, PluginLeaseRequest } from './access-plugin.contract.js';
9
+ export { newSessionId } from './session-id.algorithm.js';
10
+ export { accessConfigJsonSchema } from './access-json-schema.mapper.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,41 @@
1
+ /** What access templates can read. */
2
+ export interface AccessTemplateContext {
3
+ env: Record<string, string | undefined>;
4
+ params?: Record<string, string>;
5
+ session?: string;
6
+ country?: string;
7
+ recipe?: {
8
+ id: string;
9
+ };
10
+ }
11
+ /**
12
+ * Renders one access template. An `env.*` path that is not set fails loudly:
13
+ * an empty password would otherwise reach the provider and fail as a 407.
14
+ *
15
+ * @param template - The text.
16
+ * @param context - What `{{ }}` can read.
17
+ * @param where - The profile field, for the error.
18
+ * @returns The rendered text.
19
+ * @throws AccessConfigError naming the missing environment variable.
20
+ */
21
+ export declare function renderAccessText(template: string, context: AccessTemplateContext, where: string): string;
22
+ /**
23
+ * Renders every string inside a value, keeping its shape.
24
+ *
25
+ * @param value - Plugin options, a header map...
26
+ * @param context - What `{{ }}` can read.
27
+ * @param where - For errors.
28
+ * @returns The rendered copy.
29
+ */
30
+ export declare function renderAccessDeep(value: unknown, context: AccessTemplateContext, where: string): unknown;
31
+ /**
32
+ * Renders a header map and drops headers that render empty, so a template
33
+ * such as `{{country ? upper(country) : ''}}` can leave a header out.
34
+ *
35
+ * @param headers - The templated headers.
36
+ * @param context - What `{{ }}` can read.
37
+ * @param where - For errors.
38
+ * @returns The headers to send, or `undefined` when none remain.
39
+ */
40
+ export declare function renderHeaders(headers: Record<string, string> | undefined, context: AccessTemplateContext, where: string): Record<string, string> | undefined;
41
+ //# sourceMappingURL=render-access.mapper.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A new random session id in a provider's format.
3
+ *
4
+ * @param format - `alnum8`, `digits6`, `hex16`...
5
+ * @returns The id. A `digits` id never starts with 0, so providers that read it as a number keep its length.
6
+ */
7
+ export declare function newSessionId(format?: string): string;
8
+ //# sourceMappingURL=session-id.algorithm.d.ts.map
@@ -0,0 +1,27 @@
1
+ import type { ExtractionScope } from '../extraction-scope/index.js';
2
+ import type { ExtractStep } from '../recipe-schema/index.js';
3
+ /**
4
+ * Runs an `extract` step against a static document: the value bound under
5
+ * `from`, else the scope's current document. `css` reads HTML, `jsonpath`
6
+ * reads JSON; `xpath` needs a live page and is refused here.
7
+ *
8
+ * A `jsonpath` extract whose `from` is text parses that text as JSON, and a
9
+ * list of texts (every `<script type="application/ld+json">` of a page) becomes
10
+ * an array of the entries that parse, so `$[*].actors[*].name` finds the block
11
+ * that has actors wherever it sits.
12
+ *
13
+ * @param step - The extract step.
14
+ * @param scope - Where the document and the result live.
15
+ * @throws NoMatchError when a single extract matches nothing.
16
+ */
17
+ export declare function extractFromDocument(step: ExtractStep, scope: ExtractionScope): void;
18
+ /**
19
+ * A selector may carry `{{ }}` placeholders (a trim name, an id): they render
20
+ * against the scope before the selector runs.
21
+ *
22
+ * @param selector - The recipe's selector.
23
+ * @param scope - The current scope.
24
+ * @returns The selector to run.
25
+ */
26
+ export declare function renderSelector(selector: string, scope: ExtractionScope): string;
27
+ //# sourceMappingURL=extract-from-document.use-case.d.ts.map
@@ -0,0 +1,4 @@
1
+ export { ApiStepRunner } from './run-api-step.use-case.js';
2
+ export { extractFromDocument, renderSelector } from './extract-from-document.use-case.js';
3
+ export { sendRequest, documentValue } from './send-request.use-case.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,20 @@
1
+ import type { EventBus } from '../crawl-events/index.js';
2
+ import type { ExtractionScope } from '../extraction-scope/index.js';
3
+ import type { HttpSender } from '../http-session/index.js';
4
+ import type { InputRecipe, PaginateNext, Step } from '../recipe-schema/index.js';
5
+ import { RunGate } from '../step-flow/index.js';
6
+ import type { NextPageResult, StepRunner } from '../step-flow/index.js';
7
+ /** Runs api-mode leaf steps against an HTTP sender. */
8
+ export declare class ApiStepRunner implements StepRunner {
9
+ private readonly client;
10
+ private readonly recipe;
11
+ private readonly events;
12
+ private readonly gate;
13
+ constructor(client: HttpSender & {
14
+ dispose?: () => Promise<void>;
15
+ }, recipe: InputRecipe, events: EventBus, gate?: RunGate);
16
+ runLeaf(step: Step, scope: ExtractionScope): Promise<void>;
17
+ nextPage(next: PaginateNext, scope: ExtractionScope): Promise<NextPageResult>;
18
+ dispose(): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=run-api-step.use-case.d.ts.map
@@ -0,0 +1,22 @@
1
+ import type { EventBus } from '../crawl-events/index.js';
2
+ import type { ExtractionScope } from '../extraction-scope/index.js';
3
+ import type { HttpBody, HttpSender } from '../http-session/index.js';
4
+ import type { InputRecipe, RequestStep } from '../recipe-schema/index.js';
5
+ import type { RunGate } from '../step-flow/index.js';
6
+ /**
7
+ * Sends a `request` step: renders its templates, waits for the gate's throttle,
8
+ * sends, checks the response against the recipe's block rule, then binds it as
9
+ * the scope's current document (and under the step id).
10
+ *
11
+ * @param step - The request step.
12
+ * @param scope - The scope to render in and bind into.
13
+ * @param client - The HTTP sender.
14
+ * @param recipe - The recipe: its limits, block rule and id.
15
+ * @param gate - Spaces request starts by `delayMs`.
16
+ * @param events - Where to report the visit.
17
+ * @throws BlockedError when the response is a block; HttpError for any other 4xx/5xx.
18
+ */
19
+ export declare function sendRequest(step: RequestStep, scope: ExtractionScope, client: HttpSender, recipe: InputRecipe, gate: RunGate, events: EventBus): Promise<void>;
20
+ /** What a step id holds for a document: parsed JSON, or the markup / text. */
21
+ export declare function documentValue(body: HttpBody): unknown;
22
+ //# sourceMappingURL=send-request.use-case.d.ts.map
@@ -0,0 +1,21 @@
1
+ /** How the browser is launched. Everything is optional; the default is headless chromium. */
2
+ export interface BrowserSessionConfig {
3
+ browserType?: 'chromium' | 'firefox' | 'webkit';
4
+ /** Default `true`. */
5
+ headless?: boolean;
6
+ /** Milliseconds added to every action, for watching a crawl. */
7
+ slowMo?: number;
8
+ /** A browser binary other than the one `playwright install` fetched. */
9
+ executablePath?: string;
10
+ proxy?: {
11
+ server: string;
12
+ username?: string;
13
+ password?: string;
14
+ bypass?: string;
15
+ };
16
+ /** Default navigation and action timeout in milliseconds. */
17
+ timeoutMs?: number;
18
+ ignoreHTTPSErrors?: boolean;
19
+ }
20
+ export declare const DEFAULT_BROWSER_CONFIG: Required<Pick<BrowserSessionConfig, 'browserType' | 'headless'>>;
21
+ //# sourceMappingURL=browser-session.config.d.ts.map
@@ -0,0 +1,67 @@
1
+ import type { BrowserContext, Page } from 'playwright';
2
+ import type { BrowserSessionConfig } from './browser-session.config.js';
3
+ /** Playwright's storage state: cookies plus per-origin local storage. */
4
+ export type StorageState = Awaited<ReturnType<BrowserContext['storageState']>>;
5
+ /** What a session starts from. */
6
+ export interface SessionOptions {
7
+ storageState?: StorageState;
8
+ cookies?: Parameters<BrowserContext['addCookies']>[0];
9
+ headers?: Record<string, string>;
10
+ userAgent?: string;
11
+ viewport?: {
12
+ width: number;
13
+ height: number;
14
+ };
15
+ /** A proxy for this context only; overrides the launch-level `proxy`. */
16
+ proxy?: {
17
+ server: string;
18
+ username?: string;
19
+ password?: string;
20
+ bypass?: string;
21
+ };
22
+ /** Also accept invalid certificates in this context (a proxy that intercepts HTTPS). */
23
+ ignoreHTTPSErrors?: boolean;
24
+ /** Resource types this context never loads (`image`, `font`, `media`...), to save proxy bandwidth. */
25
+ blockResources?: readonly string[];
26
+ }
27
+ /** One browser context with one page: the unit a recipe runs in. */
28
+ export declare class BrowserSession {
29
+ readonly context: BrowserContext;
30
+ readonly page: Page;
31
+ private readonly closer?;
32
+ /**
33
+ * @param context - The browser context.
34
+ * @param page - Its page.
35
+ * @param closer - How to end the session; closing the context by default. A remote browser disconnects instead.
36
+ */
37
+ constructor(context: BrowserContext, page: Page, closer?: (() => Promise<void>) | undefined);
38
+ /** The cookies and storage this session holds now, in the shape an HTTP client or a later run can reuse. */
39
+ storageState(): Promise<StorageState>;
40
+ close(): Promise<void>;
41
+ }
42
+ /** A launched browser; sessions are opened from it and closed independently. */
43
+ export declare class BrowserClient {
44
+ private readonly browser;
45
+ private readonly config;
46
+ static launch(config?: BrowserSessionConfig): Promise<BrowserClient>;
47
+ /**
48
+ * A session in a remote browser, over the Chrome DevTools Protocol. The
49
+ * provider's own context is reused when it offers one (several providers
50
+ * pin the proxy and fingerprint to it); cookies, headers, blocked resources
51
+ * and the viewport are applied to it. Closing the session disconnects,
52
+ * which ends it on the provider's side.
53
+ *
54
+ * @param cdp - The endpoint and connection headers.
55
+ * @param options - What the session starts from. `userAgent` cannot change on an existing context and is ignored.
56
+ * @param timeoutMs - For the connection and every action.
57
+ * @returns The session.
58
+ */
59
+ static connectOverCDP(cdp: {
60
+ endpoint: string;
61
+ headers?: Record<string, string>;
62
+ }, options?: SessionOptions, timeoutMs?: number): Promise<BrowserSession>;
63
+ private constructor();
64
+ newSession(options?: SessionOptions): Promise<BrowserSession>;
65
+ close(): Promise<void>;
66
+ }
67
+ //# sourceMappingURL=browser.client.d.ts.map
@@ -0,0 +1,5 @@
1
+ export { BrowserClient, BrowserSession } from './browser.client.js';
2
+ export type { StorageState, SessionOptions } from './browser.client.js';
3
+ export { DEFAULT_BROWSER_CONFIG } from './browser-session.config.js';
4
+ export type { BrowserSessionConfig } from './browser-session.config.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Everything a crawl reports while it runs. Payloads are structural on purpose:
3
+ * this slice is a leaf, so it declares its own shapes instead of importing the
4
+ * richer record and error types from the slices above it.
5
+ */
6
+ interface Base {
7
+ at: string;
8
+ recipeId: string;
9
+ }
10
+ export type CrawlEvent = (Base & {
11
+ type: 'recipe:start';
12
+ mode: 'web' | 'api';
13
+ }) | (Base & {
14
+ type: 'recipe:finish';
15
+ emitted: number;
16
+ rejected: number;
17
+ duplicates: number;
18
+ skipped: number;
19
+ pages: number;
20
+ durationMs: number;
21
+ error?: string;
22
+ }) |
23
+ /** `status` is the HTTP status of the navigation or request, when there was a response. */
24
+ (Base & {
25
+ type: 'page:visit';
26
+ url: string;
27
+ number: number;
28
+ status?: number;
29
+ }) |
30
+ /** How a recipe run reaches the network. Never carries credentials. */
31
+ (Base & {
32
+ type: 'access:lease';
33
+ profile: string;
34
+ kind: string;
35
+ server?: string;
36
+ session?: string;
37
+ }) |
38
+ /** A response matched the recipe's block rule. */
39
+ (Base & {
40
+ type: 'access:blocked';
41
+ url: string;
42
+ status: number;
43
+ reason: string;
44
+ }) |
45
+ /** The run gave up its access lease after a block and is taking a new one. */
46
+ (Base & {
47
+ type: 'access:rotate';
48
+ attempt: number;
49
+ reason: string;
50
+ }) | (Base & {
51
+ type: 'step:start';
52
+ stepType: string;
53
+ stepId?: string;
54
+ path: string;
55
+ }) | (Base & {
56
+ type: 'step:finish';
57
+ stepType: string;
58
+ stepId?: string;
59
+ path: string;
60
+ durationMs: number;
61
+ }) | (Base & {
62
+ type: 'step:retry';
63
+ stepType: string;
64
+ stepId?: string;
65
+ path: string;
66
+ attempt: number;
67
+ error: string;
68
+ }) | (Base & {
69
+ type: 'step:skip';
70
+ stepType: string;
71
+ stepId?: string;
72
+ path: string;
73
+ error: string;
74
+ }) | (Base & {
75
+ type: 'step:branch';
76
+ path: string;
77
+ branch: 'then' | 'else';
78
+ }) |
79
+ /** `scope` (the snapshot the record was mapped from) is present only under `CrawlOptions.debug`. */
80
+ (Base & {
81
+ type: 'record:emit';
82
+ url: string;
83
+ key: string | null;
84
+ data: Record<string, unknown>;
85
+ scope?: Record<string, unknown>;
86
+ }) | (Base & {
87
+ type: 'record:reject';
88
+ url: string;
89
+ field: string;
90
+ reason: string;
91
+ scope?: Record<string, unknown>;
92
+ }) | (Base & {
93
+ type: 'record:duplicate';
94
+ url: string;
95
+ key: string;
96
+ }) |
97
+ /** A resumed run found the key already in the sink. */
98
+ (Base & {
99
+ type: 'record:skipped';
100
+ url: string;
101
+ key: string;
102
+ }) | (Base & {
103
+ type: 'warning';
104
+ message: string;
105
+ meta?: Record<string, unknown>;
106
+ }) | (Base & {
107
+ type: 'error';
108
+ message: string;
109
+ meta?: Record<string, unknown>;
110
+ });
111
+ export type CrawlEventType = CrawlEvent['type'];
112
+ /** An event without its timestamp; the bus stamps `at`. */
113
+ export type CrawlEventInput = {
114
+ [K in CrawlEventType]: Omit<Extract<CrawlEvent, {
115
+ type: K;
116
+ }>, 'at'>;
117
+ }[CrawlEventType];
118
+ export type CrawlListener = (event: CrawlEvent) => void;
119
+ export {};
120
+ //# sourceMappingURL=crawl-event.contract.d.ts.map
@@ -0,0 +1,10 @@
1
+ import type { CrawlEventInput, CrawlListener } from './crawl-event.contract.js';
2
+ /** Fans crawl events out to listeners. A listener that throws never breaks the crawl. */
3
+ export declare class EventBus {
4
+ private readonly listeners;
5
+ constructor(listener?: CrawlListener);
6
+ /** @returns A function that removes the listener. */
7
+ subscribe(listener: CrawlListener): () => void;
8
+ emit(input: CrawlEventInput): void;
9
+ }
10
+ //# sourceMappingURL=event-bus.store.d.ts.map
@@ -0,0 +1,4 @@
1
+ export type { CrawlEvent, CrawlEventType, CrawlEventInput, CrawlListener } from './crawl-event.contract.js';
2
+ export { EventBus } from './event-bus.store.js';
3
+ export { traceLine, depthOf } from './trace-line.mapper.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,14 @@
1
+ import type { CrawlEvent } from './crawl-event.contract.js';
2
+ /**
3
+ * One line of a crawl trace: the route a recipe takes (pages visited, steps
4
+ * run, records produced, policies fired), indented by how deep in the step
5
+ * tree the event happened. `step:start` yields nothing; `step:finish` carries
6
+ * the duration, so every step prints once.
7
+ *
8
+ * @param event - Any crawl event.
9
+ * @returns The line, or `undefined` for events a trace does not show.
10
+ */
11
+ export declare function traceLine(event: CrawlEvent): string | undefined;
12
+ /** How deep a step path such as `steps.8.steps.2` or `steps.1.else.0` sits: one level per nested `steps` or `else`. */
13
+ export declare function depthOf(path: string): number;
14
+ //# sourceMappingURL=trace-line.mapper.d.ts.map