@semiont/content 0.5.23 → 0.5.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -87,25 +87,69 @@ When the project has `[git] sync = true` in `.semiont/config`, the store keeps t
87
87
 
88
88
  Every method accepts `{ noGit: true }` to skip staging for a single call. Without git sync, the store falls back to plain filesystem operations.
89
89
 
90
- ## PDF Text-Layer Extraction
90
+ ## PDF Extraction
91
91
 
92
- For native (non-scanned) PDFs, `extractPdfTextLayer()` extracts positioned text using [pdfjs-dist](https://www.npmjs.com/package/pdfjs-dist). It returns `null` for scanned/image-only PDFs.
92
+ `EXTRACTORS['pdf-text-layer']` turns a PDF into text plus the geometry that
93
+ indexes it, routing by what the document actually holds:
94
+
95
+ | Class | Document | Read by |
96
+ |---|---|---|
97
+ | A | native text layer | pdf.js, directly |
98
+ | B | scanned — pixels only | OCR (Tesseract) |
99
+ | C | hybrid — some pages scanned | both; pages still unread are reported |
100
+ | D | tables | grid pages rewritten as markdown rows |
101
+ | E | forms | AcroForm values folded in, anchored to their widgets |
102
+ | F / G | encrypted, corrupt | declined by name, from the parser error |
93
103
 
94
104
  ```typescript
95
- import { extractPdfTextLayer, locate } from '@semiont/content';
105
+ import { EXTRACTORS } from '@semiont/content';
106
+ import { textExtractionOf, locate } from '@semiont/core';
96
107
 
97
- const layer = await extractPdfTextLayer(pdfBytes);
98
- if (layer) {
99
- console.log(layer.text); // Full extracted text
100
- console.log(layer.pages.length); // Page dimensions in PDF points
108
+ const extracted = await EXTRACTORS[textExtractionOf('application/pdf')]!
109
+ .extract(pdfBytes, 'application/pdf');
101
110
 
102
- // Find bounding rectangles for a span of the text (one per line)
103
- const rects = locate(layer, 120, 178);
104
- // => PdfCoordinate[] in PDF point space (origin: bottom-left)
111
+ if (!('declined' in extracted)) {
112
+ extracted.text; // reading-order text
113
+ extracted.items; // positioned runs indexing it
114
+ extracted.method; // 'pdf-text-layer' | 'ocr' | 'table' | 'form'
115
+ extracted.unreadPages; // class C: pages no reader could recover
105
116
  }
106
117
  ```
107
118
 
108
- Coordinates are in PDF point space, originating from the bottom-left of the page. The Y-flip to canvas pixels happens downstream in the browser; the server has no canvas. The `PdfCoordinate` geometry type lives in `@semiont/core` alongside the viewrect FragmentSelector codec.
119
+ A decline is named (`'no-text-layer' | 'encrypted' | 'corrupt' | 'too-large'`)
120
+ rather than a bare null, so a caller can settle with the reason.
121
+ `'no-text-layer'` means recognition ran and came up empty — not that it was
122
+ never attempted.
123
+
124
+ `extractPdfTextLayer()` is the lower-level reader underneath class A, returning
125
+ `null` for a document with no text operators anywhere.
126
+
127
+ Coordinates are PDF points, origin bottom-left; the Y-flip to canvas pixels
128
+ happens in the browser. The vocabulary these produce — `AnchoredText`,
129
+ `PdfTextItem` — and the `locate` / `textUnder` pair that reads it are exported
130
+ from [`@semiont/core`](../core/README.md), so the browser can reason over
131
+ geometry without importing this package's extraction stack.
132
+
133
+ ## Anchored-text store
134
+
135
+ OCR costs ~2.9 s per scanned page and six consumers read the same document, so
136
+ what the engine produced is kept rather than re-derived:
137
+
138
+ ```typescript
139
+ import { createAnchoredTextStore } from '@semiont/content';
140
+
141
+ const store = createAnchoredTextStore(dir, logger);
142
+ await store.write(checksum, { text, items });
143
+ const map = await store.read(checksum); // null on any miss
144
+ ```
145
+
146
+ Derived values only, keyed by content checksum and stamped with the versions of
147
+ this package, the engine and its traineddata. A stamp mismatch, a corrupt file
148
+ and an absent one are all the same answer: a miss. The store may make things
149
+ faster, never make them fail.
150
+
151
+ See **[ANCHORING.md](../../docs/system/ANCHORING.md)** for the pipeline this
152
+ sits in.
109
153
 
110
154
  ## Utilities
111
155
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SemiontProject } from '@semiont/core/node';
2
- import { Logger, SupportedMediaType, PdfCoordinate } from '@semiont/core';
2
+ import { Logger, SupportedMediaType, ExtractionOutcome, PdfTextItem, TextExtraction, IContentTransport, AnchoredText } from '@semiont/core';
3
3
 
