polite-crawler 0.1.1 → 0.1.3

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 (62) hide show
  1. package/README.md +1087 -15
  2. package/build/browser-CKRNbIDT.mjs +62 -0
  3. package/build/browser-CKRNbIDT.mjs.map +1 -0
  4. package/build/cli-daemon--cTmq0Z5.mjs +38 -0
  5. package/build/cli-daemon--cTmq0Z5.mjs.map +1 -0
  6. package/build/cli.mjs +1065 -123
  7. package/build/cli.mjs.map +1 -1
  8. package/build/daemon-DP4EqjFL.d.mts +3772 -0
  9. package/build/daemon-fZTE24P5.mjs +515 -0
  10. package/build/daemon-fZTE24P5.mjs.map +1 -0
  11. package/build/diff-NQcQqKe9.mjs +648 -0
  12. package/build/diff-NQcQqKe9.mjs.map +1 -0
  13. package/build/extract-ByFfc8Zk.mjs +1793 -0
  14. package/build/extract-ByFfc8Zk.mjs.map +1 -0
  15. package/build/hours.d.mts +26 -0
  16. package/build/hours.mjs +48 -1
  17. package/build/hours.mjs.map +1 -1
  18. package/build/{html-nWYFVsRU.d.mts → html-BACljlkf.d.mts} +8 -9
  19. package/build/{html-oNpGAHwi.mjs → html-DkQUAE_d.mjs} +18 -39
  20. package/build/html-DkQUAE_d.mjs.map +1 -0
  21. package/build/html.d.mts +2 -1
  22. package/build/html.mjs +3 -1
  23. package/build/index.d.mts +582 -12
  24. package/build/index.mjs +903 -6
  25. package/build/index.mjs.map +1 -0
  26. package/build/log-Dx-wXjJl.mjs +342 -0
  27. package/build/log-Dx-wXjJl.mjs.map +1 -0
  28. package/build/loopback-C_QYowSf.mjs +22 -0
  29. package/build/loopback-C_QYowSf.mjs.map +1 -0
  30. package/build/mcp.d.mts +164 -5
  31. package/build/mcp.mjs +1115 -42
  32. package/build/mcp.mjs.map +1 -1
  33. package/build/ollama-BJxkjny4.mjs +160 -0
  34. package/build/ollama-BJxkjny4.mjs.map +1 -0
  35. package/build/open-C4fhXJgD.mjs +4544 -0
  36. package/build/open-C4fhXJgD.mjs.map +1 -0
  37. package/build/{browser-gJ_h4AhB.mjs → render-C1CUraWF.mjs} +31 -74
  38. package/build/render-C1CUraWF.mjs.map +1 -0
  39. package/build/rolldown-runtime-D7D4PA-g.mjs +13 -0
  40. package/build/{open-DYZ7KL2A.mjs → runtime-JToRO63o.mjs} +986 -1657
  41. package/build/runtime-JToRO63o.mjs.map +1 -0
  42. package/build/transformers-BQMlaGj4.mjs +133 -0
  43. package/build/transformers-BQMlaGj4.mjs.map +1 -0
  44. package/build/urls-BHFeSyEK.mjs +62 -0
  45. package/build/urls-BHFeSyEK.mjs.map +1 -0
  46. package/build/urls-BTDSgDLC.d.mts +16 -0
  47. package/build/version-ntbY-6wh.mjs +38 -0
  48. package/build/version-ntbY-6wh.mjs.map +1 -0
  49. package/build/wacz-BFNG42Kt.mjs +275 -0
  50. package/build/wacz-BFNG42Kt.mjs.map +1 -0
  51. package/build/warc-CVS0t1fW.mjs +728 -0
  52. package/build/warc-CVS0t1fW.mjs.map +1 -0
  53. package/build/webbotauth-CjJdTAfE.mjs +568 -0
  54. package/build/webbotauth-CjJdTAfE.mjs.map +1 -0
  55. package/package.json +10 -2
  56. package/record.schema.json +15 -1
  57. package/build/browser-gJ_h4AhB.mjs.map +0 -1
  58. package/build/html-oNpGAHwi.mjs.map +0 -1
  59. package/build/open-DYZ7KL2A.mjs.map +0 -1
  60. package/build/open-eHcriTds.d.mts +0 -1499
  61. package/build/version-no12qgos.mjs +0 -11
  62. package/build/version-no12qgos.mjs.map +0 -1
