@sobree/core 0.1.28 → 0.1.30

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 (43) hide show
  1. package/dist/doc/mutations/blocks.d.ts +14 -0
  2. package/dist/doc/mutations/index.d.ts +38 -0
  3. package/dist/doc/mutations/numbering.d.ts +8 -0
  4. package/dist/doc/mutations/paragraphs.d.ts +13 -0
  5. package/dist/doc/mutations/sections.d.ts +40 -0
  6. package/dist/doc/mutations/styles.d.ts +14 -0
  7. package/dist/doc/mutations/types.d.ts +57 -0
  8. package/dist/doc/types/block.d.ts +182 -0
  9. package/dist/doc/types/document.d.ts +122 -0
  10. package/dist/doc/types/drawing.d.ts +141 -0
  11. package/dist/doc/types/headersFooters.d.ts +7 -0
  12. package/dist/doc/types/index.d.ts +34 -0
  13. package/dist/doc/types/numbering.d.ts +25 -0
  14. package/dist/doc/types/paragraph.d.ts +82 -0
  15. package/dist/doc/types/parts.d.ts +18 -0
  16. package/dist/doc/types/revisions.d.ts +8 -0
  17. package/dist/doc/types/runs.d.ts +178 -0
  18. package/dist/doc/types/sections.d.ts +67 -0
  19. package/dist/doc/types/styles.d.ts +32 -0
  20. package/dist/doc/types.d.ts +7 -842
  21. package/dist/editor/index.d.ts +7 -2
  22. package/dist/editor/internal/applyMutation.d.ts +9 -0
  23. package/dist/editor/internal/mutations.d.ts +4 -64
  24. package/dist/editor/ops/blocks.d.ts +5 -4
  25. package/dist/editor/renderedDocument/blocks.d.ts +14 -0
  26. package/dist/editor/renderedDocument/comments.d.ts +6 -0
  27. package/dist/editor/renderedDocument/index.d.ts +27 -0
  28. package/dist/editor/renderedDocument/revisions.d.ts +11 -0
  29. package/dist/editor/renderedDocument/selectors.d.ts +51 -0
  30. package/dist/editor/renderedDocument/types.d.ts +59 -0
  31. package/dist/editor/table.d.ts +17 -11
  32. package/dist/headless.d.ts +14 -5
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +5154 -4829
  35. package/dist/index.js.map +1 -1
  36. package/dist/ydoc/apply.d.ts +7 -2
  37. package/dist/ydoc/blockCodec.d.ts +55 -0
  38. package/dist/ydoc/frameCodec.d.ts +33 -0
  39. package/dist/ydoc/index.d.ts +3 -2
  40. package/dist/ydoc/project.d.ts +1 -6
  41. package/dist/ydoc/schema.d.ts +66 -8
  42. package/dist/ydoc/seed.d.ts +2 -33
  43. package/package.json +1 -1
@@ -7,10 +7,11 @@ import { History } from '../history';
7
7
  import { BlockRegistry } from './internal/blockRegistry';
8
8
  import { countBlocks } from './internal/positionMap';
9
9
  import { EditorNumbering } from './numbering';
10
+ import { RenderedDocumentIndex } from './renderedDocument';
10
11
  import { EditorSections } from './sections';
11
12
  import { EditorSelection } from './selection';
12
13
  import { EditorStyles } from './styles';
13
- import { EditorTable } from './table';
14
+ import { TableApi } from './table';
14
15
  import { ApiRangeType, BlockInfo, ChangePayload, CommandBus, CommandDefinition, CommandSnapshot, EditorEvent, EditorEventPayload, EditorOptions, KeyDownPayload, NamedStylePatch, OutlineItem, ParagraphPropertiesPatch, RevisionSpan, SectionPropertiesPatch, SelectionPayload, TrackChangesState, Unsubscribe, WrapTag } from './types';
15
16
  import * as Y from "yjs";
16
17
  export { EditorCommands } from './commands';