4
4
  /**
5
5
  * WorkingTreeStore - Manages files in the project working tree
@@ -165,6 +165,299 @@ declare function calculateChecksum(content: string | Buffer): string;
165
165
  */
166
166
  declare function verifyChecksum(content: string | Buffer, checksum: string): boolean;
167
167
 
168
+ /**
169
+ * Anchored-text cache — the persistent half of ANCHORED-TEXT-CACHE.md Lane 2.
170
+ *
171
+ * OCR costs ~2.9 s per scanned page, and six passes read the same document (five
172
+ * detection motivations plus the smelter's embed), each its own job in its own
173
+ * process. This stores what the engine produced so only the first pass pays.
174
+ *
175
+ * **Derived values only.** Everything here is reproducible from the source
176
+ * bytes, which is what makes a stamp miss safe. An authored coordinate map is
177
+ * embedded in the PDF Semiont generated, not stored alongside one — see
178
+ * `PDF-GENERATION.md`, which owns that decision and states the negative:
179
+ * never this store.
180
+ *
181
+ * The seam is `extract()` (PERSIST-ANCHORS D1/P2b): the record is the FINISHED
182
+ * extraction outcome — classification, geometry, provenance, or a named
183
+ * decline — so a hit skips the native parse and the engine both, and every
184
+ * geometry-yielding extraction stores an entry, native documents included.
185
+ * That is what makes the anchored-text endpoint answer for every resource
186
+ * whose extraction yields geometry, and what lets the reconcile planner treat
187
+ * "no entry under the current checksum" as work (P0's third drift class).
188
+ */
189
+
190
+ /** The two halves of the wire record, split for storage. */
191
+ type SuccessOutcome = Exclude<ExtractionOutcome, {
192
+ declined: string;
193
+ }>;
194
+ type DeclineOutcome = Extract<ExtractionOutcome, {
195
+ declined: string;
196
+ }>;
197
+ /**
198
+ * One line of recognized text: the geometry every word on it shares, plus the
199
+ * per-word parts that differ.
200
+ *
201
+ * Grouping is by *contiguous runs* of equal `(y, h)`, never by scanning for all
202
+ * items at a given y. That makes the codec lossless and order-preserving for
203
+ * any input — compression is the only thing that depends on words actually
204
+ * arriving in reading order, and correctness never is.
205
+ *
206
+ * Sharing `y`/`h` is measured-safe rather than assumed: within-line word-height
207
+ * spread is 0.0pt in both native and OCR'd output, because the engine already
208
+ * normalizes word boxes to the line. Per-word `x` and `width` are stored
209
+ * explicitly and NOT derived from neighbouring split positions — deriving width
210
+ * from the gap to the next word would widen every box to touch its neighbour,
211
+ * which would silently change the coverage arithmetic `textUnder` is calibrated
212
+ * on (RUN_COVERAGE_THRESHOLD, tuned against ink-tight boxes).
213
+ */
214
+ interface CachedLine {
215
+ /** 1-indexed page. */
216
+ p: number;
217
+ /** PDF points, bottom-left origin — shared by every word on the line. */
218
+ y: number;
219
+ h: number;
220
+ /** `[x, width, start, end]` per word; offsets index `CachedAnchoredText.text`. */
221
+ words: [number, number, number, number][];
222
+ }
223
+ /**
224
+ * The stored record: one extraction OUTCOME for the whole resource
225
+ * (PERSIST-ANCHORS decision D1) — the anchored text with its provenance
226
+ * (`method`, `pdfClass`, `ocrConfidence`, `unreadPages`), or a named decline.
227
+ *
228
+ * Whole-resource on every side, deliberately. The producer's own shape is a
229
+ * per-page map, but that is an artifact of how `ocrPages` iterates, and letting
230
+ * it reach storage would have forced every consumer — the transport, the
231
+ * browser, a headless client — to reassemble pages it never asked to see.
232
+ *
233
+ * The `ocrConfidence` SUMMARY is stored (v2) — this repairs the regression
234
+ * OCR-CONFIDENCE-LOST.md records, where a hit answered with no confidence at
235
+ * all. Per-word confidences remain unstored: the summary is the record's
236
+ * quality provenance; the word list is operator log detail.
237
+ *
238
+ * v1 records (bare `{ text, lines }`, no provenance) read as misses under the
239
+ * v2 prefix; the reconcile planner's third drift class re-derives them.
240
+ */
241
+ type CachedAnchoredText = ({
242
+ v: 2;
243
+ /** Engine + traineddata + our assembly code. A mismatch is a clean miss. */
244
+ stamp: string;
245
+ text: string;
246
+ lines: CachedLine[];
247
+ } & Omit<SuccessOutcome, 'text' | 'items'>) | ({
248
+ v: 2;
249
+ stamp: string;
250
+ } & DeclineOutcome);
251
+ interface AnchoredTextStore {
252
+ /**
253
+ * The stored map for this key, or null for any miss. Never throws.
254
+ *
255
+ * The key is the **content checksum of the bytes the map derives from**
256
+ * (PERSIST-ANCHORS decision A): a representation is its bytes, so the
257
+ * checksum is its identity, and geometry derived from one revision of the
258
+ * bytes is unreachable by a reader holding a different revision — by
259
+ * construction, not by invalidation. Callers holding some other handle
260
+ * (a resource id) reach the artifact through an index, not by a second
261
+ * key scheme here.
262
+ */
263
+ read(key: string): Promise<ExtractionOutcome | null>;
264
+ /** Record an extraction outcome under the content checksum of its source
265
+ * bytes. A store that cannot write is still a store. */
266
+ write(key: string, outcome: ExtractionOutcome): Promise<void>;
267
+ /**
268
+ * Every key `read()` would currently HIT — entries under a stale stamp or
269
+ * unreadable files are excluded, exactly as `read()` would exclude them.
270
+ * That equivalence is load-bearing: the reconcile planner treats a listed
271
+ * key as "artifact present" and plans re-derivation for the rest
272
+ * (PERSIST-ANCHORS P0, the third drift class), so a key listed here but
273
+ * missed by `read()` would be a permanent loss the diff can never see —
274
+ * the exact shape of the post-engine-upgrade hole this filter closes.
275
+ * One bulk call per reconcile, never a probe per resource. Never throws.
276
+ */
277
+ list(): Promise<string[]>;
278
+ }
279
+ /**
280
+ * A file-backed store under `dir` — one file per content key, sharded as
281
+ * `{ab}/{cd}/{key}.json` via the same `getShardPath` the event log uses
282
+ * (PERSIST-ANCHORS decision E). Same convention, separate tree: `.semiont/`
283
+ * is the KB's committed system of record; everything here is derived,
284
+ * reclaimable, and never a source of truth.
285
+ *
286
+ * `dir` is the caller's, out of `Project.anchoredTextDir`: this package has no idea
287
+ * which project it is serving. Every failure path is a miss rather than an
288
+ * error, matching the rule extraction already follows for unreadable pages —
289
+ * the cache may make things faster, never make them fail.
290
+ */
291
+ declare function createAnchoredTextStore(dir: string, logger?: Logger): AnchoredTextStore;
292
+
293
+ /**
294
+ * ContentExtractor — strategy-keyed text extraction for embedding.
295
+ *
296
+ * The registry is keyed by `TextExtraction` from `@semiont/core` — the
297
+ * media-type registry's dispatch vocabulary — never by a second media-type
298
+ * list (SMELTER-MEDIA-TYPES.md, Design §1): there is exactly one media-type
299
+ * table in the system, and this registry consumes it. The Smelter resolves
300
+ * `textExtractionOf(contentType)` and looks the extractor up by strategy; a
301
+ * `null` slot means decline (settle skipped, reason 'no-extractor').
302
+ *
303
+ * Extraction is ephemeral: `extract` runs at read time, its output feeds the
304
+ * chunker, and is discarded — no stored derived representation. Annotations
305
+ * anchor to native geometry (`items`), never to extracted-text offsets, so
306
+ * re-extraction can never break an anchor.
307
+ */
308
+
309
+ interface ExtractedText {
310
+ /** Reading-order plain text, ready for the chunker. */
311
+ text: string;
312
+ /**
313
+ * Positioned text runs indexing `text`, for callers that anchor; absent for
314
+ * pure text, where character offsets are the anchor. Named `items` to match
315
+ * `AnchoredText`/`PdfTextLayer` — one concept, one name, and no collision
316
+ * with the OCR engine's own "blocks" (which are page regions, not runs).
317
+ */
318
+ items?: PdfTextItem[];
319
+ method: 'text-passthrough' | 'pdf-text-layer' | 'table' | 'form' | 'ocr';
320
+ pdfClass?: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G';
321
+ /**
322
+ * How well the engine read the pixels, when any of this text came from OCR.
323
+ *
324
+ * Extraction quality, deliberately NOT anchor confidence: the two answer
325
+ * different questions. `AnchorConfidence` asks whether the renderer
326
+ * relocated a stored span in the current text, and for a PDF the answer is
327
+ * always "exactly" — the viewrect is absolute. This asks whether the glyphs
328
+ * under that box were read correctly, which no client can recompute.
329
+ * Reported for operators rather than stored on annotations, following the
330
+ * existing rule that anchor-audit detail belongs in logs.
331
+ */
332
+ ocrConfidence?: {
333
+ /** Mean per-word confidence, 0–100. */
334
+ mean: number;
335
+ /** Words the engine was unsure of — the number worth acting on. */
336
+ lowConfidenceWords: number;
337
+ totalWords: number;
338
+ };
339
+ /**
340
+ * 1-indexed pages this extraction could not read — present only when a
341
+ * document is partially covered (class C). Naming the gap is the point:
342
+ * without it a hybrid document embeds its native pages and says nothing
343
+ * about the rest, so coverage silently overstates what search can see.
344
+ * This is the work list OCR consumes.
345
+ */
346
+ unreadPages?: number[];
347
+ }
348
+ /**
349
+ * A named decline — an extractor that ran and decided it cannot yield text
350
+ * says why, so the settled signal can carry the class reason (a bare null
351
+ * could not name its class; SMELTER-MEDIA-TYPES Phase 0 log, note a).
352
+ */
353
+ interface ExtractionDecline {
354
+ declined: 'no-text-layer' | 'encrypted' | 'corrupt' | 'too-large';
355
+ }
356
+ /**
357
+ * Where a strategy may reuse an earlier recognition, and under what key.
358
+ *
359
+ * The caller supplies the key, and derives it from the bytes it actually
360
+ * holds — `calculateChecksum` over the same Buffer it passes to `extract()` —
361
+ * never from a descriptor's claim. A catalog-derived key can race a byte
362
+ * change (bytes fetched at one moment, descriptor read at another) and file
363
+ * or read geometry under an identity that does not describe the bytes being
364
+ * extracted. The write path made recompute-over-claim the rule
365
+ * (PERSIST-ANCHORS P1b); readers mirror it (P1c). One SHA-256 over bytes
366
+ * already in memory is noise against the engine pass a hit avoids.
367
+ *
368
+ * Optional throughout: a caller that passes nothing extracts uncached and is
369
+ * unaffected. The seam is `extract()` itself (PERSIST-ANCHORS D1/P2b): a hit
370
+ * returns the FINISHED outcome — classification, geometry, provenance, or a
371
+ * named decline — so neither the native parse nor the engine runs. Every
372
+ * geometry-yielding extraction produces an entry, native documents included;
373
+ * the 'decode' strategy ignores the cache (no geometry, nothing expensive).
374
+ */
375
+ interface ExtractionCache {
376
+ key: string;
377
+ store: AnchoredTextStore;
378
+ }
379
+ interface ContentExtractor {
380
+ /**
381
+ * Whether this strategy's extractions carry positioned runs (`items`) — the
382
+ * geometry an anchored-text artifact is made of. Declared, not probed:
383
+ * the reconcile planner must know "should an artifact exist?" without
384
+ * running the extractor (PERSIST-ANCHORS P0, the third drift class), and
385
+ * the declaration keeps the planner's gate and the live fetch's behavior
386
+ * twins by construction. Text strategies anchor by character offset and
387
+ * declare false.
388
+ */
389
+ yieldsGeometry: boolean;
390
+ /**
391
+ * Extract embeddable/annotatable text, or decline with the class reason
392
+ * (scanned-without-OCR, encrypted, corrupt). The caller skips embedding
393
+ * and settles skipped with that reason.
394
+ */
395
+ extract(content: Buffer, mediaType: string, cache?: ExtractionCache): Promise<ExtractedText | ExtractionDecline>;
396
+ }
397
+ /**
398
+ * Strategy → extractor. A `null` slot is a decline: the strategy names a
399
+ * capability nothing currently provides ('none' permanently).
400
+ */
401
+ declare const EXTRACTORS: Record<TextExtraction, ContentExtractor | null>;
402
+
403
+ /**
404
+ * PDF extractor — the 'pdf-text-layer' strategy (SMELTER-MEDIA-TYPES).
405
+ *
406
+ * Wraps the shared `extractPdfTextLayer` reader (detection's other consumer)
407
+ * and turns a PDF into text plus the geometry that indexes it, by class:
408
+ *
409
+ * A native text layer → read directly
410
+ * B scanned → read the page pixels by OCR
411
+ * C hybrid → both, with any page still unread reported
412
+ * D tables → grid pages rewritten as markdown rows
413
+ * E forms → AcroForm values folded in, anchored to widgets
414
+ * F/G encrypted, corrupt → declined by name, from the parser error
415
+ *
416
+ * Everything runs inline. OCR was originally planned off the hot path, but
417
+ * the Smelter's lanes are per-resource and concurrent, so a slow page delays
418
+ * only its own resource — see SMELTER-MEDIA-TYPES Design §4 (revised).
419
+ */
420
+
421
+ /**
422
+ * Largest PDF this will attempt, in bytes.
423
+ *
424
+ * A PDF is a compressed container, so input size bounds nothing on its own —
425
+ * but it is the one number available before the parser touches the file, and
426
+ * refusing here means a hostile or pathological document never gets to expand
427
+ * inside pdf.js. Chosen to sit above real corpora (a few hundred pages of
428
+ * scanned FOIA material runs tens of megabytes) while still being a ceiling.
429
+ *
430
+ * A starting point, not a measured optimum — revisit against a real corpus
431
+ * (SMELTER-MEDIA-TYPES, live-testing follow-up). The per-image budget in
432
+ * `pdf-page-images` guards the decoded side, which is where the unbounded
433
+ * growth actually lives.
434
+ */
435
+ declare const MAX_PDF_BYTES: number;
436
+ /** Whether a document is small enough to attempt. Exported because the
437
+ * threshold is a judgement, and judgements deserve tests that do not have to
438
+ * materialize two hundred megabytes to ask the question. */
439
+ declare function withinByteBudget(bytes: number): boolean;
440
+
441
+ /**
442
+ * `AnchoredTextStore` over `IContentTransport` — how an out-of-process
443
+ * extraction seam reaches the one real store (PERSIST-ANCHORS P2c).
444
+ *
445
+ * Every cache consumer runs outside the backend — the smelter worker and the
446
+ * detection workers — while the KnowledgeSystem owns the storage. This
447
+ * adapter maps the store contract onto the transport's three
448
+ * checksum-addressed calls, so `ExtractionCache { key, store }` works
449
+ * identically in-process (LocalContentTransport → the store directly) and
450
+ * over the wire (HttpContentTransport → the /anchored-text routes).
451
+ *
452
+ * It honors the store contract's failure rule — the cache may make things
453
+ * faster, never make them fail: a read or list failure is a miss, a write
454
+ * failure is swallowed (debug-logged). Callers that need a write to be LOUD
455
+ * — the re-anchor path, whose artifact IS the job — use the transport's
456
+ * `putAnchoredText` directly, not this adapter.
457
+ */
458
+
459
+ declare function anchoredTextStoreOverTransport(content: IContentTransport, logger?: Logger): AnchoredTextStore;
460
+
168
461
  /**
169
462
  * PDF Text Layer Types
170
463
  *
@@ -173,37 +466,58 @@ declare function verifyChecksum(content: string | Buffer, checksum: string): boo
173
466
  * (Y increases upward). The Y-flip to canvas pixels happens downstream in the
174
467
  * browser; the server has no canvas.
175
468
  *
176
- * `PdfCoordinate` the geometry `locate()` emitslives in `@semiont/core`
177
- * alongside the viewrect FragmentSelector codec.
469
+ * The anchoring vocabulary these build on`AnchoredText`, `PdfTextItem`,
470
+ * `PdfCoordinate`, and the `locate`/`textUnder` pair — lives in `@semiont/core`
471
+ * alongside the viewrect FragmentSelector codec, so the browser can reason over
472
+ * geometry without importing this package's extraction stack.
178
473
  */