@@ -1,1499 +0,0 @@
1
- import { n as Outcome } from "./classify-CrfyXcwo.mjs";
2
- import { r as Signals, t as AiInput } from "./signals-BHpy2xb2.mjs";
3
- import { f as PolicyOptions, o as HostStateStore, t as Clock } from "./politeness-yI3xBEx9.mjs";
4
- import { a as Robots } from "./robots-R-qaEBOb.mjs";
5
- import { Dispatcher } from "undici";
6
- import { LookupAddress, LookupAllOptions } from "node:dns";
7
- import { LookupFunction } from "node:net";
8
- //#region src/blobs.d.ts
9
- /**
10
- * A blob store keeps the bytes of each response, and the hash of the bytes is the key. The crawler
11
- * needs only these two operations, so an application can give its own store.
12
- */
13
- interface BlobStore {
14
- put(bytes: Uint8Array): Promise<{
15
- readonly hash: string;
16
- }>;
17
- get(hash: string): Promise<Uint8Array | undefined>;
18
- }
19
- /** These options change a file blob store. */
20
- interface FileBlobStoreOptions {
21
- /** When this value is true (the default), a blob is on the disk (`fsync`) before `put` finishes. */
22
- readonly sync?: boolean | undefined;
23
- }
24
- /**
25
- * This store keeps each blob in a file: `<dir>/ab/cd/abcd…`, where the name is the SHA-256 hash
26
- * of the bytes. These are its rules:
27
- *
28
- * - Equal bytes are written one time only. A file of the wrong size (a write that a crash cut) is
29
- * written again.
30
- * - A write goes to a temporary file with a random name, goes to the disk, and then gets its name.
31
- * A crash thus cannot leave half a blob under its name.
32
- * - Two writers can put the same bytes at the same time. When the rename of one fails because the
33
- * other was first, the put succeeds if the stored file has the same hash.
34
- * - The method `get` examines the hash of the bytes. A damaged file gets a new name
35
- * (`.damaged`), and `get` gives no bytes, so the crawler fetches the body again.
36
- */
37
- declare class FileBlobStore implements BlobStore {
38
- readonly dir: string;
39
- private readonly writing;
40
- private readonly sync;
41
- constructor(dir: string, options?: FileBlobStoreOptions);
42
- put(bytes: Uint8Array): Promise<{
43
- readonly hash: string;
44
- readonly existed: boolean;
45
- }>;
46
- /** This method tells if a file holds exactly the bytes of a hash. */
47
- private static holds;
48
- private write;
49
- get(hash: string): Promise<Uint8Array | undefined>;
50
- }
51
- //#endregion
52
- //#region src/render.d.ts
53
- /**
54
- * The renderer opens the headless browser only for a page that shows almost nothing without
55
- * JavaScript. The settings:
56
- *
57
- * - The default `chromium-headless-shell` of Playwright, the lighter build.
58
- * - One browser for many pages, and a new context for each page. Thus no cookie or storage goes
59
- * from one site to the next. A context has its own HTTP cache, so routing each request costs
60
- * no cache across sites.
61
- * - Each request of the page goes through a route, the first navigation too. The route refuses
62
- * images, fonts and media by their resource type. It asks `allowRequest` about each other
63
- * request, and it sends `headers` with it.
64
- * - Playwright routes only the first request of a redirect chain. Thus with `allowRequest`, the
65
- * route sends each request itself, follows each redirect itself and asks about each step. The
66
- * browser then gets each body whole, not as a stream.
67
- * - No download, no popup, no service worker and no dialog.
68
- * - A wait until the visible text stops growing, with a limit. Playwright discourages
69
- * `networkidle`. The text includes open shadow roots and the frames of the same origin.
70
- * - One deadline for the whole render: the navigation, the wait and the reading of the page.
71
- * - After a crash or a disconnection, the next page launches a new browser.
72
- * - The browser closes after two idle minutes. An idle Chromium holds hundreds of megabytes, so
73
- * it stays open only while pages need it. The open browser keeps the process alive, so a
74
- * script uses `close()` when it is done.
75
- */
76
- interface Rendered {
77
- readonly html: string;
78
- readonly finalUrl: string;
79
- readonly status: number | null;
80
- readonly headers: Readonly<Record<string, string>>;
81
- }
82
- /** These are the options of one render. */
83
- interface RenderOptions {
84
- readonly userAgent: string;
85
- /** This value is the deadline of the whole render, in milliseconds. */
86
- readonly timeoutMs: number;
87
- /** These headers go with each request of the page, for example the `From` header. */
88
- readonly headers?: Readonly<Record<string, string>> | undefined;
89
- /**
90
- * This function decides each request that the page makes, the first navigation included. When
91
- * it gives false, the browser does not send the request. The crawler uses it to apply the
92
- * egress policy and robots.txt to the requests of the page.
93
- */
94
- readonly allowRequest?: ((url: string) => Promise<boolean> | boolean) | undefined;
95
- /** This value is the maximum number of redirects of one request of the page. The default is 5, as for a plain fetch. */
96
- readonly maxRedirects?: number | undefined;
97
- /** When this signal aborts, the renderer stops the page: it closes the context, and the render rejects. */
98
- readonly signal?: AbortSignal | undefined;
99
- }
100
- interface Renderer {
101
- render(url: string, options: RenderOptions): Promise<Rendered>;
102
- close(): Promise<void>;
103
- }
104
- /** The reason of a `RenderRefused`. */
105
- type RefusedReason = "refused" | "download" | "scheme" | "browser";
106
- /**
107
- * This error tells that the renderer did not render the page, and that the page or the site is
108
- * not at fault. The reason is one of these:
109
- *
110
- * - `refused`: `allowRequest` refused the first navigation, a step of its redirects, or a later
111
- * navigation of the page that left it on an error page. `url` names the refused URL.
112
- * - `download`: the URL gives a file, not a page.
113
- * - `scheme`: the URL is not an http or https URL.
114
- * - `browser`: the renderer has no browser (`playwright-core` or its browser is not installed). The
115
- * crawler then renders no more pages, and gives each one the note at once.
116
- *
117
- * A crawler does not count this error as a failure of the host.
118
- */
119
- declare class RenderRefused extends Error {
120
- readonly reason: RefusedReason;
121
- /** This URL is the request that `allowRequest` or the limit of redirects refused, when the reason is `refused`. */
122
- readonly url: string | undefined;
123
- constructor(reason: RefusedReason, message: string, url?: string);
124
- }
125
- /** The text of the error when the optional package `playwright-core` is not installed. */
126
- declare const NO_PLAYWRIGHT = "rendering needs the package playwright-core and a browser: npm install playwright-core, then npx playwright-core install chromium-headless-shell. For the MCP server with npx, start it with npx -y -p polite-crawler -p playwright-core polite-crawler mcp";
127
- interface PlaywrightRenderer extends Renderer {
128
- /** This function tells if a browser is open. */
129
- readonly open: () => boolean;
130
- }
131
- declare const playwrightRenderer: (options?: {
132
- readonly idleMs?: number;
133
- /**
134
- * This function starts the browser: it gives a `Browser` of `playwright-core`. The default is
135
- * the headless shell of Playwright. The type names no type of `playwright-core`, so a program
136
- * with no `playwright-core` can check its types.
137
- */
138
- readonly launch?: (() => Promise<object>) | undefined;
139
- }) => PlaywrightRenderer;
140
- //#endregion
141
- //#region src/docs.d.ts
142
- /** This is one document, as an extractor gives it. */
143
- interface ExtractedDoc {
144
- readonly doc: string;
145
- readonly kind: string;
146
- readonly title: string;
147
- /** This text is the readable text. For a paper, it is the title and the abstract. */
148
- readonly text: string;
149
- readonly url: string | null;
150
- readonly meta: Readonly<Record<string, unknown>>;
151
- /** This rule chooses between the texts of two recipes. The default is `richest`: the longer text. */
152
- readonly merge?: "latest" | "richest" | undefined;
153
- /** When the extractor cut the text, this text is the whole text. The function `verify` looks for a quote here too. */
154
- readonly full_text?: string | undefined;
155
- }
156
- /** This is one version of a document: the document as one capture gave it. */
157
- interface DocInput extends ExtractedDoc {
158
- /** These ids are the capture records that this version came from. The first id names the version. */
159
- readonly captures: readonly string[];
160
- readonly ai_input?: AiInput | undefined;
161
- /** This id is the capture of the version. The default is the first id of `captures`. */
162
- readonly capture?: string | undefined;
163
- /** This time (ISO 8601) is the time of the fetch. The default is the time of the upsert. */
164
- readonly fetched_at?: string | undefined;
165
- readonly blob?: string | null | undefined;
166
- /** This value is the recipe that read the capture. A version with no recipe has the recipe `""`. */
167
- readonly recipe?: string | undefined;
168
- /** This value is true when the headless browser made the capture. */
169
- readonly rendered?: boolean | undefined;
170
- /** This label comes from the capture. The index writes it as it is and does not read it. */
171
- readonly scope?: string | undefined;
172
- /** These labels come from the capture. The index writes them as they are and does not read them. */
173
- readonly labels?: Readonly<Record<string, string>> | undefined;
174
- }
175
- /** This is the current version of a document. */
176
- interface Doc {
177
- readonly doc: string;
178
- readonly kind: string;
179
- readonly title: string;
180
- readonly text: string;
181
- readonly url: string | null;
182
- readonly meta: Readonly<Record<string, unknown>>;
183
- /** These ids are the captures behind the current text, the newest first, `MAX_CAPTURES` or fewer. */
184
- readonly captures: readonly string[];
185
- /** This value is the number of versions of the document. */
186
- readonly capture_count: number;
187
- /** This id is the capture of the current text. */
188
- readonly capture: string;
189
- readonly blob: string | null;
190
- /** This time (ISO 8601) is the fetch time of the current text. */
191
- readonly fetched_at: string;
192
- readonly recipe: string;
193
- readonly rendered: boolean;
194
- readonly ai_input: AiInput;
195
- /** This value is true when the extractor cut the text, and the index keeps the whole text for `verify`. */
196
- readonly cut: boolean;
197
- readonly scope?: string | undefined;
198
- readonly labels?: Readonly<Record<string, string>> | undefined;
199
- readonly updated_at: string;
200
- }
201
- /** This is one version of a document, with no text. */
202
- interface DocVersion {
203
- readonly doc: string;
204
- readonly capture: string;
205
- readonly recipe: string;
206
- readonly rendered: boolean;
207
- readonly fetched_at: string;
208
- readonly blob: string | null;
209
- readonly kind: string;
210
- readonly title: string;
211
- readonly url: string | null;
212
- readonly ai_input: AiInput;
213
- /** This value is the length of the text of the version. */
214
- readonly chars: number;
215
- /** This value is true when the index keeps a whole text that is longer than the text. */
216
- readonly cut: boolean;
217
- }
218
- /** This is the text of one version, with its metadata. */
219
- interface VersionText extends DocVersion {
220
- readonly text: string;
221
- /** This text is the whole text when the extractor cut `text`. */
222
- readonly full_text: string | undefined;
223
- readonly meta: Readonly<Record<string, unknown>>;
224
- }
225
- /**
226
- * This value chooses the ranking of a search:
227
- *
228
- * - `exact` (the default): BM25 ranks each document that matches.
229
- * - `fast`: the form of the query that needs one part leaves out the common parts. A common part
230
- * is in more than `FAST_RANK_SHARE` of the documents. The rarest part stays when each part is common.
231
- *
232
- * The documents that hold each part come first in the two modes, with the same rank. In the mode
233
- * `fast`, the rest of the results leaves out a document that holds only common parts. The common
234
- * parts also do not add to the score of the rest. Thus `fast` is faster for a long question, and
235
- * its results can be different. The README gives the measured difference.
236
- */
237
- type RankMode = "exact" | "fast";
238
- /** In the mode `fast`, a part is common when more than this share of the documents hold it. */
239
- declare const FAST_RANK_SHARE = .2;
240
- /** These are the options of a search of the index. */
241
- interface FindIndexOptions {
242
- /** This value is the maximum number of results. The index gives 1000 or fewer. */
243
- readonly limit: number;
244
- /** This value keeps only the documents of one kind, for example `page` or `pdf`. */
245
- readonly kind?: string | null | undefined;
246
- /** This value chooses the ranking. The default is `exact`. */
247
- readonly rank?: RankMode | undefined;
248
- }
249
- interface Found {
250
- readonly doc: string;
251
- readonly kind: string;
252
- readonly title: string;
253
- readonly url: string | null;
254
- readonly snippet: string;
255
- readonly score: number;
256
- readonly ai_input: AiInput;
257
- /** This time (ISO 8601) is the fetch time of the current text. */
258
- readonly fetched_at: string;
259
- /** This id is the capture of the current text. */
260
- readonly capture: string;
261
- }
262
- /** The variant of a cache entry: the plain response, or the page that the browser rendered. */
263
- type Variant = "plain" | "rendered";
264
- interface Latest {
265
- readonly url: string;
266
- readonly capture: string;
267
- readonly blob: string | null;
268
- readonly etag: string | null;
269
- readonly last_modified: string | null;
270
- readonly content_type: string | null;
271
- readonly fetched_at: string;
272
- readonly status: number;
273
- /** This value is what the page said about AI input at the time of the fetch. */
274
- readonly ai_input: AiInput;
275
- /** This URL is the target of a stored redirect. Its secrets show as `REDACTED`. */
276
- readonly location?: string | null | undefined;
277
- /** This value is true when the stored body is only the first part of the response. */
278
- readonly truncated?: boolean | undefined;
279
- /** This time (ISO 8601) is the end of the freshness that the server gave. */
280
- readonly fresh_until?: string | null | undefined;
281
- /** This text holds the request headers that the response varies on (`Vary`), with their values. */
282
- readonly vary_key?: string | null | undefined;
283
- /** The default is `plain`. A key that ends in `#rendered` (the form of version 0.1) is `rendered`. */
284
- readonly variant?: Variant | undefined;
285
- }
286
- /** These are the counts of the index. */
287
- interface Counts {
288
- readonly docs: number;
289
- readonly urls: number;
290
- }
291
- /** A rebuild of the index writes a new generation of the tables. The old generation answers until the commit. */
292
- interface IndexBuild {
293
- /** This method adds a version to the new generation. The build writes the versions in batches. */
294
- upsert(input: DocInput, now: string): void;
295
- /** This method sets a cache entry in the new generation, when it is newer than the stored entry. */
296
- setLatest(entry: Latest): void;
297
- /** This method reads a cache entry of the new generation. */
298
- latest(url: string, variant?: Variant): Latest | undefined;
299
- /** This method writes the waiting versions in one transaction. */
300
- flush(): void;
301
- /**
302
- * This method copies the versions of each recipe that is not in `recipes` from the current
303
- * generation. A runtime with no extractor for a recipe thus keeps the documents of that recipe.
304
- * It gives the number of documents that it copied.
305
- */
306
- carry(recipes: ReadonlySet<string>): number;
307
- /**
308
- * This method makes the new generation current. It first copies the rows that a different writer
309
- * added to the current generation since `since`. Then it removes the old generation.
310
- */
311
- commit(since: string): Counts;
312
- /** This method removes the new generation. The current generation stays. */
313
- abort(): void;
314
- }
315
- /**
316
- * A reading index keeps the documents, their versions, the search and the cache entries. `DocIndex`
317
- * is the SQLite index. A runtime takes any object with these methods, for example a search index
318
- * of a different kind that wraps a `DocIndex`.
319
- */
320
- interface ReadingIndex {
321
- /** This value is true when the index opened empty and a rebuild did not fill it yet. */
322
- readonly stale: boolean;
323
- get(doc: string): Doc | undefined;
324
- upsert(input: DocInput, now: string): Doc;
325
- versions(doc: string, options?: {
326
- readonly limit?: number;
327
- }): DocVersion[];
328
- versionText(doc: string, capture?: string): VersionText | undefined;
329
- earlierTexts(doc: string, options?: {
330
- readonly limit?: number;
331
- }): VersionText[];
332
- docsOfCapture(capture: string): Doc[];
333
- /** This method tells if a capture gave a version of a document. */
334
- hasVersion(capture: string): boolean;
335
- find(q: string, options: FindIndexOptions): Found[];
336
- rankWithin(q: string, docs: readonly string[], options?: {
337
- readonly rank?: RankMode | undefined;
338
- }): Array<{
339
- readonly doc: string;
340
- readonly score: number;
341
- }>;
342
- latest(url: string, variant?: Variant): Latest | undefined;
343
- setLatest(entry: Latest): void;
344
- /** This method gives the newest fetch time of the cache entries, or undefined for an empty index. */
345
- newestFetch(): string | undefined;
346
- counts(): Counts;
347
- beginRebuild(options?: {
348
- readonly batch?: number;
349
- }): IndexBuild;
350
- }
351
- /** These are the options of a reading index. */
352
- interface DocIndexOptions {
353
- /** This value is the time in milliseconds that a write waits for the lock of a different process. The default is 10 seconds. */
354
- readonly busyTimeoutMs?: number | undefined;
355
- }
356
- declare class DocIndex implements ReadingIndex {
357
- readonly path: string;
358
- private readonly db;
359
- private readonly statements;
360
- private depth;
361
- private closed;
362
- private empty;
363
- /**
364
- * This value is true when the file had a different schema, or no tables, so the index opened
365
- * empty. A store with captures then needs `reindex`. The commit of a rebuild makes it false.
366
- */
367
- get stale(): boolean;
368
- constructor(path: string, options?: DocIndexOptions);
369
- /** This method makes the tables of the schema. It gives true when the index opened empty. */
370
- private prepareSchema;
371
- private setMeta;
372
- private getMeta;
373
- private stmt;
374
- /**
375
- * This method does a write in one transaction. A transaction in progress takes the write in,
376
- * also a transaction that the caller opened on the connection.
377
- */
378
- private write;
379
- private generation;
380
- /**
381
- * This method does a step on the tables of the current generation. A rebuild of a different
382
- * process can remove those tables in the meantime. Then the method reads the generation again
383
- * and does the step once more.
384
- */
385
- private live;
386
- /** This method removes the tables of a generation. */
387
- private dropGeneration;
388
- /** This method removes the generations of builds that a stopped process left. */
389
- private dropAbandoned;
390
- private putText;
391
- private textOf;
392
- private putVersion;
393
- private newest;
394
- /** This method chooses the current version of a document from its versions, and writes it with its search entry. */
395
- private recompute;
396
- private docOf;
397
- private toDoc;
398
- private versionTextOf;
399
- get(doc: string): Doc | undefined;
400
- /**
401
- * This method adds one version of a document, and it gives the current document. The rules of
402
- * the class choose the current version. An upsert of a known capture replaces that version.
403
- */
404
- upsert(input: DocInput, now: string): Doc;
405
- /** This method gives the versions of a document, the newest first. */
406
- versions(doc: string, options?: {
407
- readonly limit?: number;
408
- }): DocVersion[];
409
- /**
410
- * This method gives the text of one version of a document. With no capture, it gives the current
411
- * version. It also gives the text of a held-back version: the caller applies `isHeldBack` to the
412
- * `ai_input` of the version.
413
- */
414
- versionText(doc: string, capture?: string): VersionText | undefined;
415
- /**
416
- * This method gives the texts of the earlier versions of a document, the newest first. Each
417
- * text comes one time, with the newest version that has it. It skips the current text. It also
418
- * gives held-back texts: the caller applies `isHeldBack` to the `ai_input` of each version.
419
- */
420
- earlierTexts(doc: string, options?: {
421
- readonly limit?: number;
422
- }): VersionText[];
423
- /** This method tells if a capture gave a version of a document. */
424
- hasVersion(capture: string): boolean;
425
- /** This method gives the newest fetch time of the cache entries, or undefined for an empty index. */
426
- newestFetch(): string | undefined;
427
- /** This method gives the current documents that a capture gave. */
428
- docsOfCapture(capture: string): Doc[];
429
- /**
430
- * This method searches the documents with BM25, the best first. The syntax of the query is the
431
- * syntax of `parseQuery`. It first asks for each part. When that gives too few documents, it
432
- * adds the documents that match one part. A document that asked not to be AI input is not in
433
- * the results, so a search cannot show its text. The option `rank` chooses the ranking (`RankMode`).
434
- */
435
- find(q: string, options: FindIndexOptions): Found[];
436
- /**
437
- * This method scores a set of documents against a query, with the best first. It leaves out a
438
- * document that matches no term, and a document that asked not to be AI input. It ranks the
439
- * results of a source again, because the order of the source is only as good as its search engine.
440
- * In the mode `fast`, it also leaves out a document that holds only common parts (`RankMode`).
441
- */
442
- rankWithin(q: string, docs: readonly string[], options?: {
443
- readonly rank?: RankMode | undefined;
444
- }): Array<{
445
- readonly doc: string;
446
- readonly score: number;
447
- }>;
448
- /**
449
- * This method gives the form of a query that needs one part, without the common parts (the mode
450
- * `fast` of `RankMode`). It counts the documents that hold each part. When each part is common,
451
- * it keeps the rarest part.
452
- */
453
- private rareParts;
454
- /** This method gives the cache entry of a URL. The key is canonical, so two spellings of one URL give one entry. */
455
- latest(url: string, variant?: Variant): Latest | undefined;
456
- private putLatest;
457
- /** This method keeps the last answer for a URL. An entry that is older than the stored entry changes nothing. */
458
- setLatest(entry: Latest): void;
459
- counts(): Counts;
460
- /** This method empties the current generation. A rebuild uses `beginRebuild`, which keeps the index until its commit. */
461
- reset(): void;
462
- /**
463
- * This method starts a rebuild into a new generation of the tables. The current generation
464
- * answers each read and takes each write until the commit. A failed rebuild thus leaves the
465
- * index as it was.
466
- */
467
- beginRebuild(options?: {
468
- readonly batch?: number;
469
- }): IndexBuild;
470
- /** This method closes the file. A second close does nothing. */
471
- close(): void;
472
- }
473
- //#endregion
474
- //#region src/egress.d.ts
475
- /**
476
- * The egress policy keeps the crawler on the public internet. A page or an agent can ask for an
477
- * internal address. Examples are a loopback service, a router on the LAN and the metadata
478
- * service of a cloud host. The crawler refuses these addresses by default.
479
- *
480
- * - The crawler fetches only `http:` and `https:` URLs.
481
- * - The check uses the address after DNS. The `lookup` hook of the connection checks the address
482
- * that the socket then uses, so a DNS answer that changes cannot pass the check.
483
- * - The crawler examines a literal IP host directly, in each spelling that the URL parser reads.
484
- * - The crawler examines each redirect hop again.
485
- *
486
- * A refusal is a skipped fetch with a clear note. It does not throw an error.
487
- */
488
- /** These options change the egress policy. With no options, the crawler fetches only public addresses. */
489
- interface EgressOptions {
490
- /** The value true lets the crawler fetch loopback, private and link-local addresses. The default is false. */
491
- readonly allowPrivate?: boolean | undefined;
492
- /**
493
- * These hosts are permitted although their address is not public. An entry is a host name, a
494
- * name pattern (`*.corp.example`), an IP address or a CIDR range (`10.0.0.0/8`).
495
- */
496
- readonly allowHosts?: readonly string[] | undefined;
497
- }
498
- /** The connection hook gives this error when the policy refuses each address of a host. */
499
- declare class EgressRefused extends Error {
500
- readonly address: string;
501
- readonly kind: string;
502
- readonly code: string;
503
- constructor(address: string, kind: string);
504
- }
505
- /** This is the form of `dns.lookup` that the egress hook uses. Tests give a resolver of their own. */
506
- type Resolve = (host: string, options: LookupAllOptions, callback: (error: NodeJS.ErrnoException | null, addresses: LookupAddress[]) => void) => void;
507
- /**
508
- * This function gives a `lookup` hook for the connection options of an undici `Agent`. The hook
509
- * resolves the name, removes each address that the policy refuses, and gives the rest to the
510
- * socket. When no address stays, the connection fails with `EgressRefused`.
511
- */
512
- declare const egressLookup: (policy: EgressOptions, resolve?: Resolve) => LookupFunction;
513
- //#endregion
514
- //#region src/record.d.ts
515
- /**
516
- * A capture record is one line of the capture log. Each fetch decision makes one record, and a
517
- * fetch that the crawler declines makes one too.
518
- *
519
- * The record id comes from a hash of its content, so the same decision always gets the same id.
520
- * A citation names this id.
521
- *
522
- * The id has 48 bits: the source and the first 12 hexadecimal digits of the hash. Approximately
523
- * 1 million records give a chance of a collision of 0.2 percent. The package keeps this length on purpose,
524
- * because the ids of the earlier capture logs and their citations must stay the same. A later
525
- * version can make the ids of new records longer behind a record version. It must still read a
526
- * 12-digit id.
527
- */
528
- interface CaptureRecord {
529
- readonly id: string;
530
- /** The source of the record. The crawler writes `fetch`, and an application can add its own sources. */
531
- readonly source: string;
532
- readonly kind: string;
533
- readonly external_id?: string | undefined;
534
- readonly occurred_at?: string | undefined;
535
- readonly received_at: string;
536
- readonly payload: unknown;
537
- readonly content_hash: string;
538
- /** This label comes from the application. The crawler writes it as it is and does not read it. */
539
- readonly scope?: string | undefined;
540
- /**
541
- * These labels come from the application, for example the lineage of a request. The crawler writes
542
- * them as they are and does not read them. Like `scope`, they are not part of the hash.
543
- */
544
- readonly labels?: Readonly<Record<string, string>> | undefined;
545
- }
546
- /** These are the fields of a new record. The function `makeRecord` calculates the id and the hash. */
547
- interface RecordInput {
548
- readonly source: string;
549
- readonly kind: string;
550
- readonly payload: unknown;
551
- readonly received_at: string;
552
- readonly external_id?: string | undefined;
553
- readonly occurred_at?: string | undefined;
554
- readonly scope?: string | undefined;
555
- readonly labels?: Readonly<Record<string, string>> | undefined;
556
- }
557
- /**
558
- * This function makes a capture record. The hash covers the source, the kind, the external id
559
- * and the payload. The id is the source and the first 12 digits of the hash. The times, `scope`
560
- * and `labels` are not part of the hash.
561
- */
562
- declare const makeRecord: (input: RecordInput) => CaptureRecord;
563
- //#endregion
564
- //#region src/crawler.d.ts
565
- /**
566
- * The crawler is a polite fetcher. It sends one request at a time to each host, and it obeys
567
- * robots.txt for web pages. Its `User-Agent` header tells what it is. It asks again with the
568
- * validators of the stored copy, and it stops when a site refuses. Each decision goes into the
569
- * capture log, and a fetch that the crawler declines goes there too.
570
- *
571
- * There are two kinds of request. A documented public API (`api`) has its own terms and rate
572
- * limits. A web page (`page`) obeys robots.txt. The settings come from measurements:
573
- *
574
- * - The `request` function of undici on one `Agent`.
575
- * - A keep-alive time longer than the delay for each host. With the default of 4 seconds, each
576
- * polite request opens a new connection.
577
- * - A backoff with jitter in the queue, not the retry handler of undici. That handler limits
578
- * Retry-After to 30 seconds and adds no jitter.
579
- * - A maximum size for each body, after decompression. The crawler keeps the first part of a
580
- * longer body and marks it as truncated.
581
- *
582
- * A fetch and a render go through one admission. It examines the URL, the egress policy, the
583
- * product tokens, robots.txt, the cache and the stops of the host. Only the transport is
584
- * different: an HTTP request or the headless browser.
585
- *
586
- * The egress policy (`EgressOptions`) keeps the crawler on public addresses by default. The
587
- * politeness policy (`PolitenessPolicy`) holds each limit, and a host can have its own values.
588
- * The fetch and the render do not throw an error: each problem is an outcome with a note.
589
- */
590
- /**
591
- * The outcome of a fetch or a render. A `skipped` request did not go out. A render of a URL that
592
- * gives a file and not a page is `not-html`.
593
- */
594
- type FetchOutcome = Outcome | "skipped" | "not-html";
595
- interface FetchRequest {
596
- readonly url: string;
597
- /** The value `api` is a documented API with its own terms. The value `page` is a web page, and robots.txt applies. */
598
- readonly mode: "api" | "page";
599
- /** This recipe reads the capture again. The function `reindex` uses it to replay the capture. */
600
- readonly recipe: string;
601
- readonly accept?: string | undefined;
602
- /**
603
- * These are more request headers. The crawler does not write them into the capture. They
604
- * cannot replace `User-Agent`, `From`, `Accept-Encoding` or the validators. A redirect to a
605
- * different origin removes `Authorization`, `Cookie` and `Proxy-Authorization`.
606
- */
607
- readonly headers?: Readonly<Record<string, string>> | undefined;
608
- /**
609
- * These query parameters contain secrets. Each capture shows `REDACTED` in their place. The
610
- * names in `DEFAULT_SECRET_PARAMS` get the same treatment with no list.
611
- */
612
- readonly secretParams?: readonly string[] | undefined;
613
- /** This value is the documented pace of the source: the shortest time between two of its requests. */
614
- readonly minIntervalMs?: number | undefined;
615
- /**
616
- * A stored capture younger than this age answers, and the crawler sends no request. The value
617
- * `auto` uses the freshness that the server gave (RFC 9111): `Cache-Control`, `Expires`, or 10
618
- * percent of the age of `Last-Modified`.
619
- */
620
- readonly maxAgeMs?: number | "auto" | undefined;
621
- readonly maxBytes?: number | undefined;
622
- /**
623
- * These are the product tokens of an agent that the fetch acts for, for example `Claude-User`.
624
- * The robots.txt rules for these tokens apply too.
625
- */
626
- readonly onBehalfOf?: readonly string[] | undefined;
627
- /** This name connects the captures to the job that asked for them. */
628
- readonly job?: string | undefined;
629
- /** When this signal aborts, the crawler stops the fetch. The result is then `skipped` or `error`, with a note. */
630
- readonly signal?: AbortSignal | undefined;
631
- /** This label goes into each capture record of the request. It replaces the `scope` of the crawler. */
632
- readonly scope?: string | undefined;
633
- /** These labels go into each capture record of the request, for example its lineage. They are not part of the capture id. */
634
- readonly labels?: Readonly<Record<string, string>> | undefined;
635
- }
636
- interface Fetched {
637
- /** This URL is the URL of the capture. Its secrets show as `REDACTED`. */
638
- readonly url: string;
639
- readonly status: number;
640
- readonly outcome: FetchOutcome;
641
- /** This value is true when a stored capture answered, with no request. */
642
- readonly fromCache: boolean;
643
- /** This id is the capture record behind the body. A citation names it. */
644
- readonly capture: string | undefined;
645
- readonly blob: string | undefined;
646
- readonly body: Uint8Array | undefined;
647
- readonly contentType: string | undefined;
648
- readonly signals: Signals;
649
- readonly note: string | undefined;
650
- /** This value is true when the body was longer than the maximum, so the crawler kept only its first part. */
651
- readonly truncated?: boolean | undefined;
652
- /** This time (ISO 8601) is the time of the fetch of the body. For a stored copy, it is the time of that copy. */
653
- readonly fetchedAt?: string | undefined;
654
- /** This label is the scope of the capture. */
655
- readonly scope?: string | undefined;
656
- /** These labels are the labels of the capture. */
657
- readonly labels?: Readonly<Record<string, string>> | undefined;
658
- }
659
- /** The crawler writes each record to a capture writer. The class `CaptureLog` is one. */
660
- interface CaptureWriter {
661
- append(record: CaptureRecord): Promise<void>;
662
- close?(): Promise<void>;
663
- }
664
- /** A cache entry is the last answer for a URL: its capture, its body and its validators. */
665
- interface CacheEntry {
666
- /** This text is the cache key: the canonical URL, with its secrets as `REDACTED`. */
667
- readonly url: string;
668
- readonly capture: string;
669
- readonly blob: string | null;
670
- readonly etag: string | null;
671
- readonly last_modified: string | null;
672
- readonly content_type: string | null;
673
- readonly fetched_at: string;
674
- readonly status: number;
675
- /** This value is what the page said about AI input at the time of the fetch. */
676
- readonly ai_input: AiInput;
677
- /** This URL is the target of a stored redirect. Its secrets show as `REDACTED`. */
678
- readonly location?: string | null | undefined;
679
- /** This value is true when the stored body is only the first part of the response. */
680
- readonly truncated?: boolean | undefined;
681
- /** This time (ISO 8601) is the end of the freshness that the server gave. */
682
- readonly fresh_until?: string | null | undefined;
683
- /** This text holds the request headers that the response varies on (`Vary`), with their values. */
684
- readonly vary_key?: string | null | undefined;
685
- /** This value tells a plain response from a page that the browser rendered. The default is `plain`. */
686
- readonly variant?: Variant | undefined;
687
- }
688
- /**
689
- * The cache index holds the last answer for each URL. The crawler reads it before a request, and
690
- * it writes it after an answer. The class `DocIndex` is one. An index that keeps only the
691
- * necessary fields of `CacheEntry` works, and the crawler keeps the other fields in memory.
692
- */
693
- interface CacheIndex {
694
- latest(url: string, variant?: Variant): CacheEntry | undefined;
695
- setLatest(entry: CacheEntry): void;
696
- }
697
- /** An event tells a listener what the crawler does. The listener cannot change it. */
698
- type CrawlEvent = {
699
- readonly type: "request";
700
- readonly url: string;
701
- readonly host: string;
702
- readonly transport: "http" | "browser";
703
- } | {
704
- readonly type: "response";
705
- readonly url: string;
706
- readonly host: string;
707
- readonly status: number;
708
- readonly outcome: FetchOutcome;
709
- readonly elapsedMs: number;
710
- } | {
711
- readonly type: "wait";
712
- readonly host: string;
713
- readonly ms: number;
714
- readonly reason: string;
715
- } | {
716
- readonly type: "stop";
717
- readonly host: string;
718
- readonly until: number;
719
- readonly reason: string;
720
- } | {
721
- readonly type: "skip";
722
- readonly url: string;
723
- readonly note: string;
724
- };
725
- interface CrawlerOptions {
726
- /** This product token is the name that robots.txt rules match. It contains only letters, `_` and `-` (RFC 9309). */
727
- readonly token: string;
728
- /** This text is the full `User-Agent` header. */
729
- readonly userAgent: string;
730
- /** This contact goes into the `From` header. Without it, the crawler sends no `From` header. */
731
- readonly from?: string | undefined;
732
- readonly log: CaptureWriter;
733
- readonly blobs: BlobStore;
734
- readonly index: CacheIndex;
735
- readonly clock?: Clock | undefined;
736
- readonly random?: (() => number) | undefined;
737
- /** This value is the number of hosts that get requests at one time. The default is 16. */
738
- readonly maxActive?: number | undefined;
739
- /**
740
- * This value tells if the crawler also obeys the robots.txt group of `PoliteCrawler`. That applies
741
- * when the `User-Agent` links the bot page of polite-crawler (`BOT_PAGE`) and the token is different.
742
- * Site owners read that page, and they write their rules for `PoliteCrawler`. The most restrictive
743
- * of the groups applies, as for `onBehalfOf`. The default is true. Set false for a bot page of your own.
744
- */
745
- readonly obeyDefaultToken?: boolean | undefined;
746
- /**
747
- * This value is the number of pages that the browser renders at one time. The default is 2. Each
748
- * render is a browser context of its own, which holds much memory. A render waits for a slot before
749
- * the lease of its host, so the wait does not count toward the time of the host.
750
- */
751
- readonly maxRenders?: number | undefined;
752
- /**
753
- * This undici dispatcher sends the requests. With a dispatcher of your own, the crawler checks
754
- * only literal addresses. Put `egressLookup` in its connection options to check the address after DNS.
755
- */
756
- readonly dispatcher?: Dispatcher | undefined;
757
- /** This label goes into each capture record as it is. */
758
- readonly scope?: string | undefined;
759
- /**
760
- * This function ranks the scopes of the requests, the most private scope highest. One fetch of a
761
- * robots.txt can serve requests of different scopes. Its record then takes the scope with the
762
- * highest rank, and the labels of each request. With no function, the first request gives the scope.
763
- */
764
- readonly scopeRank?: ((scope: string) => number) | undefined;
765
- /** This browser renders the pages that need JavaScript. Without it, the crawler renders no page. */
766
- readonly renderer?: Renderer | undefined;
767
- /** This policy controls the addresses that the crawler fetches. By default, the crawler fetches only public addresses. */
768
- readonly egress?: EgressOptions | undefined;
769
- /** These values change the limits of the politeness policy, for each host or for some hosts. */
770
- readonly politeness?: PolicyOptions | undefined;
771
- /** This store keeps the pace, the counts and the stops of each host. The default keeps them in memory. */
772
- readonly hostState?: HostStateStore | undefined;
773
- /** This function gets an event for each request, response, wait, stop and skip. An error in it does not stop the crawler. */
774
- readonly onEvent?: ((event: CrawlEvent) => void) | undefined;
775
- }
776
- interface RenderRequest {
777
- readonly url: string;
778
- readonly recipe: string;
779
- /** A stored render younger than this age answers. The value `auto` uses the freshness that the server gave. */
780
- readonly maxAgeMs?: number | "auto" | undefined;
781
- readonly onBehalfOf?: readonly string[] | undefined;
782
- readonly job?: string | undefined;
783
- /** When this signal aborts, the crawler stops the render, and the browser stops the page. */
784
- readonly signal?: AbortSignal | undefined;
785
- /** This label goes into the capture record of the render. It replaces the `scope` of the crawler. */
786
- readonly scope?: string | undefined;
787
- /** These labels go into the capture record of the render. */
788
- readonly labels?: Readonly<Record<string, string>> | undefined;
789
- }
790
- /**
791
- * This function gives the key of the cache entry of a rendered page in the form of version 0.1.
792
- * The index keeps the variant in a column of its own, and it reads this form too.
793
- */
794
- declare const renderedKey: (url: string) => string;
795
- /** This value is the version of the payload of the records that the crawler writes. A record with no `schema` is version 1. */
796
- declare const CAPTURE_SCHEMA = 2;
797
- /**
798
- * These query parameters hold secrets in many APIs. The crawler writes `REDACTED` in place of
799
- * their values in each capture, in addition to the names of `secretParams`.
800
- */
801
- declare const DEFAULT_SECRET_PARAMS: readonly string[];
802
- declare class Crawler {
803
- private readonly options;
804
- private readonly clock;
805
- private readonly random;
806
- private readonly scheduler;
807
- private readonly dispatcher;
808
- private readonly ownsDispatcher;
809
- private readonly egress;
810
- private readonly robots;
811
- /** The fields of a cache entry that the index does not keep, and the raw target of a redirect. */
812
- private readonly meta;
813
- private readonly inFlight;
814
- private readonly running;
815
- private readonly closing;
816
- private closed;
817
- private closingDone;
818
- /** This note tells why the renderer has no browser. After the first page that finds it, the crawler renders nothing. */
819
- private renderOff;
820
- /** The renders that run at one time (`maxRenders`). */
821
- private readonly renders;
822
- /** These tokens apply because the `User-Agent` links the bot page (`obeyDefaultToken`). */
823
- private readonly pageTokens;
824
- constructor(options: CrawlerOptions);
825
- private iso;
826
- private policyOf;
827
- private emit;
828
- private track;
829
- /** This method gives the validator memo of a host. The memo is a hint, so an error of its store gives no memo. */
830
- private memoOf;
831
- private stopHost;
832
- private record;
833
- private skip;
834
- /** This method reads the cache entry of a URL, with the fields that the crawler keeps in memory. */
835
- private lookup;
836
- private store;
837
- /** This method gives the target of a stored redirect, when the crawler can follow it. */
838
- private followable;
839
- /** This method answers from the cache, when the stored entry is young or fresh enough. */
840
- private fromCache;
841
- private requestHeaders;
842
- /**
843
- * This method records the result of a request for the host, and it gives the rest of the host.
844
- * The rest comes from `restAfter`. A 429 or 503 waits, an error counts toward a stop, and a
845
- * refusal stops the host for a time.
846
- */
847
- private settle;
848
- /**
849
- * This method stops the host of a URL as a challenge does: for the `challengeStopMs` of the policy.
850
- * The runtime uses it when a page that answered 200 is a bot check (`meta.blocked`).
851
- */
852
- reportBlocked(url: string, what: string): void;
853
- /**
854
- * This method applies the rules that a fetch and a render share. The sequence is the URL, the
855
- * options, the egress policy, the product tokens and the rules for an agent. Then come the
856
- * cache, the stops of the host and robots.txt. It gives the answer when a rule decides, or the
857
- * facts that the transport needs.
858
- */
859
- private admit;
860
- /** This method fetches a URL. It follows the redirects up to the maximum, and each step is a separate decision. */
861
- fetch(request_: FetchRequest): Promise<Fetched>;
862
- private follow;
863
- /** This method joins a request to an equal request in progress, so one URL gets one request at a time. */
864
- private hop;
865
- private knownRobots;
866
- /**
867
- * This method gives the robots.txt of the origin of a URL. A good copy stays for the TTL of the
868
- * policy. An unreachable verdict stays for some minutes, with a backoff and the `Retry-After`
869
- * of the server. During that time the last good copy applies, when there is one (RFC 9309 §2.4).
870
- */
871
- private robotsFor;
872
- /**
873
- * This method gives the robots.txt rules that apply to a URL, as the crawler applies them. They
874
- * come from its memory, or from a fetch of `/robots.txt` with its redirects. A robots.txt that
875
- * the crawler cannot read gives rules that permit nothing, and `unreachable` gives the reason.
876
- */
877
- readRobots(url: string): Promise<{
878
- readonly robots: Robots;
879
- readonly capture: string | undefined;
880
- readonly stale?: string | undefined;
881
- }>;
882
- /** This method reads the stored copy of a robots.txt, when it is younger than the limit of the policy. */
883
- private storedRobots;
884
- /** This method adds the scope and the labels of one request to the requests that wait for a robots.txt. The most private scope wins. */
885
- private join;
886
- private fetchRobots;
887
- private fetchOnce;
888
- /**
889
- * This method gives the function that decides each request of a rendered page. It refuses an
890
- * address that the egress policy refuses, and a URL of the page's host that robots.txt
891
- * disallows. For a different host, it uses a robots.txt that the crawler holds, when there is one.
892
- */
893
- private allowRequestFor;
894
- /**
895
- * This method tells why the browser did not go on to a URL that the page moved to: the egress
896
- * policy or robots.txt. For a different site, it uses a robots.txt that the crawler holds. It
897
- * gives undefined for the page itself, or for a URL that it cannot read.
898
- */
899
- private movedRefusal;
900
- /**
901
- * This method renders a page in the headless browser and captures what the page shows. The rules
902
- * of a fetch apply:
903
- *
904
- * - the egress policy and robots.txt, for the page, its final URL and each request of the page
905
- * - one request at a time for each host
906
- * - the backoff after a 429 or a 503
907
- * - a capture for each decision
908
- *
909
- * A render costs the site more than a fetch, so the host rests longer after one. A render that
910
- * the browser refuses (`RenderRefused`) does not count against the host.
911
- */
912
- render(request_: RenderRequest): Promise<Fetched>;
913
- private renderOnce;
914
- /**
915
- * This method removes the stops and the failure counts of one host, or of each host. It also
916
- * forgets the robots.txt verdicts that came from an unreachable robots.txt. The pace of each host
917
- * stays. A process that runs for a long time uses it, for example after the network comes back.
918
- */
919
- resetHosts(host?: string): void;
920
- /**
921
- * This method closes the crawler. Work in the queue ends as `skipped` with the note
922
- * `crawler closed`, and the crawler writes no capture after the close. Then it closes the
923
- * browser, the log and its own dispatcher. A second close waits for the first.
924
- */
925
- close(): Promise<void>;
926
- }
927
- //#endregion
928
- //#region src/log.d.ts
929
- /** A scan filter selects the records of one source, one kind, or the records after one time. */
930
- interface CaptureFilter {
931
- readonly source?: string | undefined;
932
- readonly kind?: string | undefined;
933
- /** This value is an ISO 8601 time. The scan gives the records received at this time or later. */
934
- readonly since?: string | undefined;
935
- }
936
- /** A damaged line is a line of the log that is not a record: a torn append, or bytes that a crash left. */
937
- interface DamagedLine {
938
- /** This value is the path of the file. */
939
- readonly path: string;
940
- /** This value is the number of the line in the file, from 1. */
941
- readonly line: number;
942
- }
943
- /** These options change a scan. */
944
- interface ScanOptions {
945
- /** The scan skips a damaged line, and it gives the line to this function. */
946
- readonly onDamaged?: ((damaged: DamagedLine) => void) | undefined;
947
- }
948
- /** The read side of the capture log is what `reindex` replays. */
949
- interface CaptureReader {
950
- scan(filter?: CaptureFilter, options?: ScanOptions): AsyncIterable<CaptureRecord>;
951
- }
952
- /** These options change a capture log. */
953
- interface CaptureLogOptions {
954
- /**
955
- * When this value is true (the default), the log writes each batch of appends to the disk
956
- * (`fdatasync`) before the appends finish. Thus a power cut does not lose a record that the
957
- * crawler reported.
958
- */
959
- readonly sync?: boolean | undefined;
960
- }
961
- /**
962
- * The capture log keeps each fetch decision as one line of JSON in
963
- * `<dir>/<source>/<yyyy>/<mm>.ndjson`. It is the record of each access that the crawler makes.
964
- *
965
- * These are the rules of the log:
966
- *
967
- * - The log appends a batch of records with one write, and it writes the batch to the disk before
968
- * the appends finish.
969
- * - An append always starts on a new line. After a crash leaves a partial line, the next append
970
- * starts after a line break. The partial line stays as a damaged line, and the record is good.
971
- * - A scan reads each file as a stream. It skips a damaged line, counts it, and continues.
972
- * - The log does not remove or change a line.
973
- *
974
- * Two processes can append to one log, because each batch is one write to a file in append mode.
975
- */
976
- declare class CaptureLog implements CaptureReader {
977
- readonly dir: string;
978
- private readonly handles;
979
- private readonly pending;
980
- private draining;
981
- private readonly sync;
982
- constructor(dir: string, options?: CaptureLogOptions);
983
- private pathOf;
984
- private handleFor;
985
- /** This method tells if the last byte of a file is not a line break: a partial line that a crash left. */
986
- private static needsBreak;
987
- append(record: CaptureRecord): Promise<void>;
988
- /** This method starts the writer when it is not in progress. A record that comes as the writer stops starts it again. */
989
- private kick;
990
- /** This method writes the waiting records in batches: one write and one sync for each file. */
991
- private drain;
992
- /** This method waits until each append in progress is on the disk. */
993
- flush(): Promise<void>;
994
- /** This method gives the record files of one source, in the sequence of time. It skips the months before `since`. */
995
- private filesOf;
996
- /** This method reads the records of one source in the sequence of the files. */
997
- private readSource;
998
- /**
999
- * This method reads the records that agree with the filter. It first waits for the appends that
1000
- * are in progress. It reads each file as a stream, so its memory does not grow with the log.
1001
- *
1002
- * The records of one source come in the sequence of the files. The records of two or more sources
1003
- * merge in the sequence of `received_at`.
1004
- */
1005
- scan(filter?: CaptureFilter, options?: ScanOptions): AsyncIterable<CaptureRecord>;
1006
- /** This method writes the appends in progress, then closes the files. A later append opens them again. */
1007
- close(): Promise<void>;
1008
- }
1009
- //#endregion
1010
- //#region src/runtime.d.ts
1011
- /**
1012
- * An extractor changes one captured body into the documents that it holds. It has no side effects,
1013
- * so `reindex` can replay each capture through it and build the index again with no request. It can
1014
- * answer later, because the crawler reads a PDF asynchronously.
1015
- *
1016
- * An extractor that throws does not stop a fetch, a render or a rebuild. The runtime records the
1017
- * error and gives no document for that capture.
1018
- */
1019
- type Extractor = (body: Uint8Array, capture: {
1020
- readonly url: string;
1021
- readonly contentType: string | null;
1022
- }) => ReadonlyArray<ExtractedDoc> | Promise<ReadonlyArray<ExtractedDoc>>;
1023
- /** This function gives the document id of a web page. Each page has one id. */
1024
- declare const pageDocId: (url: string) => string;
1025
- /**
1026
- * This extractor is the built-in recipe for a web page, plain or rendered. It keeps the visible
1027
- * text, the JSON-LD (whole objects, up to a limit) and the links. It decodes the body in the
1028
- * encoding that the page declares, with `decodeBody`. It does not throw: a page that it cannot read
1029
- * gives a document that names the error. When the reader cut the text, the document keeps the whole
1030
- * text in `full_text`, so `verify` finds a quote past the cut.
1031
- */
1032
- declare const pageExtractor: Extractor;
1033
- declare class Extractors {
1034
- private readonly byRecipe;
1035
- register(recipe: string, extractor: Extractor): void;
1036
- get(recipe: string): Extractor | undefined;
1037
- /** This method gives the names of the recipes that have an extractor. */
1038
- recipes(): string[];
1039
- }
1040
- interface CrawlRuntime {
1041
- readonly crawler: Crawler;
1042
- /** This index keeps the documents and the cache entries. `DocIndex` is the SQLite index. */
1043
- readonly index: ReadingIndex;
1044
- readonly blobs: BlobStore;
1045
- /** This reader is the read side of the capture log. The function `reindex` replays it. */
1046
- readonly captures: CaptureReader;
1047
- /** This log is the write side of the capture log. */
1048
- readonly log: CaptureLog;
1049
- readonly extractors: Extractors;
1050
- readonly now: () => string;
1051
- }
1052
- /** This is the payload of a capture record, as the crawler writes it. */
1053
- interface CapturePayload {
1054
- readonly url: string;
1055
- readonly recipe: string;
1056
- readonly mode: "api" | "page";
1057
- readonly status?: number;
1058
- readonly outcome?: string;
1059
- readonly blob?: string | null;
1060
- readonly content_type?: string | null;
1061
- readonly etag?: string | null;
1062
- readonly last_modified?: string | null;
1063
- readonly fetched_at: string;
1064
- readonly signals?: {
1065
- readonly ai_input?: AiInput;
1066
- };
1067
- /** This value is true when the headless browser made the capture, not a plain request. */
1068
- readonly rendered?: boolean;
1069
- /** This value is true when the body is only the first part of the response. */
1070
- readonly truncated?: boolean;
1071
- /** This value is true when the server cut a compressed body. The capture is not a copy to keep. */
1072
- readonly cut?: boolean;
1073
- /** This value is true when an API answered with a web page that the request did not accept. The capture is not a copy to keep. */
1074
- readonly unasked?: boolean;
1075
- /** This time (ISO 8601) is the end of the freshness that the server gave. Captures before version 0.2 do not have it. */
1076
- readonly fresh_until?: string | null;
1077
- /** This text holds the request headers that the response varies on. Captures before version 0.2 do not have it. */
1078
- readonly vary_key?: string | null;
1079
- /** This URL is the target of a redirect, with its secrets as `REDACTED`. */
1080
- readonly location?: string | null;
1081
- readonly note?: string;
1082
- }
1083
- /** The note of a document that is held back. */
1084
- declare const HELD_BACK = "This page asked not to be used as AI input, so its text is held back. Open the URL to read it, or read again with userProvided when a person gave this URL directly (the crawler logs that).";
1085
- /**
1086
- * This function tells if a document is held back: the page asked not to be AI input, and no person
1087
- * gave its URL directly. The only way to read a held-back document is `userProvided`.
1088
- */
1089
- declare const isHeldBack: (doc: {
1090
- readonly ai_input: AiInput;
1091
- }, userProvided?: boolean) => boolean;
1092
- /** This function gives the metadata that a held-back document shows: only the structural fields, which hold no text of the page. */
1093
- declare const heldBackMeta: (meta: Readonly<Record<string, unknown>>) => Record<string, unknown>;
1094
- /** The result of `fetchAndIndex` and `renderAndIndex`. */
1095
- interface Indexed {
1096
- readonly fetched: Fetched;
1097
- readonly docs: readonly Doc[];
1098
- /** This text tells why the capture gave no document: the error of the extractor, or a bot check. */
1099
- readonly error?: string | undefined;
1100
- /** This value names the bot check or the firewall that sent its page in place of the content. */
1101
- readonly blocked?: string | undefined;
1102
- }
1103
- /**
1104
- * This function fetches one URL and adds its documents to the index. Each recipe uses it. A fetch
1105
- * from the cache gives the documents that the index has for that capture. Thus a repeated
1106
- * question sends no request and reads nothing again. An extractor that throws gives no document and an
1107
- * `error`, and the fetch still succeeds.
1108
- */
1109
- declare const fetchAndIndex: (runtime: CrawlRuntime, request: FetchRequest) => Promise<Indexed>;
1110
- /** This function renders a page in the headless browser and adds what the page shows to the index. */
1111
- declare const renderAndIndex: (runtime: CrawlRuntime, request: RenderRequest) => Promise<Indexed>;
1112
- interface PageResult {
1113
- readonly url: string;
1114
- readonly doc: string | null;
1115
- readonly outcome: string;
1116
- readonly status: number;
1117
- /** This value is the title of the page. A held-back page shows no title. */
1118
- readonly title: string | null;
1119
- readonly chars: number;
1120
- readonly rendered: boolean;
1121
- /** These are the schema.org types that the JSON-LD of the page declares. */
1122
- readonly structured: readonly string[];
1123
- readonly links: number;
1124
- /** These ids are the captures behind the current text, the newest first, 10 or fewer. */
1125
- readonly captures: readonly string[];
1126
- /** This id is the capture of the text that the document shows. A citation names it. */
1127
- readonly capture: string | null;
1128
- /** This value is the number of captures of the document. */
1129
- readonly capture_count: number;
1130
- /** This time (ISO 8601) is the fetch time of the text that the document shows. */
1131
- readonly fetched_at: string | null;
1132
- /** This value is true when the stored copy answered, and the crawler sent no request. */
1133
- readonly from_cache: boolean;
1134
- /** This value is true when the page asked not to be AI input. Its title and text are then held back. */
1135
- readonly held_back: boolean;
1136
- readonly note: string | null;
1137
- }
1138
- /** These options control one page. */
1139
- interface PageOptions {
1140
- readonly render: "auto" | "never" | "always";
1141
- readonly maxAgeMs?: number | "auto" | undefined;
1142
- readonly onBehalfOf?: readonly string[] | undefined;
1143
- readonly job?: string | undefined;
1144
- /** When this signal aborts, the crawler stops the fetch and the render. */
1145
- readonly signal?: AbortSignal | undefined;
1146
- readonly scope?: string | undefined;
1147
- readonly labels?: Readonly<Record<string, string>> | undefined;
1148
- }
1149
- /**
1150
- * This function reads one web page. It first sends a plain request. It opens the browser only when
1151
- * the page shows almost nothing without JavaScript, or when the caller asks for it. It renders
1152
- * only an HTML page: not a PDF, a different file or a bot check. A page that sends the reader on
1153
- * with a `<meta http-equiv="refresh">` gets one more plain fetch, of its target.
1154
- */
1155
- declare const fetchPage: (runtime: CrawlRuntime, url: string, options: PageOptions) => Promise<PageResult>;
1156
- /** This result is a part of one stored document. */
1157
- interface ReadResult {
1158
- readonly doc: string;
1159
- readonly kind: string;
1160
- /** This value is the title of the document. A held-back document shows no title. */
1161
- readonly title: string;
1162
- readonly url: string | null;
1163
- /** This value is the metadata of the document. A held-back document shows only the structural fields. */
1164
- readonly meta: Readonly<Record<string, unknown>>;
1165
- readonly from: number;
1166
- readonly to: number;
1167
- readonly total: number;
1168
- readonly text: string;
1169
- readonly captures: readonly string[];
1170
- /** This id is the capture of the text that the result reads. */
1171
- readonly capture: string;
1172
- /** This time (ISO 8601) is the fetch time of the text that the result reads. */
1173
- readonly fetched_at: string;
1174
- readonly ai_input: AiInput;
1175
- /** This value is true when the page asked not to be AI input. The text is then empty. */
1176
- readonly held_back: boolean;
1177
- readonly note: string | null;
1178
- }
1179
- /** This result tells if a quote is in a stored document, and where. */
1180
- interface VerifyResult {
1181
- readonly doc: string;
1182
- /** This value is true when the quote is in the text. A held-back document gives false. */
1183
- readonly found: boolean;
1184
- /** These values are the positions of the quote in the text of `capture`. */
1185
- readonly start: number | null;
1186
- readonly end: number | null;
1187
- readonly excerpt: string | null;
1188
- readonly url: string | null;
1189
- readonly captures: readonly string[];
1190
- /** This id is the capture whose text holds the quote, or the capture that the result examined. */
1191
- readonly capture: string | null;
1192
- /** This hash is the blob of that capture. */
1193
- readonly blob: string | null;
1194
- /** This time (ISO 8601) is the fetch time of that capture. */
1195
- readonly fetched_at: string | null;
1196
- /** This value is true when only an earlier version of the document holds the quote. */
1197
- readonly stale: boolean;
1198
- /** This value is true when the quote is in the whole text of a page that the reader cut. The positions are then in that whole text. */
1199
- readonly in_full_text: boolean;
1200
- /** This value is false when the examined text is not complete (a PDF that the reader stopped). A quote that is not found can then be in the file. */
1201
- readonly complete: boolean;
1202
- /** This value is the number of places where the quote is. */
1203
- readonly count: number;
1204
- readonly held_back: boolean;
1205
- readonly note: string | null;
1206
- }
1207
- /** These options control a read. */
1208
- interface ReadOptions {
1209
- /** This value is the first character to read. The default is 0. */
1210
- readonly from?: number | undefined;
1211
- /** This value is the number of characters to read. The default is 4000. */
1212
- readonly length?: number | undefined;
1213
- /** This value is true when a person gave this URL directly. It is the only way to read a held-back document. The crawler logs it. */
1214
- readonly userProvided?: boolean | undefined;
1215
- /** This id reads the version of one capture, not the current version. */
1216
- readonly capture?: string | undefined;
1217
- }
1218
- /** These options control a verification. */
1219
- interface VerifyOptions {
1220
- /** This id examines the version of one capture only. A citation of that capture thus stays true after a new fetch. */
1221
- readonly capture?: string | undefined;
1222
- /** This value is true when a person gave this URL directly. It is the only way to verify a quote in a held-back document. */
1223
- readonly userProvided?: boolean | undefined;
1224
- }
1225
- /**
1226
- * This function writes an `override` record to the capture log. A person gave the URL of a
1227
- * held-back document directly, and the hold stops for one action (`read` or `verify`). The record
1228
- * takes the scope and the labels of `marks`, or else those of the document, as its captures do.
1229
- */
1230
- declare const recordOverride: (runtime: CrawlRuntime, doc: {
1231
- readonly doc: string;
1232
- readonly url: string | null;
1233
- readonly scope?: string | undefined;
1234
- readonly labels?: Readonly<Record<string, string>> | undefined;
1235
- }, action: string, marks?: {
1236
- readonly scope?: string | undefined;
1237
- readonly labels?: Readonly<Record<string, string>> | undefined;
1238
- }) => Promise<void>;
1239
- /**
1240
- * This function reads a range of characters of one stored document. It applies the rule for a
1241
- * held-back document: no title, no text, and only the structural metadata, unless `userProvided`.
1242
- * The positions do not cut a character in two.
1243
- */
1244
- declare const readDocument: (runtime: CrawlRuntime, id: string, options?: ReadOptions) => Promise<ReadResult>;
1245
- /**
1246
- * This function finds a quote in a stored document, with `locate`. It tells which capture holds the
1247
- * quote, with its blob, its fetch time and the positions:
1248
- *
1249
- * - With `capture`, it examines the version of that capture only.
1250
- * - With no capture, it examines the current text first. When the quote is not there, it examines
1251
- * the earlier texts, the newest first. A match there has `stale: true`.
1252
- * - When the reader cut a text, it also examines the whole text.
1253
- *
1254
- * A held-back document gives `found: false` and no positions, so a quote cannot test its text,
1255
- * unless `userProvided`. The same rule applies to each version. A version that asked not to be AI
1256
- * input stays held back after a later capture drops the signal. The crawler logs an override when
1257
- * `userProvided` opens a held-back version.
1258
- */
1259
- declare const verifyQuote: (runtime: CrawlRuntime, id: string, quote: string, options?: VerifyOptions) => Promise<VerifyResult>;
1260
- /**
1261
- * This function searches the stored documents. The syntax of the query is the syntax of
1262
- * `parseQuery`. A held-back document is not in the results. The option `rank` chooses the
1263
- * ranking (`RankMode`), and the default is `exact`.
1264
- */
1265
- declare const findDocuments: (runtime: CrawlRuntime, q: string, options?: {
1266
- readonly limit?: number | undefined;
1267
- readonly kind?: string | null | undefined;
1268
- readonly rank?: RankMode | undefined;
1269
- }) => Promise<Found[]>;
1270
- /** The counts of a rebuild. */
1271
- interface ReindexResult {
1272
- /** This value is the number of captures that the rebuild read again. */
1273
- readonly captures: number;
1274
- readonly docs: number;
1275
- readonly urls: number;
1276
- /** This value is the number of captures whose extractor threw. */
1277
- readonly failed: number;
1278
- /** This value is the number of captures whose blob is missing or damaged. */
1279
- readonly missing: number;
1280
- /** This value is the number of damaged lines of the log that the rebuild skipped. */
1281
- readonly damaged: number;
1282
- /** This value is the number of documents of recipes with no extractor, kept from the old index. */
1283
- readonly carried: number;
1284
- /** These recipes have captures in the log and no extractor in this runtime. */
1285
- readonly unknown_recipes: readonly string[];
1286
- /** These are the first errors of the extractors. */
1287
- readonly errors: ReadonlyArray<{
1288
- readonly capture: string;
1289
- readonly error: string;
1290
- }>;
1291
- }
1292
- /**
1293
- * This function builds the reading index again from the capture log and the blobs. The index is a
1294
- * projection, and this function is the proof that its deletion loses nothing. These are its rules:
1295
- *
1296
- * - It builds a new generation of the tables and commits it in batches. The old index answers
1297
- * until the end, and a failed rebuild leaves it as it was.
1298
- * - It reads the log as a stream, so its memory does not grow with the log.
1299
- * - It counts and skips a damaged line, a missing blob and an extractor that throws.
1300
- * - The documents of a recipe that has no extractor in this runtime stay, from the old index.
1301
- * - A capture that a different writer adds during the rebuild goes into the new index.
1302
- */
1303
- declare const reindex: (runtime: CrawlRuntime, options?: {
1304
- readonly batch?: number | undefined;
1305
- }) => Promise<ReindexResult>;
1306
- /** The result of `catchUpIndex`. */
1307
- interface CatchUpResult extends ReindexResult {
1308
- /**
1309
- * The value `rebuild` tells that the index was stale, and the function built it again from the
1310
- * whole log. The value `tail` tells that it read only the captures that the index missed.
1311
- */
1312
- readonly mode: "rebuild" | "tail";
1313
- }
1314
- /**
1315
- * This function brings the reading index up to the capture log, with no request. `openCrawler`
1316
- * uses it at open. An application that uses `createRuntime` uses it the same way:
1317
- *
1318
- * - A stale index (a new schema, or a deleted file) is built again with `reindex`.
1319
- * - An index that is behind the log gets the captures that it missed. A process can stop between
1320
- * the log and the index, and SQLite can lose its last transactions after a power cut. The
1321
- * function reads the log from a short time before the newest cache entry.
1322
- *
1323
- * It gives the counts, or undefined when the index missed nothing.
1324
- */
1325
- declare const catchUpIndex: (runtime: CrawlRuntime) => Promise<CatchUpResult | undefined>;
1326
- //#endregion
1327
- //#region src/open.d.ts
1328
- /**
1329
- * This function gives the default `User-Agent` header. The header names the crawler, its version
1330
- * and the page about it, so a site owner can find out what made each request.
1331
- */
1332
- declare const defaultUserAgent: (contact?: string) => string;
1333
- /**
1334
- * This function tells if a contact is a mailbox. The `From` header holds only a mailbox (RFC 9110,
1335
- * section 10.1.2). Thus the crawler sends a mailbox in `From` and in the `User-Agent`, and a URL in
1336
- * the `User-Agent` only.
1337
- */
1338
- declare const isMailbox: (contact: string) => boolean;
1339
- /** A duration is a count of milliseconds, or a text, for example `"30m"`, `"24h"` or `"7d"`. */
1340
- type Duration = number | string;
1341
- /**
1342
- * This function changes a duration into milliseconds. The units are `ms`, `s`, `m` (minutes), `h`,
1343
- * `d` and `w`, in any case. The unit `M` is an error, because a month is not a unit. A bare `0`
1344
- * is zero. The function throws an error for a text that it cannot read.
1345
- */
1346
- declare const durationMs: (duration: Duration) => number;
1347
- /**
1348
- * These options make a runtime. A store needs a log, a blob store and an index. Give `dir`, and
1349
- * the runtime makes the three parts in it, or give the parts. A part that you give replaces the
1350
- * part in `dir`.
1351
- */
1352
- interface RuntimeOptions {
1353
- /** This folder keeps the capture log (`captures/`), the bodies (`blobs/`), the index (`index.sqlite`) and the state of each host (`hosts.sqlite`). */
1354
- readonly dir?: string | undefined;
1355
- /** This log replaces `<dir>/captures`. */
1356
- readonly log?: CaptureLog | undefined;
1357
- /** This blob store replaces `<dir>/blobs`. */
1358
- readonly blobs?: BlobStore | undefined;
1359
- /** This index replaces `<dir>/index.sqlite`. A runtime takes any `ReadingIndex`. */
1360
- readonly index?: ReadingIndex | undefined;
1361
- /**
1362
- * This store keeps the pace and the stops of each host. The default with `dir` is a SQLite file
1363
- * (`hosts.sqlite`), so the processes on one store share the pace. With no `dir`, it is in memory.
1364
- */
1365
- readonly hostState?: HostStateStore | undefined;
1366
- /** This token is the name that robots.txt rules match. The default is `PoliteCrawler`. */
1367
- readonly token?: string | undefined;
1368
- /** This text is the full `User-Agent` header. The default names the crawler and its page. */
1369
- readonly userAgent?: string | undefined;
1370
- /**
1371
- * This address goes into the `User-Agent` header. A mailbox (`ops@example.com`) also goes into the
1372
- * `From` header, and a URL does not. The crawler sends no contact without it.
1373
- */
1374
- readonly contact?: string | undefined;
1375
- /**
1376
- * This browser renders the pages that need JavaScript. The value `false` turns rendering off. The
1377
- * default checks one time that `playwright-core` and its browser are installed. With no browser,
1378
- * each page that needs JavaScript gets a note at once, with no wait.
1379
- */
1380
- readonly renderer?: Renderer | false | undefined;
1381
- /** This value is the number of sites that the crawler fetches from at one time. The default is 16. */
1382
- readonly maxActive?: number | undefined;
1383
- /** This value is the number of pages that the browser renders at one time. The default is 2: each render holds a browser context. */
1384
- readonly maxRenders?: number | undefined;
1385
- /** This `undici` dispatcher sends the requests. Tests give a mock agent, and a proxy is possible. */
1386
- readonly dispatcher?: Dispatcher | undefined;
1387
- /** This policy controls the addresses that the crawler fetches. By default, it fetches only public addresses. */
1388
- readonly egress?: EgressOptions | undefined;
1389
- /** These values change the limits of the politeness policy, for each host or for some hosts. */
1390
- readonly politeness?: PolicyOptions | undefined;
1391
- /** This clock gives the time to the crawler and to the index. Tests give a clock that they control. */
1392
- readonly clock?: Clock | undefined;
1393
- /** This function gives the random numbers of the jitter. The default is `Math.random`. */
1394
- readonly random?: (() => number) | undefined;
1395
- /** This label goes into each capture record. */
1396
- readonly scope?: string | undefined;
1397
- /** With the value false, the crawler does not also obey the group of `PoliteCrawler` when its `User-Agent` links the bot page (`CrawlerOptions.obeyDefaultToken`). */
1398
- readonly obeyDefaultToken?: boolean | undefined;
1399
- /** This function ranks the scopes, the most private highest. A shared fetch of a robots.txt records the scope with the highest rank (`CrawlerOptions.scopeRank`). */
1400
- readonly scopeRank?: ((scope: string) => number) | undefined;
1401
- /** This function gets an event for each request, response, wait, stop and skip. */
1402
- readonly onEvent?: ((event: CrawlEvent) => void) | undefined;
1403
- /** These extractors read the captures of the recipes of an application. The recipe `page` is built in. */
1404
- readonly extractors?: Readonly<Record<string, Extractor>> | undefined;
1405
- }
1406
- /** A runtime that a store made. It owns the parts that it made, and it closes them. */
1407
- interface StoreRuntime extends CrawlRuntime {
1408
- readonly hostState: HostStateStore;
1409
- /** This method closes the crawler, the browser, the log, the index and the host state store that the runtime made. A second close does nothing. */
1410
- close(): Promise<void>;
1411
- }
1412
- /**
1413
- * This function makes a runtime. It is the one place that puts the log, the blob store, the index,
1414
- * the host state, the crawler and the extractors together. The function `openCrawler` uses it.
1415
- * An application that needs the parts uses it too. The runtime and the crawler share one clock.
1416
- */
1417
- declare const createRuntime: (options: RuntimeOptions) => StoreRuntime;
1418
- /** These options open a crawler on a folder. Only `dir` is necessary. */
1419
- interface OpenOptions extends Omit<RuntimeOptions, "dir" | "log" | "blobs" | "index"> {
1420
- /** This folder keeps the capture log, the response bodies, the search index and the state of each host. */
1421
- readonly dir: string;
1422
- /** These agents get their robots.txt rules applied to each fetch, for example `Claude-User`. */
1423
- readonly onBehalfOf?: readonly string[] | undefined;
1424
- }
1425
- /** These options control one fetch. */
1426
- interface FetchOptions {
1427
- /** The value `auto` renders a page only when it shows almost nothing without JavaScript. */
1428
- readonly render?: "auto" | "never" | "always" | undefined;
1429
- /**
1430
- * A stored copy younger than this age answers, and the crawler sends no request. The default is
1431
- * `24h`. The value `auto` uses the freshness that the server gave. The value `0s` asks again.
1432
- */
1433
- readonly maxAge?: Duration | undefined;
1434
- /** These agents get their robots.txt rules applied to this fetch, in addition to the defaults. */
1435
- readonly onBehalfOf?: readonly string[] | undefined;
1436
- /** When this signal aborts, the crawler stops the fetch and the render. */
1437
- readonly signal?: AbortSignal | undefined;
1438
- /** This label goes into the capture records of this fetch. */
1439
- readonly scope?: string | undefined;
1440
- /** These labels go into the capture records of this fetch. They are not part of the capture ids. */
1441
- readonly labels?: Readonly<Record<string, string>> | undefined;
1442
- }
1443
- /** These options control a search. */
1444
- interface FindOptions {
1445
- /** This value is the maximum number of results. The default is 10. */
1446
- readonly limit?: number | undefined;
1447
- /** This value keeps only the documents of one kind, for example `page` or `pdf`. */
1448
- readonly kind?: string | null | undefined;
1449
- /**
1450
- * This value chooses the ranking. The default `exact` ranks each match with BM25. `fast` leaves
1451
- * the common words out of the second part of the search, so a long question is faster (`RankMode`).
1452
- */
1453
- readonly rank?: RankMode | undefined;
1454
- }
1455
- /** A polite crawler fetches each source one time, keeps it, and answers the next questions from the disk. */
1456
- interface PoliteCrawler {
1457
- /** The runtime gives the parts to an application that needs more control. */
1458
- readonly runtime: StoreRuntime;
1459
- /** This method fetches a page, reads it and adds it to the index. */
1460
- fetch(url: string, options?: FetchOptions): Promise<PageResult>;
1461
- /**
1462
- * This method searches the stored documents. It sends no request. A held-back document is not
1463
- * in the results. The syntax of the query is the syntax of `parseQuery`.
1464
- */
1465
- find(q: string, options?: FindOptions): Promise<Found[]>;
1466
- /** This method reads a range of characters of one stored document, the current version or the version of one capture. */
1467
- read(doc: string, options?: ReadOptions): Promise<ReadResult>;
1468
- /**
1469
- * This method finds a quote in a stored document. It ignores case, spaces, typographic
1470
- * punctuation and Unicode forms. It tells which capture holds the quote.
1471
- */
1472
- verify(doc: string, quote: string, options?: VerifyOptions): Promise<VerifyResult>;
1473
- /** This method gives the versions of a stored document, the newest first. A held-back version shows no title. */
1474
- versions(doc: string, options?: {
1475
- readonly limit?: number;
1476
- }): Promise<DocVersion[]>;
1477
- /**
1478
- * This method builds the index again from the capture log and the stored bodies, with no request.
1479
- * When the crawler rebuilt a stale index at open, the first reindex gives the counts of that
1480
- * rebuild, unless a fetch came before it.
1481
- */
1482
- reindex(): Promise<ReindexResult>;
1483
- /** This method closes the browser, the log files and the index. A second close does nothing. */
1484
- close(): Promise<void>;
1485
- }
1486
- /**
1487
- * This function opens a crawler on a folder. The folder keeps the capture log (`captures/`), the
1488
- * response bodies (`blobs/`), the search index (`index.sqlite`) and the state of each host
1489
- * (`hosts.sqlite`). The index is a projection: `reindex` makes it again from the log and the bodies.
1490
- * At open, `catchUpIndex` rebuilds an index of an earlier version, and gives an index that is
1491
- * behind the log the captures that it missed.
1492
- *
1493
- * Each method gives a promise, and none throws before its promise. After `close`, each method
1494
- * rejects.
1495
- */
1496
- declare const openCrawler: (options: OpenOptions) => PoliteCrawler;
1497
- //#endregion
1498
- export { FetchOutcome as $, findDocuments as A, playwrightRenderer as At, CaptureFilter as B, ReadResult as C, NO_PLAYWRIGHT as Ct, catchUpIndex as D, RenderRefused as Dt, VerifyResult as E, RenderOptions as Et, readDocument as F, CAPTURE_SCHEMA as G, CaptureReader as H, recordOverride as I, CaptureWriter as J, CacheEntry as K, reindex as L, isHeldBack as M, FileBlobStore as Mt, pageDocId as N, fetchAndIndex as O, Rendered as Ot, pageExtractor as P, DEFAULT_SECRET_PARAMS as Q, renderAndIndex as R, ReadOptions as S, VersionText as St, VerifyOptions as T, RefusedReason as Tt, DamagedLine as U, CaptureLog as V, ScanOptions as W, Crawler as X, CrawlEvent as Y, CrawlerOptions as Z, Extractors as _, Found as _t, PoliteCrawler as a, RecordInput as at, PageOptions as b, ReadingIndex as bt, createRuntime as c, EgressRefused as ct, isMailbox as d, DocIndex as dt, FetchRequest as et, openCrawler as f, DocInput as ft, Extractor as g, FindIndexOptions as gt, CrawlRuntime as h, FAST_RANK_SHARE as ht, OpenOptions as i, CaptureRecord as it, heldBackMeta as j, BlobStore as jt, fetchPage as k, Renderer as kt, defaultUserAgent as l, egressLookup as lt, CatchUpResult as m, ExtractedDoc as mt, FetchOptions as n, RenderRequest as nt, RuntimeOptions as o, makeRecord as ot, CapturePayload as p, DocVersion as pt, CacheIndex as q, FindOptions as r, renderedKey as rt, StoreRuntime as s, EgressOptions as st, Duration as t, Fetched as tt, durationMs as u, Doc as ut, HELD_BACK as v, Latest as vt, ReindexResult as w, PlaywrightRenderer as wt, PageResult as x, Variant as xt, Indexed as y, RankMode as yt, verifyQuote as z };
1499
- //# sourceMappingURL=open-eHcriTds.d.mts.map