@@ -28,7 +29,7 @@ export declare class Editor {
28
29
  * unmerge, cell-level properties. Every method returns an `EditResult`
29
30
  * and inherits optimistic-lock checking via `replaceBlock`.
30
31
  */
31
- readonly table: EditorTable;
32
+ readonly table: TableApi;
32
33
  /**
33
34
  * Section-level edit operations — page size / margins, columns,
34
35
  * header/footer references, vertical alignment. Grouped here (rather
@@ -56,6 +57,10 @@ export declare class Editor {
56
57
  * keyboard / toolbar / agent / MCP all dispatch through `execute()`.
57
58
  */
58
59
  readonly commands: CommandBus;
60
+ /** Typed lookup mapping rendered DOM elements ↔ document concepts
61
+ * (blocks, revision marks, comment ranges) — the bridge plugins use
62
+ * instead of hardcoding renderer selectors. See `./renderedDocument`. */
63
+ readonly renderedDocument: RenderedDocumentIndex;
59
64
  /**
60
65
  * Y.Doc backing the document. The Editor's `this.doc` field is a
61
66
  * cached projection of this Y.Doc — every local mutation mirrors
@@ -0,0 +1,9 @@
1
+ import { EditResult } from '../../doc/api';
2
+ import { DocumentMutationResult, MutationInput } from '../../doc/mutations';
3
+ import { EditorContext } from '../context';
4
+ /** Build the engine input from the live editor context. The `BlockRegistry`
5
+ * satisfies `BlockRegistryView` directly. */
6
+ export declare function mutationInput(ctx: EditorContext): MutationInput;
7
+ /** Apply a mutation result through `ctx.commit`, or pass the failure
8
+ * through unchanged. */
9
+ export declare function applyMutation<T>(ctx: EditorContext, result: DocumentMutationResult<T>): EditResult<T>;
@@ -1,67 +1,8 @@
1
1
  import { RunPropertiesPatch } from '../../doc/runs';
2
- import { Block, NamedStyle, ParagraphProperties, RunProperties, SectionProperties, SobreeDocument } from '../../doc/types';
3
- import { NamedStylePatch, ParagraphPropertiesPatch, SectionPropertiesPatch, WrapTag } from '../types';
4
- /**
5
- * One registry-level operation produced by a mutation. The caller
6
- * applies these to the BlockRegistry after committing the new doc:
7
- * `insert` adds an id, `remove` drops one, `bump` keeps the same id
8
- * but increments its version.
9
- */
10
- export type Mutation = {
11
- type: "bump";
12
- index: number;
13
- } | {
14
- type: "insert";
15
- index: number;
16
- } | {
17
- type: "remove";
18
- index: number;
19
- };
20
- /**
21
- * Index in `sections` of the section that ENDS at the section_break at
22
- * `breakIndex`. Sections are 1:1 with section_breaks; the first
23
- * section ends at the first break (or at the end of `body` if there's
24
- * no break).
25
- *
26
- * body = [p, p, break, p, break, p]
27
- * sections = [s0, s1, s2]
28
- *
29
- * breakIndex = 2 → 0 (the first break ends section 0)
30
- * breakIndex = 4 → 1 (the second break ends section 1)
31
- */
32
- export declare function removedSectionIndex(body: readonly Block[], breakIndex: number): number;
33
- /**
34
- * Drop the section at `endingIndex + 1` from `sections` — that's the
35
- * section the now-removed break STARTED. The section ENDED by the
36
- * removed break (at `endingIndex`) absorbs whatever content used to
37
- * belong to its successor. Properties of the surviving section are
38
- * preserved verbatim; nothing about the removed section's settings is
39
- * carried over.
40
- *
41
- * If `sections` doesn't have a successor (the removed break was the
42
- * last one and there's only one section), the array is returned
43
- * unchanged.
44
- */
45
- export declare function mergeSectionsAcross(sections: readonly SectionProperties[], endingIndex: number): SectionProperties[];
46
- /**
47
- * Merge a `ParagraphPropertiesPatch` into existing properties.
48
- * `undefined` in the patch removes a field; everything else
49
- * overwrites.
50
- */
51
- export declare function mergeParagraphProps(prev: ParagraphProperties, patch: ParagraphPropertiesPatch): ParagraphProperties;
52
- /**
53
- * Merge a {@link SectionPropertiesPatch} onto existing section properties.
54
- * `pageSize` / `pageMargins` are FIELD-merged (a partial stays valid); the
55
- * other fields replace wholesale. For the optional fields (`columns`,
56
- * `titlePage`, `type`, `vAlign`) an explicit `undefined` clears them, while
57
- * the required `headerRefs` / `footerRefs` only replace when present.
58
- */
59
- export declare function mergeSectionProps(prev: SectionProperties, patch: SectionPropertiesPatch): SectionProperties;
60
- /** Merge a {@link NamedStylePatch} onto an existing style. Each present
61
- * field replaces the style's field wholesale; an explicit `undefined`
62
- * clears an OPTIONAL field. The required `type` / `displayName` are never
63
- * cleared (an undefined for them is ignored). */
64
- export declare function mergeNamedStyle(prev: NamedStyle, patch: NamedStylePatch): NamedStyle;
2
+ import { SobreeDocument } from '../../doc/types';
3
+ import { WrapTag } from '../types';
4
+ export type { Mutation } from '../../doc/mutations';
5
+ export { mergeNamedStyle, mergeParagraphProps, mergeSectionProps, mergeSectionsAcross, removedSectionIndex, } from '../../doc/mutations';
65
6
  /**
66
7
  * Map a semantic "wrap" tag to the run-property patch that achieves it.
67
8
  * Same mapping the browser editor uses for toolbar buttons.
@@ -73,4 +14,3 @@ export declare function mimeToExtension(mime: string): string;
73
14
  export declare function allocateMediaPath(doc: SobreeDocument, ext: string): string;
74
15
  /** Convert pixels (CSS @ 96 dpi) to OOXML's EMU (914400 per inch). */
75
16
  export declare function pxToEmu(px: number): number;
76
- export type { RunProperties };
@@ -4,9 +4,10 @@ import { EditorContext } from '../context';
4
4
  import { ParagraphPropertiesPatch } from '../types';
5
5
  /**
6
6
  * Block-level mutations: replace / insert / delete whole blocks and
7
- * patch paragraph properties. All enforce optimistic locking via
8
- * `ctx.checkRefs` and route through `ctx.commit`. Section-break removal
9
- * merges the two sections it delimited. Track-changes mode stamps
7
+ * patch paragraph properties. The plain document transform lives in the
8
+ * shared `doc/mutations` engine (lock check + body splice + section-break
9
+ * merge); these wrappers add the browser-only track-changes behaviour and
10
+ * apply the engine's patch through `ctx.commit`. Track-changes mode stamps
10
11
  * paragraph insert/delete markers instead of moving content outright.
11
12
  */
12
13
  /** Replace the block at `target`'s index with `block`. */
@@ -35,7 +36,7 @@ export declare function insertBlockAfter(ctx: EditorContext, target: BlockRef, b
35
36
  * `ins` marker (a paragraph the user themselves just created), the block
36
37
  * is removed outright — cancelling an un-committed insert, matching the
37
38
  * inline `deleteRange` semantics. Non-paragraph blocks (tables, section
38
- * breaks) bypass tracking in v1 — they remove plainly.
39
+ * breaks) bypass tracking in v1 — they remove plainly via the engine.
39
40
  */
40
41
  export declare function deleteBlock(ctx: EditorContext, target: BlockRef): EditResult<void>;
41
42
  /** Merge a patch into each target paragraph's properties. */
@@ -0,0 +1,14 @@
1
+ import { BlockRef } from '../../doc/api';
2
+ import { BlockRegistry } from '../internal/blockRegistry';
3
+ /** Id of the nearest block ancestor of `el` (including `el`), or `null`. */
4
+ export declare function blockIdFromElement(el: Element): string | null;
5
+ /**
6
+ * Live, versioned ref of the nearest block ancestor of `el`, or `null`.
7
+ * Returns `null` when the id isn't live in the registry (e.g. the block
8
+ * was just deleted) — the registry is the source of truth for versions.
9
+ */
10
+ export declare function blockRefFromElement(el: Element, registry: BlockRegistry): BlockRef | null;
11
+ /** Rendered element bearing `blockId`, searched across `roots`, or `null`. */
12
+ export declare function elementForBlockId(blockId: string, roots: readonly ParentNode[]): HTMLElement | null;
13
+ /** Rendered element for a block ref (matched by id), or `null`. */
14
+ export declare function elementForBlock(ref: BlockRef, roots: readonly ParentNode[]): HTMLElement | null;
@@ -0,0 +1,6 @@
1
+ import { BlockRegistry } from '../internal/blockRegistry';
2
+ import { RenderedCommentRange } from './types';
3
+ /** Every comment range under `root`. */
4
+ export declare function commentRanges(root: ParentNode, registry: BlockRegistry): RenderedCommentRange[];
5
+ /** Nearest comment range at or above `target`, or `null`. */
6
+ export declare function nearestCommentRange(target: Element, registry: BlockRegistry): RenderedCommentRange | null;
@@ -0,0 +1,27 @@
1
+ import { BlockRef } from '../../doc/api';
2
+ import { BlockRegistry } from '../internal/blockRegistry';
3
+ import { RenderedCommentRange, RenderedDocumentIndex, RenderedRevisionMark } from './types';
4
+ export type { RenderedBlockLookup, RenderedCommentLookup, RenderedCommentRange, RenderedDocumentIndex, RenderedRevisionKind, RenderedRevisionLookup, RenderedRevisionMark, } from './types';
5
+ /**
6
+ * The slice of Editor internals `RenderedDocument` reads — its
7
+ * decoupling seam, so this module never imports the concrete `Editor`
8
+ * class. `roots()` returns the default search scope (the editor's
9
+ * content hosts, where every block / revision / comment element renders).
10
+ */
11
+ export interface RenderedDocumentHost {
12
+ roots(): readonly HTMLElement[];
13
+ registry(): BlockRegistry;
14
+ }
15
+ /** Concrete `RenderedDocumentIndex` over an editor's rendered DOM. */
16
+ export declare class RenderedDocument implements RenderedDocumentIndex {
17
+ private readonly host;
18
+ constructor(host: RenderedDocumentHost);
19
+ elementForBlock(ref: BlockRef): HTMLElement | null;
20
+ elementForBlockId(blockId: string): HTMLElement | null;
21
+ blockRefFromElement(element: Element): BlockRef | null;
22
+ blockIdFromElement(element: Element): string | null;
23
+ revisionMarks(root?: ParentNode): RenderedRevisionMark[];
24
+ nearestRevisionMark(target: Element): RenderedRevisionMark | null;
25
+ commentRanges(root?: ParentNode): RenderedCommentRange[];
26
+ nearestCommentRange(target: Element): RenderedCommentRange | null;
27
+ }
@@ -0,0 +1,11 @@
1
+ import { BlockRegistry } from '../internal/blockRegistry';
2
+ import { RenderedRevisionMark } from './types';
3
+ /** Every revision mark under `root` — inline, paragraph, then format. */
4
+ export declare function revisionMarks(root: ParentNode, registry: BlockRegistry): RenderedRevisionMark[];
5
+ /**
6
+ * Nearest revision mark at or above `target`. Specificity order matches
7
+ * the renderer's nesting: an inserted + format-changed run is wrapped in
8
+ * BOTH, and accepting the inline insert covers the format change too, so
9
+ * the inline mark wins.
10
+ */
11
+ export declare function nearestRevisionMark(target: Element, registry: BlockRegistry): RenderedRevisionMark | null;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The rendered-DOM protocol — the ONE place the attribute/class names
3
+ * that cross the renderer ↔ plugin boundary are declared.
4
+ *
5
+ * Two sides import this module:
6
+ * - the **writer**: `view/docRenderer/*` stamps these onto rendered
7
+ * elements,
8
+ * - the **reader**: `renderedDocument/*` (and, through it, the
9
+ * `block-tools` / `review` plugins) queries them.
10
+ *
11
+ * Plugins MUST NOT hardcode these strings — they go through the typed
12
+ * `editor.renderedDocument` surface, which is the only sanctioned reader.
13
+ * Keeping both sides on these constants means a rename is one edit with
14
+ * compiler-checked callers, never a silent cross-package break (AGENTS.md
15
+ * Rule 0: no `data-*` threaded as an inter-module protocol).
16
+ *
17
+ * Scope is deliberately narrow: only attributes/classes that are read
18
+ * across the package boundary live here. Purely-internal renderer
19
+ * attributes (layout/flow markers like `data-col-count`, `data-page-break`)
20
+ * stay local to their module.
21
+ */
22
+ export declare const BLOCK_ID_ATTR = "data-block-id";
23
+ export declare const BLOCK_REVISION_ATTR = "data-block-revision";
24
+ export declare const BLOCK_REVISION_AUTHOR_ATTR = "data-block-revision-author";
25
+ export declare const BLOCK_REVISION_DATE_ATTR = "data-block-revision-date";
26
+ export declare const REVISION_AUTHOR_ATTR = "data-revision-author";
27
+ export declare const REVISION_DATE_ATTR = "data-revision-date";
28
+ export declare const REVISION_FORMAT_AUTHOR_ATTR = "data-revision-format-author";
29
+ export declare const REVISION_FORMAT_DATE_ATTR = "data-revision-format-date";
30
+ export declare const COMMENT_IDS_ATTR = "data-comment-ids";
31
+ export declare const CLS_REVISION = "sobree-revision";
32
+ export declare const CLS_REVISION_FORMAT = "sobree-revision-format";
33
+ export declare const CLS_COMMENT_RANGE = "sobree-comment-range";
34
+ /** Matches every inline tracked-change wrapper (`<ins>` / `<del>`). */
35
+ export declare const INLINE_REVISION_SELECTOR = "ins[data-revision-author], del[data-revision-author]";
36
+ /** Matches every paragraph-mark revision (the block element). */
37
+ export declare const BLOCK_REVISION_SELECTOR = "[data-block-revision]";
38
+ /** Matches every format-change wrapper. */
39
+ export declare const FORMAT_REVISION_SELECTOR = "span.sobree-revision-format";
40
+ /** Matches every comment-range highlight wrapper. */
41
+ export declare const COMMENT_RANGE_SELECTOR = ".sobree-comment-range";
42
+ /** Matches any element carrying a block id (the nearest block ancestor). */
43
+ export declare const BLOCK_ID_SELECTOR = "[data-block-id]";
44
+ /** Selector for the element bearing a specific block id. */
45
+ export declare function blockIdSelector(id: string): string;
46
+ /**
47
+ * Minimal `CSS.escape` fallback for environments without it (jsdom,
48
+ * older browsers). Block ids are alphanumeric + underscore in practice,
49
+ * so a tight regex suffices.
50
+ */
51
+ export declare function cssEscape(s: string): string;
@@ -0,0 +1,59 @@
1
+ import { BlockRef } from '../../doc/api';
2
+ /** Which kind of tracked-change a rendered revision mark represents. */
3
+ export type RenderedRevisionKind = "inline-insert" | "inline-delete" | "paragraph" | "format";
4
+ /** A tracked-change mark discovered in the rendered DOM. */
5
+ export interface RenderedRevisionMark {
6
+ /** What the mark represents — inline insert/delete, a paragraph-mark
7
+ * revision, or a run format change. */
8
+ kind: RenderedRevisionKind;
9
+ /** The element carrying the mark (the `<ins>`/`<del>`, the format
10
+ * `<span>`, or the paragraph block element). */
11
+ element: HTMLElement;
12
+ /** Revision author, when stamped. */
13
+ author?: string;
14
+ /** Revision date (ISO string), when stamped. */
15
+ date?: string;
16
+ /** Ref of the block the mark lives in, when resolvable. */
17
+ blockRef?: BlockRef;
18
+ }
19
+ /** A comment-range highlight discovered in the rendered DOM. */
20
+ export interface RenderedCommentRange {
21
+ /** The wrapping highlight `<span>`. */
22
+ element: HTMLElement;
23
+ /** Ids of every comment anchored to this range (a range may carry
24
+ * more than one when comment ranges overlap). */
25
+ commentIds: string[];
26
+ /** Ref of the block the range lives in, when resolvable. */
27
+ blockRef?: BlockRef;
28
+ }
29
+ /** Map between rendered block elements and document block refs. */
30
+ export interface RenderedBlockLookup {
31
+ /** Element for a block ref, or `null` if not currently rendered. */
32
+ elementForBlock(ref: BlockRef): HTMLElement | null;
33
+ /** Element for a block id, or `null` if not currently rendered. */
34
+ elementForBlockId(blockId: string): HTMLElement | null;
35
+ /** Ref of the nearest block ancestor of `element` (a live, versioned
36
+ * ref), or `null` if `element` isn't inside a rendered block. */
37
+ blockRefFromElement(element: Element): BlockRef | null;
38
+ /** Id of the nearest block ancestor of `element`, or `null`. */
39
+ blockIdFromElement(element: Element): string | null;
40
+ }
41
+ /** Discover tracked-change marks in the rendered DOM. */
42
+ export interface RenderedRevisionLookup {
43
+ /** Every revision mark under `root` (defaults to the whole document). */
44
+ revisionMarks(root?: ParentNode): RenderedRevisionMark[];
45
+ /** The nearest revision mark at or above `target`, or `null`. Inline
46
+ * marks win over format, which win over paragraph — matching the
47
+ * nesting order the renderer produces. */
48
+ nearestRevisionMark(target: Element): RenderedRevisionMark | null;
49
+ }
50
+ /** Discover comment ranges in the rendered DOM. */
51
+ export interface RenderedCommentLookup {
52
+ /** Every comment range under `root` (defaults to the whole document). */
53
+ commentRanges(root?: ParentNode): RenderedCommentRange[];
54
+ /** The nearest comment range at or above `target`, or `null`. */
55
+ nearestCommentRange(target: Element): RenderedCommentRange | null;
56
+ }
57
+ /** The combined rendered-document lookup surface (`editor.renderedDocument`). */
58
+ export interface RenderedDocumentIndex extends RenderedBlockLookup, RenderedRevisionLookup, RenderedCommentLookup {
59
+ }
@@ -1,11 +1,13 @@
1
1
  import { BlockRef, EditResult } from '../doc/api';
2
2
  import { SobreeDocument, Block, ParagraphAlignment, Table, TableCell, TableProperties } from '../doc/types';
3
3
  /**
4
- * Minimal slice of `Editor` that `EditorTable` actually needs. Defining
5
- * it here (rather than `import type { Editor } from "./"`) keeps this
6
- * module a leaf in the editor/* import graph no cycle with index.ts.
4
+ * Minimal slice of an editor-like peer that `TableApi` needs. Both the
5
+ * browser `Editor` and the no-DOM `HeadlessSobree` satisfy it structurally,
6
+ * so the same table surface drives `editor.table` and `headless.table`.
7
+ * Defining it here (rather than `import type { Editor } from "./"`) keeps
8
+ * this module a leaf in the editor/* import graph — no cycle with index.ts.
7
9
  */
8
- export interface EditorTableHost {
10
+ export interface TableHost {
9
11
  getDocument(): SobreeDocument;
10
12
  getBlockById(id: string): {
11
13
  kind: string;
@@ -55,20 +57,24 @@ export interface MergeCellsOpts {
55
57
  colSpan?: number;
56
58
  }
57
59
  /**
58
- * Ergonomic table mutation surface. Lives on `editor.table`.
60
+ * Ergonomic table mutation surface. Lives on `editor.table` (browser) and
61
+ * `headless.table` (no-DOM peer / LLM agents) — same code, via {@link TableHost}.
59
62
  *
60
63
  * Every method does the same three steps under the hood:
61
64
  * 1. Resolve the target table by `BlockRef` (inherits optimistic-lock
62
- * checking from `editor.replaceBlock`).
65
+ * checking from the host's `replaceBlock`).
63
66
  * 2. Clone and mutate the table immutably.
64
- * 3. Delegate to `editor.replaceBlock(ref, nextTable)`.
67
+ * 3. Delegate to the host's `replaceBlock(ref, nextTable)`.
65
68
  *
66
69
  * No new plumbing; lock semantics, affected-block tracking, and event
67
- * emission come from the underlying core.
70
+ * emission come from the underlying core. Because every edit ultimately
71
+ * round-trips the whole table block, callers never hand-build a `Table`
72
+ * just to tweak one cell — but at the Y.Doc layer it is still a
73
+ * whole-table write (per-cell CRDT is a separate, future change).
68
74
  */
69
- export declare class EditorTable {
70
- private readonly editor;
71
- constructor(editor: EditorTableHost);
75
+ export declare class TableApi {
76
+ private readonly host;
77
+ constructor(host: TableHost);
72
78
  insertRow(ref: BlockRef, opts: InsertRowOpts): EditResult<BlockRef>;
73
79
  deleteRow(ref: BlockRef, index: number): EditResult<BlockRef>;
74
80
  insertColumn(ref: BlockRef, opts: InsertColumnOpts): EditResult<BlockRef>;
@@ -2,6 +2,7 @@ import { BlobCache, BlobStore } from './blob';
2
2
  import { BlockRef, EditError, EditResult, Selection } from './doc/api';
3
3
  import { Block, NamedStyle, NumberingDefinition, NumberingLevel, ParagraphAlignment, ParagraphProperties, SobreeDocument } from './doc/types';
4
4
  import { ParagraphPropertiesPatch, BlockInfo, CommandBus, NamedStylePatch, OutlineItem, SectionPropertiesPatch } from './editor';
5
+ import { TableApi } from './editor/table';
5
6
  import { History } from './history';
6
7
  /**
7
8
  * HeadlessSobree — a no-DOM Sobree peer for LLM agents, automation,
@@ -42,10 +43,11 @@ import { History } from './history';
42
43
  * contentEditable event handling, image-resize handles, paste
43
44
  * parsing, etc. HeadlessSobree skips all that — if you need
44
45
  * them, mount a real Editor.
45
- * - A *table editor*. The browser `Editor` has a rich table API
46
- * (`editor.table.insertRow`, etc.). HeadlessSobree v0 doesn't
47
- * wrap that operate on `Table` blocks directly via
48
- * `replaceBlock` until Phase 4.x adds a parallel table API.
46
+ *
47
+ * It DOES share the granular table surface: `headless.table.*` is the
48
+ * same {@link TableApi} as `editor.table.*` (insert/delete rows and
49
+ * columns, merge/unmerge, set cell content + properties), so agents
50
+ * never hand-build a `Table` block just to tweak one cell.
49
51
  *
50
52
  * # Origin tagging
51
53
  *
@@ -105,6 +107,8 @@ export declare class HeadlessSobree {
105
107
  readonly ydoc: Y.Doc;
106
108
  readonly commands: CommandBus;
107
109
  readonly history: History;
110
+ /** Granular table mutations — same {@link TableApi} as `editor.table`. */
111
+ readonly table: TableApi;
108
112
  readonly origin: string;
109
113
  /** Optional content-hashed blob layer. Mirrors the browser `Editor`'s
110
114
  * `blobStore` field — null when no store is configured. */
@@ -176,7 +180,12 @@ export declare class HeadlessSobree {
176
180
  * in the local cache. No-op when no `blobStore` is configured.
177
181
  */
178
182
  ensurePartsLoaded(): Promise<void>;
179
- private checkRefs;
183
+ /** Build the engine input from this peer's live state. The
184
+ * `BlockRegistry` satisfies `BlockRegistryView` directly. */
185
+ private mutationInput;
186
+ /** Apply a mutation engine result through `commit`, or pass the failure
187
+ * through unchanged. */
188
+ private applyPatch;
180
189
  private commit;
181
190
  private fireChange;
182
191
  private summariseBlock;
package/dist/index.d.ts CHANGED
@@ -18,6 +18,8 @@ export { Sobree } from './sobree';
18
18
  export type { SobreeMode, SobreeOptions, SobreeEvent, SobreeEventPayload, SobreeUnsubscribe, } from './sobree';
19
19
  export type { SobreePlugin, SobreePluginInstance, PluginContext, } from './plugin';
20
20
  export { Editor } from './editor';
21
+ export { RenderedDocument } from './editor/renderedDocument';
22
+ export type { RenderedBlockLookup, RenderedCommentLookup, RenderedCommentRange, RenderedDocumentIndex, RenderedRevisionKind, RenderedRevisionLookup, RenderedRevisionMark, } from './editor/renderedDocument';
21
23
  export type { ApiRangeType, RevisionSpan, BlockInfo, ChangePayload, CommandBus, CommandDefinition, CommandSnapshot, EditorEvent, EditorEventPayload, EditorOptions, EditError, EditResult, KeyDownPayload, OutlineItem, ParagraphPropertiesPatch, RunPropertiesPatch, SelectionPayload, TrackChangesState, Unsubscribe, WrapTag, CellRef, InsertAt, InsertColumnOpts, InsertRowOpts, MergeCellsOpts, } from './editor';
22
24
  export * from './doc/types';
23
25
  export * from './doc/builders';