Skip to content

Commit 091c24c

Browse files
authored
feat: the document API limited alpha (#2087)
* feat(document-api): bootstrap package with type model and read API core * feat(document-api): add mutating/comment/list/track-changes API modules * feat(super-editor): add read-path document-api adapters and resolver helpers * feat(super-editor): add mutation document-api adapters and command plumbing * fix(super-editor): correct document-api tracked IDs, list dry-run behavior, and text-find totals * fix(super-editor): make list commands can()-safe and prevent sdBlockId inheritance * fix(search): honor caseSensitive for plain-string queries * fix(super-editor): honor forceTrackChanges in dispatch and reject ambiguous text targets * fix(super-editor): enforce tracked-mode user preconditions in dry-run adapters * refactor(document-api-adapters): unify adapter capability errors and extract mutation helpers * feat(document-api): add capability model and super-editor capability adapter * feat(document-api): add contract schemas and derive operation member paths * feat(document-api): add contract generation/check scripts and parity bridge * chore(document-api): document generated vs manual file ownership boundaries * chore(super-editor): add doc-api helper utilities and coordsAtPos regression test * refactor(comment): harden comment target identity and anchor resolution * test(document-api): align conformance vectors with adapter behavior updates * fix(super-editor): harden document-api adapters with offset, capability, and safety fixes * chore(document-api): automate contract output sync/check via hooks and CI * fix(super-editor): preserve direct mutations and remove leaked document-api export * fix(document-api): pipe generated JSON through Prettier to fix sync/format race * fix(document-api): align list mutator catalog flags with implemented dryRun and cicd * feat(document-api): add invoke dynamic dispatch with typed operation registry Adds `api.invoke({ operationId, input, options })` for dynamic/AI callers alongside type-safe overloads for TypeScript consumers. Includes: - OperationRegistry with bidirectional compile-time completeness checks - Runtime dispatch table mapping all 36 operations to direct API methods - DynamicInvokeRequest overload accepting unknown input - hasOwnProperty guard with clear error for unknown operation IDs - Contract parity check extended to verify dispatch table keys - 13 new tests covering completeness, parity, error handling, and dynamic dispatch * fix(document-api): enforce skipTrackChanges for direct-mode bold formatting * chore: consolidate operation definitions and enforce typed invoke dispatch
1 parent 10ff3c7 commit 091c24c

File tree

233 files changed

+59558
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

233 files changed

+59558
-196
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: CI Document API
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
pull_request:
8+
paths:
9+
- 'packages/document-api/**'
10+
- 'apps/docs/document-api/**'
11+
- 'package.json'
12+
- '.github/workflows/ci-document-api.yml'
13+
workflow_dispatch:
14+
15+
concurrency:
16+
group: ci-document-api-${{ github.event.pull_request.number || github.run_id }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
validate:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: pnpm/action-setup@v4
26+
27+
- uses: actions/setup-node@v4
28+
with:
29+
node-version-file: .nvmrc
30+
cache: pnpm
31+
32+
- name: Install dependencies
33+
run: pnpm install --frozen-lockfile
34+
35+
- name: Check contract parity and generated outputs
36+
run: pnpm run docapi:check

CLAUDE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ tests/visual/ Visual regression tests (Playwright + R2 baselines)
6464
| Style resolution | `layout-engine/style-engine/` |
6565
| Main entry point (Vue) | `superdoc/src/SuperDoc.vue` |
6666
| Visual regression tests | `tests/visual/` (see its CLAUDE.md) |
67+
| Document API contract | `packages/document-api/src/contract/operation-definitions.ts` |
68+
| Adding a doc-api operation | See `packages/document-api/README.md` § "Adding a new operation" |
6769

6870
## Style Resolution Boundary
6971

@@ -82,6 +84,18 @@ tests/visual/ Visual regression tests (Playwright + R2 baselines)
8284
- **Editing commands/behavior**: Modify `super-editor/src/extensions/`
8385
- **State bridging**: Modify `PresentationEditor.ts`
8486

87+
## Document API Contract
88+
89+
The `packages/document-api/` package uses a contract-first pattern with a single source of truth.
90+
91+
- **`operation-definitions.ts`** — canonical object defining every operation's key, metadata, member path, reference doc path, and group. All downstream maps are projected from this file automatically.
92+
- **`operation-registry.ts`** — type-level registry mapping each operation to its `input`, `options`, and `output` types.
93+
- **`invoke.ts`**`TypedDispatchTable` validates dispatch wiring against the registry at compile time.
94+
95+
Adding a new operation touches 4 files: `operation-definitions.ts`, `operation-registry.ts`, `invoke.ts` (dispatch table), and the implementation. See `packages/document-api/README.md` for the full guide.
96+
97+
Do NOT hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFERENCE_DOC_PATH_MAP`, or `REFERENCE_OPERATION_GROUPS` — they are derived from `OPERATION_DEFINITIONS`.
98+
8599
## JSDoc types
86100

87101
Many packages use `.js` files with JSDoc `@typedef` for type definitions (e.g., `packages/superdoc/src/core/types/index.js`). These typedefs ARE the published type declarations — `vite-plugin-dts` generates `.d.ts` files from them.

apps/docs/CLAUDE.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@ When moving or renaming a page, always add a redirect in `docs.json`:
1515
}
1616
```
1717

18+
## Document API generation boundary
19+
20+
Document API docs have mixed manual/generated ownership. Treat these paths as authoritative:
21+
22+
- `apps/docs/document-api/reference/*`: generated, commit to git, do not hand-edit.
23+
- `packages/document-api/generated/*`: generated, commit to git, do not hand-edit.
24+
- `apps/docs/document-api/overview.mdx`: manual except for the block between:
25+
- `/* DOC_API_GENERATED_API_SURFACE_START */`
26+
- `/* DOC_API_GENERATED_API_SURFACE_END */`
27+
28+
To refresh generated content:
29+
30+
```bash
31+
pnpm exec tsx packages/document-api/scripts/generate-contract-outputs.ts
32+
pnpm exec tsx packages/document-api/scripts/check-contract-outputs.ts
33+
```
34+
1835
## Brand voice
1936

2037
One personality, two registers. SuperDoc is the same person in every conversation — warm, clear, technically confident. It adjusts **what it emphasizes** based on who's listening. Developers hear about the how. Leaders hear about the why.

apps/docs/docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
},
9292
{
9393
"group": "Document API",
94-
"tag": "SOON",
94+
"tag": "ALPHA",
9595
"pages": ["document-api/overview"]
9696
},
9797
{

apps/docs/document-api/overview.mdx

Lines changed: 67 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -5,122 +5,74 @@ description: A stable, engine-agnostic interface for programmatic document acces
55
keywords: "document api, programmatic access, query documents, document manipulation, headless docx"
66
---
77

8-
The Document API is a new way to interact with documents programmatically. Query content, make changes, and build automations — all without touching editor internals.
8+
Document API gives you a consistent way to read and edit documents without relying on editor internals.
99

1010
<Info>
11-
**Coming Soon**The Document API is currently in development. This page previews what's coming.
11+
Document API is in <strong>alpha</strong> and subject to breaking changes while the contract and adapters continue to evolve. The current API is not yet comprehensive, and more commands and namespaces are being added on an ongoing basis.
1212
</Info>
1313

14-
## Why Document API?
15-
16-
Today, programmatic access requires using internal editor methods:
17-
18-
```javascript
19-
// Current approach - uses internal APIs
20-
editor.commands.insertContent(content);
21-
editor.state.doc.descendants((node) => { ... });
22-
```
23-
24-
This works, but:
25-
- Internal APIs can change between versions
26-
- Requires understanding ProseMirror internals
27-
- Tightly coupled to the editor implementation
28-
29-
## What's coming
30-
31-
The Document API provides a stable, high-level interface:
32-
33-
```javascript
34-
// Document API - stable public interface
35-
const paragraphs = doc.query({ type: 'paragraph' });
36-
const tables = doc.query({ type: 'table', contains: 'Revenue' });
37-
38-
doc.replace(paragraphs[0], { text: 'New content' });
39-
```
40-
41-
<CardGroup cols={2}>
42-
<Card title="Query DSL" icon="search">
43-
Find content by type, attributes, or text. Filter tables, paragraphs, lists — anything in the document.
44-
</Card>
45-
<Card title="Stable Interface" icon="shield-check">
46-
Public API that won't break between versions. Build with confidence.
47-
</Card>
48-
<Card title="Engine Agnostic" icon="repeat">
49-
Works the same whether you're in the browser, Node.js, or headless mode.
50-
</Card>
51-
<Card title="Type Safe" icon="code">
52-
Full TypeScript support with autocomplete and type checking.
53-
</Card>
54-
</CardGroup>
55-
56-
## Feature preview
57-
58-
### Querying content
59-
60-
Find any content in your document:
61-
62-
```javascript
63-
// Find all paragraphs
64-
const paragraphs = doc.query({ type: 'paragraph' });
65-
66-
// Find tables containing specific text
67-
const tables = doc.query({
68-
type: 'table',
69-
contains: 'Q4 Revenue'
70-
});
71-
72-
// Find content by attributes
73-
const signatures = doc.query({
74-
type: 'field-annotation',
75-
attrs: { fieldType: 'signature' }
76-
});
77-
```
78-
79-
### Making changes
80-
81-
Modify documents with a clean API:
82-
83-
```javascript
84-
// Replace content
85-
doc.replace(address, { text: 'Updated text' });
86-
87-
// Insert at position
88-
doc.insert(address, { type: 'paragraph', text: 'New paragraph' });
89-
90-
// Delete content
91-
doc.delete(address);
92-
```
93-
94-
### Working with tables
95-
96-
First-class table operations:
97-
98-
```javascript
99-
// Add a row
100-
doc.table(tableAddress).addRow({ after: 2 });
101-
102-
// Update a cell
103-
doc.table(tableAddress).cell(1, 2).replace({ text: 'New value' });
104-
```
105-
106-
## Timeline
107-
108-
<Steps>
109-
<Step title="v0 — Read-only API">
110-
Query DSL for finding and reading document content
111-
</Step>
112-
<Step title="v1 — Mutations">
113-
Insert, replace, and delete operations
114-
</Step>
115-
<Step title="v2 — Advanced Operations">
116-
Table operations, list manipulation, track changes integration
117-
</Step>
118-
</Steps>
119-
120-
## Stay updated
121-
122-
Join Discord to get notified when Document API launches:
123-
124-
<Card title="Join Discord" icon="discord" href="https://discord.com/invite/b9UuaZRyaB">
125-
Get early access and share feedback
126-
</Card>
14+
## Why use Document API
15+
16+
- Build automations without editor-specific code.
17+
- Work with predictable inputs and outputs defined per operation.
18+
- Check capabilities up front and branch safely when features are unavailable.
19+
20+
## Reference
21+
22+
- Full operation reference: [/document-api/reference/index](/document-api/reference/index)
23+
- Machine-readable files are available for automation use (contract schema, tool manifest, and agent compatibility artifacts).
24+
25+
{/* DOC_API_OPERATIONS_START */}
26+
### Available operations
27+
28+
Use the tables below to see what operations are available and where each one is documented.
29+
30+
| Namespace | Operations | Reference |
31+
| --- | --- | --- |
32+
| Core | 8 | [Reference](/document-api/reference/core/index) |
33+
| Capabilities | 1 | [Reference](/document-api/reference/capabilities/index) |
34+
| Create | 1 | [Reference](/document-api/reference/create/index) |
35+
| Format | 1 | [Reference](/document-api/reference/format/index) |
36+
| Lists | 8 | [Reference](/document-api/reference/lists/index) |
37+
| Comments | 11 | [Reference](/document-api/reference/comments/index) |
38+
| Track Changes | 6 | [Reference](/document-api/reference/track-changes/index) |
39+
40+
| Editor method | Operation ID |
41+
| --- | --- |
42+
| `editor.doc.find(...)` | [`find`](/document-api/reference/find) |
43+
| `editor.doc.getNode(...)` | [`getNode`](/document-api/reference/get-node) |
44+
| `editor.doc.getNodeById(...)` | [`getNodeById`](/document-api/reference/get-node-by-id) |
45+
| `editor.doc.getText(...)` | [`getText`](/document-api/reference/get-text) |
46+
| `editor.doc.info(...)` | [`info`](/document-api/reference/info) |
47+
| `editor.doc.insert(...)` | [`insert`](/document-api/reference/insert) |
48+
| `editor.doc.replace(...)` | [`replace`](/document-api/reference/replace) |
49+
| `editor.doc.delete(...)` | [`delete`](/document-api/reference/delete) |
50+
| `editor.doc.format.bold(...)` | [`format.bold`](/document-api/reference/format/bold) |
51+
| `editor.doc.create.paragraph(...)` | [`create.paragraph`](/document-api/reference/create/paragraph) |
52+
| `editor.doc.lists.list(...)` | [`lists.list`](/document-api/reference/lists/list) |
53+
| `editor.doc.lists.get(...)` | [`lists.get`](/document-api/reference/lists/get) |
54+
| `editor.doc.lists.insert(...)` | [`lists.insert`](/document-api/reference/lists/insert) |
55+
| `editor.doc.lists.setType(...)` | [`lists.setType`](/document-api/reference/lists/set-type) |
56+
| `editor.doc.lists.indent(...)` | [`lists.indent`](/document-api/reference/lists/indent) |
57+
| `editor.doc.lists.outdent(...)` | [`lists.outdent`](/document-api/reference/lists/outdent) |
58+
| `editor.doc.lists.restart(...)` | [`lists.restart`](/document-api/reference/lists/restart) |
59+
| `editor.doc.lists.exit(...)` | [`lists.exit`](/document-api/reference/lists/exit) |
60+
| `editor.doc.comments.add(...)` | [`comments.add`](/document-api/reference/comments/add) |
61+
| `editor.doc.comments.edit(...)` | [`comments.edit`](/document-api/reference/comments/edit) |
62+
| `editor.doc.comments.reply(...)` | [`comments.reply`](/document-api/reference/comments/reply) |
63+
| `editor.doc.comments.move(...)` | [`comments.move`](/document-api/reference/comments/move) |
64+
| `editor.doc.comments.resolve(...)` | [`comments.resolve`](/document-api/reference/comments/resolve) |
65+
| `editor.doc.comments.remove(...)` | [`comments.remove`](/document-api/reference/comments/remove) |
66+
| `editor.doc.comments.setInternal(...)` | [`comments.setInternal`](/document-api/reference/comments/set-internal) |
67+
| `editor.doc.comments.setActive(...)` | [`comments.setActive`](/document-api/reference/comments/set-active) |
68+
| `editor.doc.comments.goTo(...)` | [`comments.goTo`](/document-api/reference/comments/go-to) |
69+
| `editor.doc.comments.get(...)` | [`comments.get`](/document-api/reference/comments/get) |
70+
| `editor.doc.comments.list(...)` | [`comments.list`](/document-api/reference/comments/list) |
71+
| `editor.doc.trackChanges.list(...)` | [`trackChanges.list`](/document-api/reference/track-changes/list) |
72+
| `editor.doc.trackChanges.get(...)` | [`trackChanges.get`](/document-api/reference/track-changes/get) |
73+
| `editor.doc.trackChanges.accept(...)` | [`trackChanges.accept`](/document-api/reference/track-changes/accept) |
74+
| `editor.doc.trackChanges.reject(...)` | [`trackChanges.reject`](/document-api/reference/track-changes/reject) |
75+
| `editor.doc.trackChanges.acceptAll(...)` | [`trackChanges.acceptAll`](/document-api/reference/track-changes/accept-all) |
76+
| `editor.doc.trackChanges.rejectAll(...)` | [`trackChanges.rejectAll`](/document-api/reference/track-changes/reject-all) |
77+
| `editor.doc.capabilities()` | [`capabilities.get`](/document-api/reference/capabilities/get) |
78+
{/* DOC_API_OPERATIONS_END */}

0 commit comments

Comments
 (0)