474
+
179
475
  /**
180
- * A single text item (one text run, roughly a word) from the PDF text layer.
181
- * Character offsets refer to positions in `PdfTextLayer.text`.
476
+ * One filled AcroForm field: the value a form carries outside its drawn text
477
+ * layer. Geometry is the widget's rectangle, in the same PDF-point,
478
+ * bottom-left-origin space as `PdfTextItem` — so a consumer that folds field
479
+ * values into text can anchor them like any other run.
182
480
  */
183
- interface PdfTextItem {
184
- start: number;
185
- end: number;
481
+ interface PdfFormField {
482
+ name: string;
483
+ value: string;
186
484
  page: number;
187
485
  x: number;
188
486
  y: number;
189
487
  width: number;
190
488
  height: number;
191
489
  }
192
- /** Page dimensions in PDF points */
490
+ /** Page dimensions in PDF points, plus the page's span of `PdfTextLayer.text` */
193
491
  interface PdfPageInfo {
194
492
  pageNumber: number;
195
493
  widthPt: number;
196
494
  heightPt: number;
495
+ textStart: number;
496
+ textEnd: number;
497
+ /**
498
+ * Whether this page carries text-showing operators. False means the page
499
+ * is scanned: its characters exist only as pixels, so reading it needs
500
+ * OCR rather than `getTextContent`. Per-PAGE, deliberately: a document
501
+ * mixing native and scanned pages (class C) must route each page
502
+ * separately, and a single document-level flag cannot express that.
503
+ */
504
+ hasTextLayer: boolean;
197
505
  }
198
506
  /**
199
507
  * The full extracted text layer for a PDF.
200
508
  * `text` is the reading-order concatenation across all pages.
201
509
  * Each `item` is one text run carrying its character range into `text` plus PDF-point geometry.
202
510
  */
203
- interface PdfTextLayer {
511
+ interface PdfTextLayer extends AnchoredText {
204
512
  pages: PdfPageInfo[];
205
- text: string;
206
- items: PdfTextItem[];
513
+ /**
514
+ * Filled AcroForm field values, empty for a document without a form.
515
+ * Deliberately NOT folded into `text`: the reader reports what the
516
+ * document holds, and each consumer projects what it needs — detection
517
+ * reads `text`/`items` and is unaffected by a form's presence, while the
518
+ * embedding extractor folds these in (SMELTER-MEDIA-TYPES class E).
519
+ */
520
+ fields: PdfFormField[];
207
521
  }
208
522
 
209
523
  /**
@@ -218,22 +532,5 @@ interface PdfTextLayer {
218
532
 
219
533
  declare function extractPdfTextLayer(bytes: Uint8Array | Buffer): Promise<PdfTextLayer | null>;
220
534
 
221
- /**
222
- * Locates bounding rectangles for a span of text in a PdfTextLayer
223
- * (single-line or multi-line).
224
- *
225
- * Finds all overlapping items [start, end), groups them by page and line, and
226
- * records one bounding rectangle per line as a PdfCoordinate.
227
- *
228
- * Returns both the per-line `rects` and the `overlap` items they were computed
229
- * from — so a caller that also needs the covered text (e.g. buildPdfAnnotation's
230
- * geometry↔text containment invariant) reuses this single `layer.items` scan
231
- * instead of re-filtering. Both arrays are empty if no item overlaps the span.
232
- */
233
- declare function locate(layer: PdfTextLayer, start: number, end: number): {
234
- rects: PdfCoordinate[];
235
- overlap: PdfTextItem[];
236
- };
237
-
238
- export { ChecksumMismatchError, WorkingTreeStore, calculateChecksum, deriveStorageUri, extractPdfTextLayer, locate, verifyChecksum };
239
- export type { PdfPageInfo, PdfTextItem, PdfTextLayer, StoredResource };
535
+ export { ChecksumMismatchError, EXTRACTORS, MAX_PDF_BYTES, WorkingTreeStore, anchoredTextStoreOverTransport, calculateChecksum, createAnchoredTextStore, deriveStorageUri, extractPdfTextLayer, verifyChecksum, withinByteBudget };
536
+ export type { AnchoredTextStore, CachedAnchoredText, CachedLine, ContentExtractor, ExtractedText, ExtractionCache, ExtractionDecline, PdfFormField, PdfPageInfo, PdfTextLayer, StoredResource };