@adeu/core 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -65,6 +65,8 @@ interface TextSpan {
65
65
  del_id?: string | null;
66
66
  hyperlink_id?: string | null;
67
67
  comment_ids?: string[];
68
+ part_index: number;
69
+ is_image_marker?: boolean;
68
70
  }
69
71
  declare class DocumentMapper {
70
72
  doc: DocumentObject;
@@ -74,10 +76,26 @@ declare class DocumentMapper {
74
76
  full_text: string;
75
77
  spans: TextSpan[];
76
78
  appendix_start_index: number;
79
+ part_ranges: [number, number, string][];
80
+ private _current_part_index;
77
81
  private _text_chunks;
78
82
  private _plain_projection;
79
83
  constructor(doc: DocumentObject, clean_view?: boolean, original_view?: boolean);
80
84
  private _build_map;
85
+ /** [part_index, start, end, kind] for parts that projected any text. */
86
+ private _nonempty_part_ranges;
87
+ part_kind_of(part_index: number): string | null;
88
+ /** Kind of the part whose projected range contains `index`, or null. */
89
+ part_kind_at(index: number): string | null;
90
+ /**
91
+ * When `index` falls strictly AFTER one part's text and at-or-before the
92
+ * start of the next part's text (i.e. inside the "\n\n" separator or
93
+ * exactly at the next part's first character), returns
94
+ * [previous_part_index, next_part_index]. Returns null everywhere else —
95
+ * including index == previous part's end, which is an ordinary
96
+ * end-of-part text position, not a boundary gap.
97
+ */
98
+ part_boundary_at(index: number): [number, number] | null;
81
99
  private _map_blocks;
82
100
  private _map_table;
83
101
  private _strip_markdown_formatting;
@@ -197,6 +215,8 @@ declare class BatchValidationError extends Error {
197
215
  errors: string[];
198
216
  constructor(errors: string[]);
199
217
  }
218
+ declare function describe_illegal_control_chars(text: string): string | null;
219
+ declare function validate_edit_strings(edits: any[], index_offset?: number): string[];
200
220
  declare class RedlineEngine {
201
221
  doc: DocumentObject;
202
222
  author: string;
@@ -243,8 +263,8 @@ declare class RedlineEngine {
243
263
  * Snapshots the document text around a resolved edit BEFORE anything is
244
264
  * applied. Previews rendered after the batch mutates the DOM cannot slice
245
265
  * full_text at the stored offsets: applied edits shift offsets and inject
246
- * tracked-change markup, which produced garbled previews mixing unrelated
247
- * edits and internal scaffolding (QA H1).
266
+ * tracked-change markup, garbling previews with unrelated edits and
267
+ * internal scaffolding (QA H1).
248
268
  */
249
269
  private _capture_preview_context;
250
270
  /**
@@ -263,8 +283,8 @@ declare class RedlineEngine {
263
283
  private _build_full_match_preview;
264
284
  /**
265
285
  * The "new text" a batch report should show for an edit. InsertTableRow has
266
- * no new_text field — surface its cell contents instead of the misleading
267
- * empty string the report used to print (QA M4).
286
+ * no new_text field — surface its cell contents rather than a misleading
287
+ * empty string (QA M4).
268
288
  */
269
289
  private static _report_new_text;
270
290
  private _build_edit_context_previews;
@@ -303,6 +323,19 @@ declare class RedlineEngine {
303
323
  private _getNextId;
304
324
  private _create_track_change_tag;
305
325
  private _set_text_content;
326
+ /**
327
+ * Walks `element` to its XML root element. Word (and LibreOffice, which
328
+ * refuses to LOAD such files) only supports comment ranges in the main
329
+ * document story ("w:document") — never in headers, footers, footnotes or
330
+ * endnotes (QA 2026-07-18 H4/C1).
331
+ */
332
+ private _comment_anchor_in_main_story;
333
+ /**
334
+ * When the anchor lives outside the main document story, records a
335
+ * user-visible warning and returns true (caller must skip the comment).
336
+ * The tracked change itself still applies — only the bubble is dropped.
337
+ */
338
+ private _skip_comment_outside_main_story;
306
339
  /**
307
340
  * Attaches a comment that wraps a contiguous range within a single paragraph.
308
341
  * start_element and end_element must both be direct children of parent_element
@@ -393,6 +426,13 @@ declare class RedlineEngine {
393
426
  * [start, start+length) in `mapper`, or null if that text is not inside a
394
427
  * table row.
395
428
  */
429
+ /**
430
+ * True when a replacement anchored in a table would ADD line-separated
431
+ * pipe-delimited content — the text shape of a table row. Writing that
432
+ * into a cell renders a fake row inside one cell while the real grid
433
+ * stays unchanged (QA 2026-07-18 C2); such edits must use insert_row.
434
+ */
435
+ private static _introduces_table_row_text;
396
436
  private static _column_count_at;
397
437
  validate_review_actions(actions: any[]): string[];
398
438
  process_batch(changes: DocumentChange[], dry_run?: boolean): any;
@@ -413,12 +453,86 @@ declare class RedlineEngine {
413
453
  private _apply_single_edit_indexed;
414
454
  }
415
455
 
456
+ /** Text-space extent of one projected table row plus its cell texts. */
457
+ interface RowGeometry {
458
+ start: number;
459
+ end: number;
460
+ cells: string[];
461
+ }
462
+ /** Text-space extent of one projected top-level table. */
463
+ interface TableGeometry {
464
+ start: number;
465
+ end: number;
466
+ rows: RowGeometry[];
467
+ }
468
+ /**
469
+ * Structural map of a projection: which offset ranges belong to which OPC
470
+ * part, and where top-level table rows live. Produced in the SAME pass as
471
+ * the text, so offsets always agree with it. Consumed by the diff pipeline
472
+ * to keep generated edits from crossing part boundaries (QA 2026-07-18 C1)
473
+ * and to emit structured row operations for table changes (QA C2).
474
+ */
475
+ interface ExtractStructure {
476
+ part_ranges: [number, number, string][];
477
+ tables: TableGeometry[];
478
+ }
479
+ declare function extractTextFromBuffer(buffer: Buffer, cleanView?: boolean, includeAppendix?: boolean): Promise<string>;
480
+ declare function _extractTextFromDoc(doc: DocumentObject, cleanView?: boolean, includeAppendix?: boolean, return_paragraph_offsets?: boolean, return_structure?: boolean): string | {
481
+ text: string;
482
+ paragraph_offsets: Map<any, [number, number]>;
483
+ } | {
484
+ text: string;
485
+ structure: ExtractStructure;
486
+ };
487
+
488
+ type DiffEdit = ModifyText | InsertTableRow | DeleteTableRow;
416
489
  declare function trim_common_context(target: string, new_val: string): [number, number];
417
490
  declare function generate_edits_from_text(original_text: string, modified_text: string): ModifyText[];
491
+ /**
492
+ * DOCX-to-DOCX diff over projections extracted with return_structure=true.
493
+ *
494
+ * Improvements over a flat generate_edits_from_text pass:
495
+ * - each OPC part (header/body/footer/notes) diffs against its
496
+ * counterpart, so no edit can span a part boundary and content that
497
+ * moved between parts is reported instead of hidden (QA 2026-07-18 C1);
498
+ * - table row insertions/deletions become structured insert_row /
499
+ * delete_row operations instead of pipe-text edits (QA C2).
500
+ *
501
+ * Every ModifyText keeps its _match_start_index pinned into text_orig, which
502
+ * the engine consumes positionally (the Node engine has no
503
+ * make_edits_self_contained JSON round trip like the Python CLI).
504
+ *
505
+ * Returns { edits, warnings }. Warnings describe fallbacks the caller should
506
+ * surface (differing part layouts, unanchorable rows, …).
507
+ */
508
+ declare function generate_structured_edits(text_orig: string, struct_orig: ExtractStructure, text_mod: string, struct_mod: ExtractStructure): {
509
+ edits: DiffEdit[];
510
+ warnings: string[];
511
+ };
418
512
  declare function create_unified_diff(original_text: string, modified_text: string, context_lines?: number): string;
419
513
  declare function create_word_patch_diff(original_text: string, modified_text: string, original_path?: string, modified_path?: string): string;
420
514
 
421
- declare function apply_edits_to_markdown(markdown_text: string, edits: ModifyText[], include_index?: boolean, highlight_only?: boolean): string;
515
+ /** One entry per input edit in apply_edits_to_markdown's edit_reports. */
516
+ interface MarkupEditReport {
517
+ index: number;
518
+ status: "applied" | "failed";
519
+ error: string | null;
520
+ occurrences: number;
521
+ }
522
+ /**
523
+ * Applies edits to Markdown text and returns CriticMarkup-annotated output.
524
+ *
525
+ * Edit resolution follows the SAME semantics as `apply` (QA 2026-07-18 M1):
526
+ * - `regex: true` targets match as regular expressions
527
+ * - `match_mode` is honored: "strict" (default) refuses ambiguous targets,
528
+ * "first" marks the first occurrence, "all" marks every occurrence
529
+ * - a missing target is a per-edit failure, never a silent skip
530
+ *
531
+ * When `edit_reports` is provided, one entry per input edit is appended:
532
+ * { index: 0-based input position, status: "applied"|"failed",
533
+ * error: string|null, occurrences: number }.
534
+ */
535
+ declare function apply_edits_to_markdown(markdown_text: string, edits: ModifyText[], include_index?: boolean, highlight_only?: boolean, edit_reports?: MarkupEditReport[]): string;
422
536
 
423
537
  /**
424
538
  * Stateless paginator for projected DOCX Markdown.
@@ -454,12 +568,6 @@ interface OutlineNode {
454
568
  }
455
569
  declare function extract_outline(doc: DocumentObject, projected_body: string, body_pages: string[], body_page_offsets: number[], paragraph_offsets?: Record<string, [number, number]> | Map<any, [number, number]> | null): OutlineNode[];
456
570
 
457
- declare function extractTextFromBuffer(buffer: Buffer, cleanView?: boolean): Promise<string>;
458
- declare function _extractTextFromDoc(doc: DocumentObject, cleanView?: boolean, includeAppendix?: boolean, return_paragraph_offsets?: boolean): string | {
459
- text: string;
460
- paragraph_offsets: Map<any, [number, number]>;
461
- };
462
-
463
571
  interface FinalizeOptions {
464
572
  filename: string;
465
573
  sanitize_mode?: 'full' | 'keep-markup' | 'baseline';
@@ -475,6 +583,42 @@ interface FinalizeResult {
475
583
  }
476
584
  declare function finalize_document(doc: DocumentObject, options: FinalizeOptions): Promise<FinalizeResult>;
477
585
 
586
+ /**
587
+ * Time-budgeted execution of USER/LLM-supplied regular expressions.
588
+ *
589
+ * `regex: true` on a ModifyText edit and `search_regex` on read_docx hand an
590
+ * LLM-controlled pattern to V8's backtracking engine. A pathological pattern
591
+ * like `(a|a)*$` against a run of repeated characters hangs the event loop
592
+ * indefinitely (QA 2026-07-17 F5 — ReDoS; mirrors the Python fix).
593
+ *
594
+ * JS regexes cannot be interrupted in-thread, but V8 CAN interrupt regex
595
+ * execution running inside a `vm` context with a `timeout` — that is the
596
+ * mechanism used here. `node:vm` is a builtin, preserving the zero-dependency
597
+ * bundle constraint.
598
+ *
599
+ * Only USER-SUPPLIED patterns belong here. The engine's own generated
600
+ * patterns (fuzzy matchers etc.) are built to be linear-time.
601
+ */
602
+ declare const USER_PATTERN_TIMEOUT_MS = 2000;
603
+ declare class RegexTimeoutError extends Error {
604
+ pattern: string;
605
+ constructor(pattern: string);
606
+ }
607
+ /**
608
+ * All non-overlapping matches of a user pattern, under the wall-clock budget.
609
+ * Invalid patterns throw SyntaxError exactly like `new RegExp(...)` would.
610
+ * The budget covers the ENTIRE scan, not just the first match.
611
+ */
612
+ declare function userFindAllMatches(pattern: string, text: string, flags?: string): Array<{
613
+ start: number;
614
+ end: number;
615
+ }>;
616
+ /** First match of a user pattern under the wall-clock budget, or null. */
617
+ declare function userSearch(pattern: string, text: string, flags?: string): {
618
+ start: number;
619
+ end: number;
620
+ } | null;
621
+
478
622
  declare function identifyEngine(): string;
479
623
 
480
- export { BatchValidationError, DocumentMapper, DocumentObject, type FinalizeOptions, type FinalizeResult, type OutlineNode, type PageInfo, type PaginationResult, RedlineEngine, type TextSpan, _extractTextFromDoc, apply_edits_to_markdown, create_unified_diff, create_word_patch_diff, extractTextFromBuffer, extract_outline, finalize_document, generate_edits_from_text, identifyEngine, paginate, split_structural_appendix, trim_common_context };
624
+ export { BatchValidationError, type DiffEdit, DocumentMapper, DocumentObject, type ExtractStructure, type FinalizeOptions, type FinalizeResult, type MarkupEditReport, type OutlineNode, type PageInfo, type PaginationResult, RedlineEngine, RegexTimeoutError, type RowGeometry, type TableGeometry, type TextSpan, USER_PATTERN_TIMEOUT_MS, _extractTextFromDoc, apply_edits_to_markdown, create_unified_diff, create_word_patch_diff, describe_illegal_control_chars, extractTextFromBuffer, extract_outline, finalize_document, generate_edits_from_text, generate_structured_edits, identifyEngine, paginate, split_structural_appendix, trim_common_context, userFindAllMatches, userSearch, validate_edit_strings };
package/dist/index.d.ts CHANGED
@@ -65,6 +65,8 @@ interface TextSpan {
65
65
  del_id?: string | null;
66
66
  hyperlink_id?: string | null;
67
67
  comment_ids?: string[];
68
+ part_index: number;
69
+ is_image_marker?: boolean;
68
70
  }
69
71
  declare class DocumentMapper {
70
72
  doc: DocumentObject;
@@ -74,10 +76,26 @@ declare class DocumentMapper {
74
76
  full_text: string;
75
77
  spans: TextSpan[];
76
78
  appendix_start_index: number;
79
+ part_ranges: [number, number, string][];
80
+ private _current_part_index;
77
81
  private _text_chunks;
78
82
  private _plain_projection;
79
83
  constructor(doc: DocumentObject, clean_view?: boolean, original_view?: boolean);
80
84
  private _build_map;
85
+ /** [part_index, start, end, kind] for parts that projected any text. */
86
+ private _nonempty_part_ranges;
87
+ part_kind_of(part_index: number): string | null;
88
+ /** Kind of the part whose projected range contains `index`, or null. */
89
+ part_kind_at(index: number): string | null;
90
+ /**
91
+ * When `index` falls strictly AFTER one part's text and at-or-before the
92
+ * start of the next part's text (i.e. inside the "\n\n" separator or
93
+ * exactly at the next part's first character), returns
94
+ * [previous_part_index, next_part_index]. Returns null everywhere else —
95
+ * including index == previous part's end, which is an ordinary
96
+ * end-of-part text position, not a boundary gap.
97
+ */
98
+ part_boundary_at(index: number): [number, number] | null;
81
99
  private _map_blocks;
82
100
  private _map_table;
83
101
  private _strip_markdown_formatting;
@@ -197,6 +215,8 @@ declare class BatchValidationError extends Error {
197
215
  errors: string[];
198
216
  constructor(errors: string[]);
199
217
  }
218
+ declare function describe_illegal_control_chars(text: string): string | null;
219
+ declare function validate_edit_strings(edits: any[], index_offset?: number): string[];
200
220
  declare class RedlineEngine {
201
221
  doc: DocumentObject;
202
222
  author: string;
@@ -243,8 +263,8 @@ declare class RedlineEngine {
243
263
  * Snapshots the document text around a resolved edit BEFORE anything is
244
264
  * applied. Previews rendered after the batch mutates the DOM cannot slice
245
265
  * full_text at the stored offsets: applied edits shift offsets and inject
246
- * tracked-change markup, which produced garbled previews mixing unrelated
247
- * edits and internal scaffolding (QA H1).
266
+ * tracked-change markup, garbling previews with unrelated edits and
267
+ * internal scaffolding (QA H1).
248
268
  */
249
269
  private _capture_preview_context;
250
270
  /**
@@ -263,8 +283,8 @@ declare class RedlineEngine {
263
283
  private _build_full_match_preview;
264
284
  /**
265
285
  * The "new text" a batch report should show for an edit. InsertTableRow has
266
- * no new_text field — surface its cell contents instead of the misleading
267
- * empty string the report used to print (QA M4).
286
+ * no new_text field — surface its cell contents rather than a misleading
287
+ * empty string (QA M4).
268
288
  */
269
289
  private static _report_new_text;
270
290
  private _build_edit_context_previews;
@@ -303,6 +323,19 @@ declare class RedlineEngine {
303
323
  private _getNextId;
304
324
  private _create_track_change_tag;
305
325
  private _set_text_content;
326
+ /**
327
+ * Walks `element` to its XML root element. Word (and LibreOffice, which
328
+ * refuses to LOAD such files) only supports comment ranges in the main
329
+ * document story ("w:document") — never in headers, footers, footnotes or
330
+ * endnotes (QA 2026-07-18 H4/C1).
331
+ */
332
+ private _comment_anchor_in_main_story;
333
+ /**
334
+ * When the anchor lives outside the main document story, records a
335
+ * user-visible warning and returns true (caller must skip the comment).
336
+ * The tracked change itself still applies — only the bubble is dropped.
337
+ */
338
+ private _skip_comment_outside_main_story;
306
339
  /**
307
340
  * Attaches a comment that wraps a contiguous range within a single paragraph.
308
341
  * start_element and end_element must both be direct children of parent_element
@@ -393,6 +426,13 @@ declare class RedlineEngine {
393
426
  * [start, start+length) in `mapper`, or null if that text is not inside a
394
427
  * table row.
395
428
  */
429
+ /**
430
+ * True when a replacement anchored in a table would ADD line-separated
431
+ * pipe-delimited content — the text shape of a table row. Writing that
432
+ * into a cell renders a fake row inside one cell while the real grid
433
+ * stays unchanged (QA 2026-07-18 C2); such edits must use insert_row.
434
+ */
435
+ private static _introduces_table_row_text;
396
436
  private static _column_count_at;
397
437
  validate_review_actions(actions: any[]): string[];
398
438
  process_batch(changes: DocumentChange[], dry_run?: boolean): any;
@@ -413,12 +453,86 @@ declare class RedlineEngine {
413
453
  private _apply_single_edit_indexed;
414
454
  }
415
455
 
456
+ /** Text-space extent of one projected table row plus its cell texts. */
457
+ interface RowGeometry {
458
+ start: number;
459
+ end: number;
460
+ cells: string[];
461
+ }
462
+ /** Text-space extent of one projected top-level table. */
463
+ interface TableGeometry {
464
+ start: number;
465
+ end: number;
466
+ rows: RowGeometry[];
467
+ }
468
+ /**
469
+ * Structural map of a projection: which offset ranges belong to which OPC
470
+ * part, and where top-level table rows live. Produced in the SAME pass as
471
+ * the text, so offsets always agree with it. Consumed by the diff pipeline
472
+ * to keep generated edits from crossing part boundaries (QA 2026-07-18 C1)
473
+ * and to emit structured row operations for table changes (QA C2).
474
+ */
475
+ interface ExtractStructure {
476
+ part_ranges: [number, number, string][];
477
+ tables: TableGeometry[];
478
+ }
479
+ declare function extractTextFromBuffer(buffer: Buffer, cleanView?: boolean, includeAppendix?: boolean): Promise<string>;
480
+ declare function _extractTextFromDoc(doc: DocumentObject, cleanView?: boolean, includeAppendix?: boolean, return_paragraph_offsets?: boolean, return_structure?: boolean): string | {
481
+ text: string;
482
+ paragraph_offsets: Map<any, [number, number]>;
483
+ } | {
484
+ text: string;
485
+ structure: ExtractStructure;
486
+ };
487
+
488
+ type DiffEdit = ModifyText | InsertTableRow | DeleteTableRow;
416
489
  declare function trim_common_context(target: string, new_val: string): [number, number];
417
490
  declare function generate_edits_from_text(original_text: string, modified_text: string): ModifyText[];
491
+ /**
492
+ * DOCX-to-DOCX diff over projections extracted with return_structure=true.
493
+ *
494
+ * Improvements over a flat generate_edits_from_text pass:
495
+ * - each OPC part (header/body/footer/notes) diffs against its
496
+ * counterpart, so no edit can span a part boundary and content that
497
+ * moved between parts is reported instead of hidden (QA 2026-07-18 C1);
498
+ * - table row insertions/deletions become structured insert_row /
499
+ * delete_row operations instead of pipe-text edits (QA C2).
500
+ *
501
+ * Every ModifyText keeps its _match_start_index pinned into text_orig, which
502
+ * the engine consumes positionally (the Node engine has no
503
+ * make_edits_self_contained JSON round trip like the Python CLI).
504
+ *
505
+ * Returns { edits, warnings }. Warnings describe fallbacks the caller should
506
+ * surface (differing part layouts, unanchorable rows, …).
507
+ */
508
+ declare function generate_structured_edits(text_orig: string, struct_orig: ExtractStructure, text_mod: string, struct_mod: ExtractStructure): {
509
+ edits: DiffEdit[];
510
+ warnings: string[];
511
+ };
418
512
  declare function create_unified_diff(original_text: string, modified_text: string, context_lines?: number): string;
419
513
  declare function create_word_patch_diff(original_text: string, modified_text: string, original_path?: string, modified_path?: string): string;
420
514
 
421
- declare function apply_edits_to_markdown(markdown_text: string, edits: ModifyText[], include_index?: boolean, highlight_only?: boolean): string;
515
+ /** One entry per input edit in apply_edits_to_markdown's edit_reports. */
516
+ interface MarkupEditReport {
517
+ index: number;
518
+ status: "applied" | "failed";
519
+ error: string | null;
520
+ occurrences: number;
521
+ }
522
+ /**
523
+ * Applies edits to Markdown text and returns CriticMarkup-annotated output.
524
+ *
525
+ * Edit resolution follows the SAME semantics as `apply` (QA 2026-07-18 M1):
526
+ * - `regex: true` targets match as regular expressions
527
+ * - `match_mode` is honored: "strict" (default) refuses ambiguous targets,
528
+ * "first" marks the first occurrence, "all" marks every occurrence
529
+ * - a missing target is a per-edit failure, never a silent skip
530
+ *
531
+ * When `edit_reports` is provided, one entry per input edit is appended:
532
+ * { index: 0-based input position, status: "applied"|"failed",
533
+ * error: string|null, occurrences: number }.
534
+ */
535
+ declare function apply_edits_to_markdown(markdown_text: string, edits: ModifyText[], include_index?: boolean, highlight_only?: boolean, edit_reports?: MarkupEditReport[]): string;
422
536
 
423
537
  /**
424
538
  * Stateless paginator for projected DOCX Markdown.
@@ -454,12 +568,6 @@ interface OutlineNode {
454
568
  }
455
569
  declare function extract_outline(doc: DocumentObject, projected_body: string, body_pages: string[], body_page_offsets: number[], paragraph_offsets?: Record<string, [number, number]> | Map<any, [number, number]> | null): OutlineNode[];
456
570
 
457
- declare function extractTextFromBuffer(buffer: Buffer, cleanView?: boolean): Promise<string>;
458
- declare function _extractTextFromDoc(doc: DocumentObject, cleanView?: boolean, includeAppendix?: boolean, return_paragraph_offsets?: boolean): string | {
459
- text: string;
460
- paragraph_offsets: Map<any, [number, number]>;
461
- };
462
-
463
571
  interface FinalizeOptions {
464
572
  filename: string;
465
573
  sanitize_mode?: 'full' | 'keep-markup' | 'baseline';
@@ -475,6 +583,42 @@ interface FinalizeResult {
475
583
  }
476
584
  declare function finalize_document(doc: DocumentObject, options: FinalizeOptions): Promise<FinalizeResult>;
477
585
 
586
+ /**
587
+ * Time-budgeted execution of USER/LLM-supplied regular expressions.
588
+ *
589
+ * `regex: true` on a ModifyText edit and `search_regex` on read_docx hand an
590
+ * LLM-controlled pattern to V8's backtracking engine. A pathological pattern
591
+ * like `(a|a)*$` against a run of repeated characters hangs the event loop
592
+ * indefinitely (QA 2026-07-17 F5 — ReDoS; mirrors the Python fix).
593
+ *
594
+ * JS regexes cannot be interrupted in-thread, but V8 CAN interrupt regex
595
+ * execution running inside a `vm` context with a `timeout` — that is the
596
+ * mechanism used here. `node:vm` is a builtin, preserving the zero-dependency
597
+ * bundle constraint.
598
+ *
599
+ * Only USER-SUPPLIED patterns belong here. The engine's own generated
600
+ * patterns (fuzzy matchers etc.) are built to be linear-time.
601
+ */
602
+ declare const USER_PATTERN_TIMEOUT_MS = 2000;
603
+ declare class RegexTimeoutError extends Error {
604
+ pattern: string;
605
+ constructor(pattern: string);
606
+ }
607
+ /**
608
+ * All non-overlapping matches of a user pattern, under the wall-clock budget.
609
+ * Invalid patterns throw SyntaxError exactly like `new RegExp(...)` would.
610
+ * The budget covers the ENTIRE scan, not just the first match.
611
+ */
612
+ declare function userFindAllMatches(pattern: string, text: string, flags?: string): Array<{
613
+ start: number;
614
+ end: number;
615
+ }>;
616
+ /** First match of a user pattern under the wall-clock budget, or null. */
617
+ declare function userSearch(pattern: string, text: string, flags?: string): {
618
+ start: number;
619
+ end: number;
620
+ } | null;
621
+
478
622
  declare function identifyEngine(): string;
479
623
 
480
- export { BatchValidationError, DocumentMapper, DocumentObject, type FinalizeOptions, type FinalizeResult, type OutlineNode, type PageInfo, type PaginationResult, RedlineEngine, type TextSpan, _extractTextFromDoc, apply_edits_to_markdown, create_unified_diff, create_word_patch_diff, extractTextFromBuffer, extract_outline, finalize_document, generate_edits_from_text, identifyEngine, paginate, split_structural_appendix, trim_common_context };
624
+ export { BatchValidationError, type DiffEdit, DocumentMapper, DocumentObject, type ExtractStructure, type FinalizeOptions, type FinalizeResult, type MarkupEditReport, type OutlineNode, type PageInfo, type PaginationResult, RedlineEngine, RegexTimeoutError, type RowGeometry, type TableGeometry, type TextSpan, USER_PATTERN_TIMEOUT_MS, _extractTextFromDoc, apply_edits_to_markdown, create_unified_diff, create_word_patch_diff, describe_illegal_control_chars, extractTextFromBuffer, extract_outline, finalize_document, generate_edits_from_text, generate_structured_edits, identifyEngine, paginate, split_structural_appendix, trim_common_context, userFindAllMatches, userSearch, validate_edit_strings };