---
title: "edytor/protocol"
description: "Every name edytor/protocol exports, with its declaration and documentation (generated from the published types)."
---

{/* Generated by scripts/api-report.mjs (pnpm api:report) from the published declarations: edit the JSDoc, not this page. */}

Every name `edytor/protocol` exports, generated from the package's published type declarations, with the documentation its JSDoc carries. The guides explain how the pieces fit; this page is the exhaustive list. 91 names.

## AdmissionResult

Non-throwing admission result — the audit/read-side counterpart of
`assertAdmission`.

```ts
export type AdmissionResult = {
    admitted: true;
    verdict: AdmissionVerdict;
} | {
    admitted: false;
    error: UnsupportedDocError | SchemaMismatchError;
};
```

## AdmissionVerdict

What an admitted doc carries — the `sync()` readiness decision:

- `'fresh'` — no schema claim and an empty block registry; seeding
  (`facade.init`) is legal. Foreign/unrelated ROOTS may still exist —
  they are not schema claims and coexist next to the seeded schema.
- `'initialized'` — supported schema content is committed; the doc is
  adopted as-is (`hydrated`), never seeded.

```ts
export type AdmissionVerdict = 'fresh' | 'initialized';
```

## applyAwarenessUpdate

Apply an encoded awareness update. `origin` is forwarded on the emitted
change/update events.

```ts
declare const applyAwarenessUpdate: (awareness: Awareness, update: Uint8Array, origin: unknown) => void;
```

## assertAdmission

The document-level admission gate — runs the ordered checks and throws
the typed refusal:

- `UnsupportedDocError` `'foreign'` — not a v14 engine doc
  (foreign roots/engines may still attach *content* later; this is
  about doc shape);
- `SchemaMismatchError` `'unversioned' | 'unsupported' |
  'foreign'` — a schema claim this build cannot own.

PURE READS — a refusal leaves the doc byte-identical (the reads may
materialize empty root SHARE entries in the doc's share map, which do
not encode into updates). Returns the `AdmissionVerdict` for the
readiness decision.

```ts
declare const assertAdmission: (doc: EngineDoc, docName?: string) => AdmissionVerdict;
```

## assertSchema

Hard gate — throws `SchemaMismatchError` when `checkSchema` reports a
problem. Used by migration and by `Edytor.sync()` before
mutating a synced document.

```ts
declare const assertSchema: (doc: EngineDoc, docName?: string) => void;
```

## assertUsableDoc

Document-boundary guard run by `EdytorDocBinding.create` before the
runs view attaches. The facade only speaks the v14 unified-node surface —
without this gate a foreign doc dies obscurely inside `buildView`
(`registry.forEachAttr is not a function`); it fails fast with an
actionable error instead.

```ts
declare const assertUsableDoc: (doc: EngineDoc) => void;
```

## AwarenessEntry

One awareness entry on the wire: a client's clock and state (`null` = removed).

```ts
export type AwarenessEntry = {
    clientID: number;
    clock: number;
    state: Record<string, unknown> | null;
};
```

## bindCrdt

```ts
declare const bindCrdt: (Y: EngineApi) => {
    createDoc: (opts?: ConstructorParameters<EngineApi["Doc"]>[0]) => YDoc;
    Awareness: typeof _Awareness;
    doc: {
        SCHEMA: {
            readonly version: 6;
            readonly name: "edytor-doc";
            readonly roots: {
                readonly registry: "blocks";
                readonly meta: "meta";
            };
            readonly metaAttrs: {
                readonly version: "v";
                readonly schema: "schema";
            };
        };
        SCHEMA_VERSION: 6;
        SCHEMA_NAME: "edytor-doc";
        META_KEY: "meta";
        init: (doc: import("./engine-api.js").EngineDoc, opts?: {
            content?: import("./index.js").BlockSpec[];
            defaultType?: string;
        }) => void;
        restore: (doc: import("./engine-api.js").EngineDoc, content: import("./index.js").BlockSpec[]) => void;
        seed: (doc: import("./engine-api.js").EngineDoc, value?: import("./index.js").JSONBlock[], defaultType?: string, data?: import("./doc/types.js").JsonObj) => void;
        isInitialized: (doc: import("./engine-api.js").EngineDoc) => boolean;
        schemaVersion: (doc: import("./engine-api.js").EngineDoc) => number | undefined;
        registryEmpty: (doc: import("./engine-api.js").EngineDoc) => boolean;
        checkSchema: (doc: import("./engine-api.js").EngineDoc) => import("./edytor-doc.js").SchemaProblem | null;
        assertSchema: (doc: import("./engine-api.js").EngineDoc, docName?: string) => void;
        SchemaMismatchError: typeof import("./edytor-doc.js").SchemaMismatchError;
        create: (doc: import("./engine-api.js").EngineDoc, config?: import("./edytor-doc.js").EdytorDocConfig) => {
            prepare: {
                insertFlow: (target: import("./flow.js").FlowTarget, flow: import("./flow.js").Flow, view?: import("./flow.js").FlowView) => import("./edytor-doc.js").Prepared;
                deleteRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView) => import("./edytor-doc.js").Prepared;
                replaceRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView) => import("./edytor-doc.js").Prepared;
                insertBlocks: (dest: import("./index.js").Destination, specs: readonly (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[]) => import("./edytor-doc.js").Prepared;
                moveBlocks: (ids: readonly import("./index.js").BlockId[], dest: import("./index.js").Destination) => import("./edytor-doc.js").Prepared;
                nestBlock: (id: import("./index.js").BlockId, parent: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
                unNestBlock: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
                unNestBlocks: (ids: readonly import("./index.js").BlockId[]) => import("./edytor-doc.js").Prepared;
                liftOut: (id: import("./index.js").BlockId, kind: string, { keep, after }?: {
                    keep?: boolean;
                    after?: readonly import("./index.js").BlockSpec[];
                }) => import("./edytor-doc.js").Prepared;
                placeBeside: (ids: readonly import("./index.js").BlockId[], target: import("./index.js").BlockId, side: "left" | "right", kind?: string) => import("./edytor-doc.js").Prepared;
                wrapInLayout: (ids: readonly import("./index.js").BlockId[], kind?: string, columns?: number) => import("./edytor-doc.js").Prepared;
                splitBlock: (id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail?: import("./placement/model.js").SplitTail) => import("./edytor-doc.js").Prepared;
                mergeBlocks: (fromId: import("./index.js").BlockId, intoId: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
                mergeBackward: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
                mergeForward: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
                deleteBlock: (id: import("./index.js").BlockId, opts?: {
                    keepChildren?: boolean;
                }) => import("./edytor-doc.js").Prepared;
                setBlock: (id: import("./index.js").BlockId, value: {
                    type?: string;
                    data?: Record<string, unknown>;
                    content?: (import("./index.js").ContentItem | import("./index.js").JSONText | import("./index.js").JSONInlineBlock)[];
                    children?: (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[];
                }) => import("./edytor-doc.js").Prepared;
                setBlockType: (id: import("./index.js").BlockId, type: string) => import("./edytor-doc.js").Prepared;
                patchData: (target: import("./edytor-doc.js").DataTarget, patches: readonly import("./data.js").DataPatch[]) => import("./edytor-doc.js").Prepared;
                duplicateBlock: (id: import("./index.js").BlockId, freshId?: (oldId: string, kind: "block" | "inline") => string) => import("./edytor-doc.js").Prepared;
                insertText: (id: import("./index.js").BlockId, offset: number, text: string, marks?: Record<string, unknown>) => import("./edytor-doc.js").Prepared;
                deleteText: (id: import("./index.js").BlockId, offset: number, length: number) => import("./edytor-doc.js").Prepared;
                formatRange: (id: import("./index.js").BlockId, offset: number, length: number, marks: Record<string, unknown>) => import("./edytor-doc.js").Prepared;
                clearMarks: (id: import("./index.js").BlockId, offset: number, length: number) => import("./edytor-doc.js").Prepared;
                insertInline: (id: import("./index.js").BlockId, offset: number, atom: import("./doc/content.js").NewInline) => import("./edytor-doc.js").Prepared;
                removeInline: (id: import("./index.js").BlockId, inlineId: string) => import("./edytor-doc.js").Prepared;
                deleteBlocks: (ids: readonly import("./index.js").BlockId[]) => import("./edytor-doc.js").Prepared;
            };
            apply: (p: import("./edytor-doc.js").Prepared) => import("./edytor-doc.js").OpResult;
            compose: (...parts: import("./edytor-doc.js").Prepared[]) => import("./edytor-doc.js").Prepared;
            transact: <R>(fn: () => R, origin?: unknown) => R;
            model: {
                REGISTRY_KEY: string;
                registryOf: (doc: import("./engine-api.js").EngineDoc) => import("./engine-api.js").EngineNode;
                blockNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
                liveNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
                isLive: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => boolean;
                candidatesOf: (node: import("./engine-api.js").EngineNode) => import("./placement/model.js").PlacementCand[];
                view: (doc: import("./engine-api.js").EngineDoc) => import("./placement/model.js").ModelView;
                resolvePlacements: (blocks: Map<import("./index.js").BlockId, import("./placement/model.js").BlockRec>, ownerOf?: (b: import("./index.js").BlockId) => import("./text/model.js").Owner) => Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>;
                childrenIndex: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./placement/model.js").DisplayOwnership) => Map<import("./index.js").BlockId | null, import("./placement/model.js").ChildSlot[]>;
                positionInView: (v: import("./placement/model.js").ModelView, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
                buildInline: (atom: import("./index.js").InlineSpec) => import("./engine-api.js").EngineNode;
                isSelfOrDescendant: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./text/model.js").Ownership, id: import("./index.js").BlockId, maybeAncestor: import("./index.js").BlockId) => boolean;
                ranksAt: (siblings: readonly {
                    rank: string;
                }[], index: number, count: number, clientId: number, rand?: () => number, run?: boolean) => string[];
                writePlacement: (doc: import("./engine-api.js").EngineDoc, node: import("./engine-api.js").EngineNode, p: import("./index.js").BlockId | null, r: string) => void;
                withdrawOnUndo: (doc: import("./engine-api.js").EngineDoc) => (item: import("./engine-api.js").EngineItemRef, stackItem: {
                    inserts: {
                        has(client: number, clock: number): boolean;
                    };
                }) => boolean;
                materializeSpec: (doc: import("./engine-api.js").EngineDoc, sp: import("./index.js").BlockSpec, parent: import("./index.js").BlockId | null, rank: string) => void;
                collides: (doc: import("./engine-api.js").EngineDoc, specs: readonly import("./index.js").BlockSpec[]) => boolean;
                writeSplit: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail: import("./placement/model.js").SplitTail, place: import("./placement/model.js").PlacementValue) => void;
                ownText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => {
                    from: unknown;
                    to: number;
                };
                insertBlocks: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, specs: import("./index.js").BlockSpec[]) => boolean;
                insertBlock: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, spec: import("./index.js").BlockSpec) => boolean;
                restoreBlocks: (doc: import("./engine-api.js").EngineDoc, specs: import("./index.js").BlockSpec[]) => void;
                project: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").ProjectedDoc;
                positionOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
                listBlockIds: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").BlockId[];
                blockText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
                crdtId: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
                resolveBlock: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
            };
            text: {
                newNode: (name: string) => import("./engine-api.js").EngineNode;
                resolveAnchor: (doc: import("./engine-api.js").EngineDoc, text: import("./engine-api.js").EngineNode, anchor: import("./text/model.js").Anchor) => number | null;
                anchorAt: (text: import("./engine-api.js").EngineNode, index: number, assoc: number) => import("./text/model.js").Anchor;
                openRangeCursor: (text: import("./engine-api.js").EngineNode) => import("./text/model.js").RangeCursor;
                itemsOfRange: (text: import("./engine-api.js").EngineNode, i0: number, i1: number) => import("./text/model.js").RangeItem[];
                readSegs: (segs: readonly import("./text/model.js").Seg[], stats?: import("./text/model.js").RangeReadStats) => import("./text/model.js").RangeItem[];
                computeOwnership: (doc: import("./engine-api.js").EngineDoc, given: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>) => import("./text/model.js").Ownership;
                flatten: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").Seg[];
                ownedLength: (segs: readonly import("./text/model.js").Seg[]) => number;
                contentItemsOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").RangeItem[];
                blockTextOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => string;
                insertIntoText: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, payload: string | import("./engine-api.js").EngineNode, marks?: Record<string, unknown>) => void;
                deleteRange: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number) => void;
                formatRangeIn: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number, formats: Record<string, unknown>) => void;
                purgeStreams: (streams: readonly import("./text/model.js").Stream[]) => void;
                findAtom: (own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, inlineId: string) => {
                    text: import("./engine-api.js").EngineNode;
                    at: number;
                    node: import("./engine-api.js").EngineNode;
                } | null;
                splitAt: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, newId: import("./text/model.js").BlockId, n: number) => import("./text/model.js").MergeClaim[];
                claimInto: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: Pick<import("./text/model.js").Ownership, "streamOf">, from: import("./text/model.js").BlockId, into: import("./text/model.js").BlockId) => void;
                ownText: (doc: import("./engine-api.js").EngineDoc, rec: import("./text/model.js").TextBlockRec) => {
                    from: unknown;
                    to: number;
                };
            };
            runsView: import("./text/runs.js").RunView;
            version: number;
            insertFlow: (target: import("./flow.js").FlowTarget, flow: import("./flow.js").Flow, view?: import("./flow.js").FlowView | undefined) => import("./edytor-doc.js").OpResult;
            deleteRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView | undefined) => import("./edytor-doc.js").OpResult;
            replaceRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView | undefined) => import("./edytor-doc.js").OpResult;
            insertBlocks: (dest: import("./index.js").Destination, specs: readonly (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[]) => import("./edytor-doc.js").OpResult;
            moveBlocks: (ids: readonly string[], dest: import("./index.js").Destination) => import("./edytor-doc.js").OpResult;
            nestBlock: (id: string, parent: string) => import("./edytor-doc.js").OpResult;
            unNestBlock: (id: string) => import("./edytor-doc.js").OpResult;
            unNestBlocks: (ids: readonly string[]) => import("./edytor-doc.js").OpResult;
            liftOut: (id: string, kind: string, args_2?: {
                keep?: boolean;
                after?: readonly import("./index.js").BlockSpec[];
            } | undefined) => import("./edytor-doc.js").OpResult;
            placeBeside: (ids: readonly string[], target: string, side: "right" | "left", kind?: string | undefined) => import("./edytor-doc.js").OpResult;
            wrapInLayout: (ids: readonly string[], kind?: string | undefined, columns?: number | undefined) => import("./edytor-doc.js").OpResult;
            splitBlock: (id: string, offset: number, newId: string, tail?: import("./placement/model.js").SplitTail | undefined) => import("./edytor-doc.js").OpResult;
            mergeBlocks: (fromId: string, intoId: string) => import("./edytor-doc.js").OpResult;
            mergeBackward: (id: string) => import("./edytor-doc.js").OpResult;
            mergeForward: (id: string) => import("./edytor-doc.js").OpResult;
            deleteBlock: (id: string, opts?: {
                keepChildren?: boolean;
            } | undefined) => import("./edytor-doc.js").OpResult;
            setBlock: (id: string, value: {
                type?: string;
                data?: Record<string, unknown>;
                content?: (import("./index.js").ContentItem | import("./index.js").JSONText | import("./index.js").JSONInlineBlock)[];
                children?: (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[];
            }) => import("./edytor-doc.js").OpResult;
            setBlockType: (id: string, type: string) => import("./edytor-doc.js").OpResult;
            patchData: (target: import("./edytor-doc.js").DataTarget, patches: readonly import("./data.js").DataPatch[]) => import("./edytor-doc.js").OpResult;
            duplicateBlock: (id: string, freshId?: ((oldId: string, kind: "block" | "inline") => string) | undefined) => import("./edytor-doc.js").OpResult;
            insertText: (id: string, offset: number, text: string, marks?: Record<string, unknown> | undefined) => import("./edytor-doc.js").OpResult;
            deleteText: (id: string, offset: number, length: number) => import("./edytor-doc.js").OpResult;
            formatRange: (id: string, offset: number, length: number, marks: Record<string, unknown>) => import("./edytor-doc.js").OpResult;
            clearMarks: (id: string, offset: number, length: number) => import("./edytor-doc.js").OpResult;
            insertInline: (id: string, offset: number, atom: import("./doc/content.js").NewInline) => import("./edytor-doc.js").OpResult;
            removeInline: (id: string, inlineId: string) => import("./edytor-doc.js").OpResult;
            deleteBlocks: (ids: readonly string[]) => import("./edytor-doc.js").OpResult;
            init: (opts?: Parameters<(doc: import("./engine-api.js").EngineDoc, opts?: {
                content?: import("./index.js").BlockSpec[];
                defaultType?: string;
            }) => void>[1]) => void;
            seed: (value: import("./index.js").JSONBlock[], data?: import("./doc/types.js").JsonObj) => void;
            isInitialized: () => boolean;
            schemaVersion: () => number | undefined;
            checkSchema: () => import("./edytor-doc.js").SchemaProblem | null;
            assertSchema: () => void;
            dispose: () => void;
            createUndoManager: (options?: import("./doc/history.js").HistoryOptions) => import("./doc/history.js").UndoManager;
            project: () => import("./index.js").ProjectedDoc;
            toJSON: () => import("./index.js").JSONDoc;
            blockJSON: (id: string) => import("./index.js").JSONBlock;
            childrenIds: (id: string | null) => string[];
            childSlots: (parent: import("./index.js").BlockId | null) => import("./placement/model.js").ChildSlot[];
            slotOf: (id: string) => {
                parent: import("./index.js").BlockId | null;
                rank: string;
            } | null;
            positionOf: (id: string) => import("./index.js").Destination | null;
            pathOf: (id: string) => number[] | null;
            parentOf: (id: string) => string | null;
            ancestorsOf: (id: string) => string[];
            listBlockIds: () => string[];
            blockText: (id: string) => string | null;
            blockTypeOf: (id: string) => string | undefined;
            blockDataOf: (id: string) => Record<string, unknown> | undefined;
            docData: () => import("./doc/types.js").JsonObj;
            dataItemIds: (target: import("./edytor-doc.js").DataTarget, path: readonly string[]) => string[];
            blockAttribution: (id: string) => import("./index.js").BlockAttribution | undefined;
            crdtId: (id: string) => string | null;
            resolveBlock: (id: string) => import("./engine-api.js").EngineNode | null;
            displayLength: (id: string) => number;
            contentItems: (id: string) => import("./index.js").ContentItem[];
            hasBlock: (id: string) => boolean;
            isVisibleBlock: (id: string) => boolean;
            order: () => readonly import("./index.js").BlockId[];
            compare: (a: import("./index.js").BlockId, b: import("./index.js").BlockId) => number;
            next: (id: string, policy?: import("./edytor-doc.js").OrderPolicy | undefined) => string | null;
            previous: (id: string, policy?: import("./edytor-doc.js").OrderPolicy | undefined) => string | null;
            anchorAt: (id: string, offset: number, affinity?: import("./edytor-doc.js").AnchorAffinity | undefined) => import("./edytor-doc.js").DocAnchor | null;
            resolveAnchor: (anchor: import("./edytor-doc.js").DocAnchor) => {
                blockId: import("./index.js").BlockId;
                offset: number;
            } | null;
            followUndo: (anchor: import("./edytor-doc.js").DocAnchor) => import("./edytor-doc.js").DocAnchor;
            rolesChanged: () => void;
            isVoid: (id: string) => boolean;
            isIsland: (id: string) => boolean;
            isLines: (id: string) => boolean;
            isLayout: (id: string) => boolean;
            isLayoutItem: (id: string) => boolean;
            besideAt: (id: import("./index.js").BlockId, kind?: string) => string;
            islandOf: (id: string) => string | null;
            isTable: (id: string) => boolean;
            isTableRow: (id: string) => boolean;
            isTableCell: (id: string) => boolean;
            tableOf: (id: string) => string | null;
            tableColumns: (id: string) => {
                id: string;
                width?: number;
            }[] | null;
            tableGrid: (id: string) => {
                columns: string[];
                rows: {
                    id: import("./index.js").BlockId;
                    cells: (import("./index.js").BlockId | null)[];
                }[];
            } | null;
            insideIsland: (id: string) => boolean;
            canPlace: (ids: readonly import("./index.js").BlockId[], parent?: import("./index.js").BlockId | null) => boolean;
            canMerge: (from: import("./index.js").BlockId, into: import("./index.js").BlockId) => boolean;
            fits: (parent: import("./index.js").BlockId | null, kind: string) => boolean;
            nestParent: (ids: readonly import("./index.js").BlockId[], parent: import("./index.js").BlockId) => string;
            landingOf: (id: import("./index.js").BlockId, kind: string, after?: boolean) => {
                parent: string | null;
                levels: string[];
            };
            defaultChild: (id: string | null) => string;
            runs: (id: string) => readonly import("./index.js").ContentRun[];
            contentJSON: (id: string) => ({
                text: string;
                marks?: Record<string, unknown>;
            } | {
                id?: string;
                type: string;
                data?: unknown;
            })[];
            onChange: (cb: (change: import("./edytor-doc.js").DocChange) => void) => (() => void);
        };
        newDoc: (opts?: ConstructorParameters<EngineApi["Doc"]>[0]) => YDoc;
        keepCopies: (doc: import("./engine-api.js").EngineDoc) => void;
        purge: (doc: import("./engine-api.js").EngineDoc, facade: {
            model: import("./placement/model.js").PlacementModel;
            text: import("./text/model.js").TextEngine;
        }, horizon: import("./purge.js").Horizon) => import("./purge.js").PurgeReport;
        horizonOf: (doc: import("./engine-api.js").EngineDoc) => import("./purge.js").Horizon | null;
        restoreTo: <Plan>(doc: import("./engine-api.js").EngineDoc, facade: import("./restore.js").RestoreFacade<Plan>, json: import("./index.js").JSONDoc) => import("./restore.js").RestoreReport;
        model: {
            REGISTRY_KEY: string;
            registryOf: (doc: import("./engine-api.js").EngineDoc) => import("./engine-api.js").EngineNode;
            blockNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
            liveNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
            isLive: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => boolean;
            candidatesOf: (node: import("./engine-api.js").EngineNode) => import("./placement/model.js").PlacementCand[];
            view: (doc: import("./engine-api.js").EngineDoc) => import("./placement/model.js").ModelView;
            resolvePlacements: (blocks: Map<import("./index.js").BlockId, import("./placement/model.js").BlockRec>, ownerOf?: (b: import("./index.js").BlockId) => import("./text/model.js").Owner) => Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>;
            childrenIndex: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./placement/model.js").DisplayOwnership) => Map<import("./index.js").BlockId | null, import("./placement/model.js").ChildSlot[]>;
            positionInView: (v: import("./placement/model.js").ModelView, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
            buildInline: (atom: import("./index.js").InlineSpec) => import("./engine-api.js").EngineNode;
            isSelfOrDescendant: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./text/model.js").Ownership, id: import("./index.js").BlockId, maybeAncestor: import("./index.js").BlockId) => boolean;
            ranksAt: (siblings: readonly {
                rank: string;
            }[], index: number, count: number, clientId: number, rand?: () => number, run?: boolean) => string[];
            writePlacement: (doc: import("./engine-api.js").EngineDoc, node: import("./engine-api.js").EngineNode, p: import("./index.js").BlockId | null, r: string) => void;
            withdrawOnUndo: (doc: import("./engine-api.js").EngineDoc) => (item: import("./engine-api.js").EngineItemRef, stackItem: {
                inserts: {
                    has(client: number, clock: number): boolean;
                };
            }) => boolean;
            materializeSpec: (doc: import("./engine-api.js").EngineDoc, sp: import("./index.js").BlockSpec, parent: import("./index.js").BlockId | null, rank: string) => void;
            collides: (doc: import("./engine-api.js").EngineDoc, specs: readonly import("./index.js").BlockSpec[]) => boolean;
            writeSplit: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail: import("./placement/model.js").SplitTail, place: import("./placement/model.js").PlacementValue) => void;
            ownText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => {
                from: unknown;
                to: number;
            };
            insertBlocks: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, specs: import("./index.js").BlockSpec[]) => boolean;
            insertBlock: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, spec: import("./index.js").BlockSpec) => boolean;
            restoreBlocks: (doc: import("./engine-api.js").EngineDoc, specs: import("./index.js").BlockSpec[]) => void;
            project: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").ProjectedDoc;
            positionOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
            listBlockIds: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").BlockId[];
            blockText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
            crdtId: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
            resolveBlock: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
        };
        text: {
            newNode: (name: string) => import("./engine-api.js").EngineNode;
            resolveAnchor: (doc: import("./engine-api.js").EngineDoc, text: import("./engine-api.js").EngineNode, anchor: import("./text/model.js").Anchor) => number | null;
            anchorAt: (text: import("./engine-api.js").EngineNode, index: number, assoc: number) => import("./text/model.js").Anchor;
            openRangeCursor: (text: import("./engine-api.js").EngineNode) => import("./text/model.js").RangeCursor;
            itemsOfRange: (text: import("./engine-api.js").EngineNode, i0: number, i1: number) => import("./text/model.js").RangeItem[];
            readSegs: (segs: readonly import("./text/model.js").Seg[], stats?: import("./text/model.js").RangeReadStats) => import("./text/model.js").RangeItem[];
            computeOwnership: (doc: import("./engine-api.js").EngineDoc, given: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>) => import("./text/model.js").Ownership;
            flatten: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").Seg[];
            ownedLength: (segs: readonly import("./text/model.js").Seg[]) => number;
            contentItemsOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").RangeItem[];
            blockTextOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => string;
            insertIntoText: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, payload: string | import("./engine-api.js").EngineNode, marks?: Record<string, unknown>) => void;
            deleteRange: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number) => void;
            formatRangeIn: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number, formats: Record<string, unknown>) => void;
            purgeStreams: (streams: readonly import("./text/model.js").Stream[]) => void;
            findAtom: (own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, inlineId: string) => {
                text: import("./engine-api.js").EngineNode;
                at: number;
                node: import("./engine-api.js").EngineNode;
            } | null;
            splitAt: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, newId: import("./text/model.js").BlockId, n: number) => import("./text/model.js").MergeClaim[];
            claimInto: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: Pick<import("./text/model.js").Ownership, "streamOf">, from: import("./text/model.js").BlockId, into: import("./text/model.js").BlockId) => void;
            ownText: (doc: import("./engine-api.js").EngineDoc, rec: import("./text/model.js").TextBlockRec) => {
                from: unknown;
                to: number;
            };
        };
        runs: {
            attach: (doc: import("./engine-api.js").EngineDoc) => import("./text/runs.js").RunView;
        };
    };
    providers: {
        prefetch: (options: PrefetchOptions) => Promise<import("./index.js").PrefetchResult>;
        lastUpdated: (options: import("./index.js").LastUpdatedOptions) => Promise<number | null>;
        documentSnapshot: (options: import("./index.js").LastUpdatedOptions) => Promise<import("./index.js").JSONDoc | null>;
        IndexeddbPersistence: {
            new (name: string, doc: YDoc, options?: import("./protocol.js").IndexeddbPersistenceOptions): {
                doc: YDoc;
                name: string;
                dbName: string;
                _dbref: number;
                _dbsize: number;
                db: IDBDatabase | null;
                _db: Promise<IDBDatabase>;
                _destroyed: boolean;
                hasSynced: boolean;
                whenSynced: Promise<any>;
                _failedEmitted?: boolean;
                _settleSynced: import("./providers/room.js").LifecycleHost["_settleSynced"];
                _leave: () => void;
                loadError: unknown;
                _storeTimeout: number;
                _storeTimeoutId: ReturnType<typeof setTimeout> | null;
                _storeUpdate: (update: Uint8Array, origin: unknown) => void;
                awareness: _Awareness;
                bcconnected: boolean;
                disableBc: boolean;
                _ownsAwareness: boolean;
                _bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
                _awarenessUpdateHandler: (updates: {
                    added: number[];
                    updated: number[];
                    removed: number[];
                }, origin: unknown) => void;
                get synced(): boolean;
                messageHandlers: Record<number, import("./providers/room.js").RoomMessageHandler<any>>;
                readMessage: (buf: Uint8Array, emitSynced: boolean) => import("lib0-v14/encoding").Encoder;
                broadcastMessage(buf: Uint8Array): void;
                connectBc(): void;
                disconnectBc(): void;
                destroy(): Promise<void>;
                emit<N extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: N, args: Parameters<{
                    synced: (provider: any) => void;
                    'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
                    'load-error': (error: unknown, provider: any) => void;
                    'message-error': (error: unknown, provider: any) => void;
                    'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
                    failed: (error: unknown, provider: any) => void;
                }[N]>): void;
                _observers: Map<string, Set<any>>;
                on<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
                    synced: (provider: any) => void;
                    'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
                    'load-error': (error: unknown, provider: any) => void;
                    'message-error': (error: unknown, provider: any) => void;
                    'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
                    failed: (error: unknown, provider: any) => void;
                }[NAME]): {
                    synced: (provider: any) => void;
                    'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
                    'load-error': (error: unknown, provider: any) => void;
                    'message-error': (error: unknown, provider: any) => void;
                    'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
                    failed: (error: unknown, provider: any) => void;
                }[NAME];
                once<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
                    synced: (provider: any) => void;
                    'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
                    'load-error': (error: unknown, provider: any) => void;
                    'message-error': (error: unknown, provider: any) => void;
                    'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
                    failed: (error: unknown, provider: any) => void;
                }[NAME]): void;
                off<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
                    synced: (provider: any) => void;
                    'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
                    'load-error': (error: unknown, provider: any) => void;
                    'message-error': (error: unknown, provider: any) => void;
                    'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
                    failed: (error: unknown, provider: any) => void;
                }[NAME]): void;
            };
        };
        WebsocketProvider: {
            new (serverUrl: string, roomname: string, doc: YDoc, { connect, awareness, params, WebSocketPolyfill, resyncInterval, maxBackoffTime, connectTimeout, disableBc, maxFrameBytes }?: import("./protocol.js").WebsocketProviderOptions): {
                serverUrl: string;
                roomname: string;
                doc: YDoc;
                awareness: _Awareness;
                params: Record<string, string>;
                maxBackoffTime: number;
                connectTimeout: number;
                maxFrameBytes: number;
                _WS: import("./protocol.js").WebsocketPolyfill;
                shouldConnect: boolean;
                ws: WebSocket | null;
                wsconnected: boolean;
                bcChannel: string;
                bcconnected: boolean;
                disableBc: boolean;
                _bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
                _fromTab: {};
                wsUnsuccessfulReconnects: number;
                wsLastMessageReceived: number;
                wsLastPingSent: number;
                _synced: boolean;
                _chunks: import("./protocol.js").ChunkReader;
                _writes: {
                    pending: {
                        sv: Map<number, number>;
                        deletes: import("./protocols/sync.js").IdSet;
                    }[];
                    acked: Map<number, number>;
                    readOnly: boolean;
                    faults: number;
                    fault(): number;
                    readonly doc: YDoc;
                    readonly changed: (unsaved: number) => void;
                    trackDocument(): void;
                    track(sv: Map<number, number>, deletes: import("./protocols/sync.js").IdSet): void;
                    acknowledge(sv: Uint8Array, deletes?: import("./protocols/sync.js").IdSet | null): void;
                    deny(): void;
                    allow(): void;
                };
                messageHandlers: Record<number, import("./providers/room.js").RoomMessageHandler<any>>;
                hasSynced: boolean;
                whenSynced: Promise<unknown>;
                _destroyed: boolean;
                _failedEmitted?: boolean;
                _settleSynced: import("./providers/room.js").LifecycleHost["_settleSynced"];
                _leave: () => void;
                _resync: ReturnType<typeof setInterval> | undefined;
                _connectTimer: ReturnType<typeof setTimeout> | undefined;
                _checkInterval: ReturnType<typeof setInterval>;
                _updateHandler: (update: Uint8Array, origin: unknown, doc?: unknown, transaction?: {
                    local: boolean;
                }) => void;
                _awarenessUpdateHandler: (updates: {
                    added: number[];
                    updated: number[];
                    removed: number[];
                }, origin: unknown) => void;
                get url(): string;
                get unsaved(): number;
                get saved(): boolean;
                get readOnly(): boolean;
                get synced(): boolean;
                set synced(state: boolean);
                destroy(): void;
                disconnect(): void;
                connect(): void;
                emit<N extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: N, args: Parameters<import("./protocol.js").WebsocketProviderEvents[N]>): void;
                _observers: Map<string, Set<any>>;
                on<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): import("./protocol.js").WebsocketProviderEvents[NAME];
                once<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): void;
                off<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): void;
            };
        };
        watchComments: (server: string, roomName: string, listener: (message: import("./protocol.js").CommentMessage) => void) => (() => void);
        storeState: (idbPersistence: {
            db: IDBDatabase | null;
            name: string;
            doc: YDoc;
            _dbref: number;
            _dbsize: number;
            _destroyed: boolean;
        }, forceStore?: boolean) => Promise<undefined>;
        clearDocument: (name: string) => Promise<void>;
        PREFERRED_TRIM_SIZE: number;
        createIndexeddbSync: (name: string) => import("./index.js").EdytorSync;
        createWebsocketSync: (options: import("./index.js").WebsocketSyncOptions) => import("./index.js").WebsocketSync;
    };
    sync: {
        messageYjsSyncStep1: number;
        messageYjsSyncStep2: number;
        messageYjsUpdate: number;
        remoteApplyOrigin: symbol;
        writeSyncStep1: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc) => void;
        writeSyncStep2: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc, encodedStateVector?: Uint8Array) => void;
        writeUpdate: (encoder: import("lib0-v14/encoding").Encoder, update: Uint8Array) => void;
        applyRemote: (doc: YDoc, update: Uint8Array, transactionOrigin: unknown, errorHandler?: (error: Error) => unknown) => {
            applied: boolean;
            problem: import("./edytor-doc.js").SchemaProblem | null;
            discarded?: import("./edytor-doc.js").SchemaProblem;
        };
        lacks: (doc: YDoc, sv: Uint8Array) => boolean;
        writeSaved: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc, deletes?: import("./protocols/sync.js").IdSet, unstored?: import("./protocols/sync.js").IdSet | null) => void;
        readSaved: (decoder: import("lib0-v14/decoding").Decoder) => {
            stateVector: Uint8Array;
            deletes: import("./protocols/sync.js").IdSet | null;
        };
    };
    admission: {
        admitUpdate: (update: Uint8Array | ReadonlyArray<Uint8Array>, docName?: string, options?: {
            prepare?: (doc: YDoc) => void;
        }) => YDoc;
    };
    attribution: {
        attach: (doc: import("./engine-api.js").EngineDoc, opts: {
            actor: import("./index.js").AttributionActor;
        }) => import("./index.js").AttributionController;
    };
};
```

## checkSchema

Inspect the document's schema record. `null` = clean (versioned under the
supported schema AND manifest name, or completely untouched). Read-only,
safe mid-transaction.

```ts
declare const checkSchema: (doc: EngineDoc) => SchemaProblem | null;
```

## chunkFrame

Split `whole` (a complete frame) into frames of at most `maxFrameBytes`:
itself when it fits, else `start(total)`, `part(bytes)`…, `end`. A
receiver applies the reassembled frame only once `end` arrives.

```ts
declare const chunkFrame: (whole: Uint8Array, maxFrameBytes?: number) => Uint8Array[];
```

## ChunkLimitError

A chunk sequence announces a frame larger than its reader takes (`createChunkReader`).

```ts
export declare class ChunkLimitError extends Error {
    readonly total: number;
    readonly limit: number;
    constructor(total: number, limit: number);
}
```

## ChunkReader

A chunk reader (`createChunkReader`): feed it chunk bodies; `buffered` is what it holds.

```ts
export type ChunkReader = {
    (decoder: decoding.Decoder): Uint8Array | null;
    readonly buffered: number;
};
```

- `buffered`: Bytes held for the sequence in flight: its announced size, allocated at its start (0: none).

## CLOSE

The close codes of the edytor room (`edytor/cloudflare`) and its router,
as the websocket provider reads them. Only `expired` and `fault` are
redialed; every other code here is a `isRefusalrefusal`.

```ts
declare const CLOSE: {
    readonly refused: 1008;
    readonly fault: 1011;
    readonly accessChanged: 1012;
    readonly invalidDocument: 4400;
    readonly expired: 4401;
    readonly denied: 4403;
    readonly replicaTaken: 4409;
    readonly quota: 4413;
};
```

## CommentChange

What one request changed (the room broadcasts it, `onComment` receives it).

```ts
export type CommentChange = {
    type: 'added' | 'replied' | 'resolved' | 'reopened' | 'deleted' | 'removed';
    thread: CommentThread;
    comment: ThreadComment | null;
    user: string;
    at: number;
    seq: number;
};
```

- `type`: `added` a thread, `replied` to one, `resolved` or `reopened` one, `deleted` a reply, or `removed` a whole thread (its anchor marks go with it).
- `thread`: The thread after the change; for `removed`, as it was.
- `comment`: The comment added (`added`, `replied`) or deleted (`deleted`), else `null`.
- `user`: Who made the change.
- `seq`: The change's sequence number in its document (the thread's new `rev`).

## CommentMessage

A comment message, decoded.

```ts
export type CommentMessage = {
    type: 'subscribe';
    on: boolean;
} | ({
    type: 'snapshot';
} & CommentSnapshot) | {
    type: 'change';
    change: CommentChange;
};
```

## commentsChange

Room → client: one change.

```ts
declare const commentsChange = 2;
```

## CommentSnapshot

The document's threads at sequence number `seq`.

```ts
export type CommentSnapshot = {
    seq: number;
    threads: CommentThread[];
};
```

## commentsSnapshot

Room → client: every thread, and the document's last sequence number (an answer to a subscribe).

```ts
declare const commentsSnapshot = 1;
```

## commentsSubscribe

Client → room: start (or stop) hearing the document's comment changes.

```ts
declare const commentsSubscribe = 0;
```

## CommentThread

A comment thread: its first comment starts it, the others reply.

```ts
export type CommentThread = {
    id: string;
    block: string | null;
    quote: string;
    createdBy: string;
    createdAt: number;
    resolved: {
        by: string;
        at: number;
    } | null;
    comments: ThreadComment[];
    rev: number;
};
```

- `id`: The thread's id, which its anchor mark names (`comment:<id>`).
- `block`: The block it was started in (`null`: unknown).
- `quote`: The text it was started on, as it read then (at most `MAX_QUOTE_LENGTH`).
- `resolved`: Who resolved it and when; `null` while it is open.
- `comments`: Oldest first; never empty.
- `rev`: The sequence number of the last change to it (a later change has a greater one).

## Crdt

```ts
export type Crdt = ReturnType<typeof bindCrdt>;
```

## createChunkReader

The receiving half of `chunkFrame`, one per connection: feed it
each chunk frame's body (after the message type); it returns the whole
frame on `end`, `null` before. An out-of-order or oversized sequence
throws and resets; a sequence announcing more than `maxBytes` throws
`ChunkLimitError` at its start, before anything is buffered. A
sequence is assembled into ONE buffer of its announced size, allocated
at its start (`buffered`), never into parts copied at its end.
`admit(total)` is asked at each start, before that allocation: it may
throw to refuse the sequence, or return `false` to skip it (its parts
are read and dropped, and its end returns `null`).

```ts
declare const createChunkReader: (maxBytes?: number, admit?: (total: number) => boolean) => ChunkReader;
```

## createDecoder

## Decoder

A Decoder handles the decoding of an Uint8Array.

## encodeAwarenessUpdate

The update carrying `clients`' entries of `awareness` (their states in `states`).

```ts
declare const encodeAwarenessUpdate: (awareness: Awareness, clients: number[], states?: AwarenessStates) => Uint8Array;
```

## Encoder

A BinaryEncoder handles the encoding to an Uint8Array.

## EngineApi

The engine surface every `bind*` receives: the object in `engine.js`
(exactly the symbols edytor calls, so consumer bundles tree-shake the
rest). The full namespace `import * as Y from 'edytor/crdt'` is a
superset and satisfies it.

```ts
export type EngineApi = typeof Engine;
```

## EngineDoc

Structural minimum of the vendored `Y.Doc`.

```ts
export interface EngineDoc {
    clientID: number;
    keepReplaced?: ((item: never) => boolean) | null;
    get(key?: string): EngineNode;
    transact<T>(f: (transaction: unknown) => T, origin?: unknown): T;
    on(name: 'update', f: (update: Uint8Array, origin: unknown, doc: EngineDoc, transaction: unknown) => void): void;
    off(name: 'update', f: (update: Uint8Array, origin: unknown, doc: EngineDoc, transaction: unknown) => void): void;
    on(name: 'commit', f: (transaction: never) => void): void;
    off(name: 'commit', f: (transaction: never) => void): void;
    on(name: 'destroy', f: () => void): void;
    off(name: 'destroy', f: () => void): void;
    readonly store?: {
        pendingStructs: null | {
            missing: Map<number, number>;
            update: Uint8Array;
        };
        pendingDs: null | Uint8Array;
        getClock(client: number): number;
    };
    readonly _transaction?: EngineTransaction | null;
}
```

- `keepReplaced`: Which node values a concurrent write of the same key replaced keep their subtree (`null`: none, upstream's semantics).
- `on`: Doc-level `update` channel — fires once per transaction that produced replicated state (local commits AND remote `applyUpdate`s), carrying the transaction's origin and the transaction itself (`transaction.local` distinguishes local commits from remote applies).
- `on`: Doc-level `update` channel — fires once per transaction that produced replicated state (local commits AND remote `applyUpdate`s), carrying the transaction's origin and the transaction itself (`transaction.local` distinguishes local commits from remote applies).
- `on`: Doc-level `update` channel — fires once per transaction that produced replicated state (local commits AND remote `applyUpdate`s), carrying the transaction's origin and the transaction itself (`transaction.local` distinguishes local commits from remote applies).
- `store`: The doc's struct store — present on a real engine doc.
- `_transaction`: The engine's CURRENT transaction (`null` outside one) — vendored `Doc._transaction`.

## EngineItemRef

Engine item identity — used by `crdtId` (`client:clock`).

```ts
export type EngineItemRef = {
    id?: {
        client: number;
        clock: number;
    };
    deleted?: boolean;
    parent?: unknown;
    parentSub?: string | null;
} | null;
```

## EngineNode

Structural minimum of the vendored `Y.Node` (v14) used by the placement
model. A real `YNode` satisfies this at runtime; typed consumers cast once
at the boundary (`doc as unknown as EngineDoc`).

```ts
export interface EngineNode {
    readonly name: string;
    readonly doc: unknown | null;
    readonly length: number;
    readonly _item: EngineItemRef;
    getAttr(key: string): unknown;
    setAttr(key: string, value: unknown): unknown;
    deleteAttr(key: string): void;
    forEachAttr(f: (value: unknown, key: string, node: EngineNode) => void): void;
    attrKeys(): IterableIterator<string>;
    insert(index: number, content: unknown): void;
    delete(index: number, length?: number): void;
}
```

- `name`: Node name ('block' | 'content' | 'at' | 'inline' in our schema).
- `doc`: The doc this node is integrated into; `null` while detached.
- `length`: Sequence length (invalid read on detached nodes — track offsets instead).
- `_item`: The item this node is attached to (identity anchor for `crdtId`).

## EngineTransaction

Structural minimum of the in-flight engine `Transaction` — exposed on the
doc as `doc._transaction` while a transaction is open. `changed` maps each
touched shared type to the set of `parentSub` keys whose items changed
(attr names for map-like children, `null` for sequence edits); the
document index folds it once at commit.

```ts
export interface EngineTransaction {
    changed?: Map<unknown, Set<string | null>>;
}
```

## frame

One provider frame: the generation word, the message type, then `write`'s payload.

```ts
declare const frame: (type: number, write: (encoder: encoding.Encoder) => void) => Uint8Array;
```

## GENERATION

This build's generation word.

```ts
declare const GENERATION: number;
```

## GENERATION_RECORD

This generation's record.

```ts
declare const GENERATION_RECORD: GenerationRecord;
```

## GenerationMismatchError

```ts
export declare class GenerationMismatchError extends Error {
    readonly dbName: string;
    readonly found: unknown;
    constructor(dbName: string, found: unknown);
}
```

## GenerationRecord

Record written to the `custom` store marking a DB as this generation's.
Every row of a container holds an update in the engine's one encoding;
a snapshot row may be gzip-compressed (`crdt/storage.ts`).

```ts
export type GenerationRecord = {
    engine: 'yjs-v14';
    protocol: number;
    schema: number;
};
```

## generationWord

The frame word a build of application schema `schema` writes.

```ts
declare const generationWord: (schema: number) => number;
```

## IndexeddbPersistence

```ts
declare const IndexeddbPersistence: ProviderStack['IndexeddbPersistence'];
```

## IndexeddbPersistenceApi

Instance type of the bound provider class.

```ts
export type IndexeddbPersistenceApi = InstanceType<IndexeddbProvider['IndexeddbPersistence']>;
```

## IndexeddbPersistenceOptions

```ts
export type IndexeddbPersistenceOptions = {
    awareness?: Awareness;
    disableBc?: boolean;
};
```

- `disableBc`: Stay off the BroadcastChannel room (no cross-tab sync): storage only.

## inspectAdmission

Non-throwing `assertAdmission` — for audits, diagnostics, and
tests that need the verdict without control flow. Unexpected
(non-admission) errors still throw.

```ts
declare const inspectAdmission: (doc: EngineDoc, docName?: string) => AdmissionResult;
```

## isInitialized

True iff the document carries the schema version record. Content alone —
e.g. a raw `doc.get('blocks').setAttr('x', …)` write — is NOT proof of
initialization: the gate distinguishes "versioned" from "has any registry
state" so rogue unversioned writes never masquerade as an initialized doc.
A replica that learned `meta.v` purely by applying updates counts.

```ts
declare const isInitialized: (doc: EngineDoc) => boolean;
```

## MAX_FRAME_BYTES

A WebSocket message limit on Cloudflare (32 MiB): a larger frame is sent as chunks.

```ts
declare const MAX_FRAME_BYTES: number;
```

## messageAuth

```ts
declare const messageAuth = 2;
```

## messageAwareness

```ts
declare const messageAwareness = 1;
```

## messageChunk

Server → client: one piece of a frame too large to send whole (bounded catch-up).

```ts
declare const messageChunk = 5;
```

## messageComments

Both ways: a document's comment threads (`protocols/comments.ts`): a
client subscribes, the room answers every thread, then each change. The
room sends it only to a socket that subscribed.

```ts
declare const messageComments = 6;
```

## messagePermissionDenied

```ts
declare const messagePermissionDenied = 0;
```

## messageQueryAwareness

```ts
declare const messageQueryAwareness = 3;
```

## messageReadOnly

The socket may read but not write: sent when it joins, before any write is refused.

```ts
declare const messageReadOnly = 1;
```

## messageSaved

Server → client: the room persisted everything under this state vector (store-before-ack).

```ts
declare const messageSaved = 4;
```

## messageSync

```ts
declare const messageSync = 0;
```

## messageYjsSyncStep1

Sync message subtypes (the varuint after `messageSync`).

```ts
declare const messageYjsSyncStep1 = 0;
```

## messageYjsSyncStep2

```ts
declare const messageYjsSyncStep2 = 1;
```

## messageYjsUpdate

```ts
declare const messageYjsUpdate = 2;
```

## META_KEY

```ts
declare const META_KEY: "meta";
```

## PROTOCOL_VERSION

Provider protocol generation. Chosen so it can never collide with a v13
message type word (0..3) at the same position.

```ts
declare const PROTOCOL_VERSION = 14;
```

## ProtocolMismatch

```ts
export type ProtocolMismatch = {
    expected: number;
    found: number | null;
};
```

## ProviderStack

```ts
export type ProviderStack = ReturnType<typeof bindProviders>;
```

## readAwarenessEntries

Instance-free awareness codec: decode an update into its entries. Pure —
no `Awareness` (whose constructor starts an interval), so a relay that
must not hold timers (a hibernating Durable Object) can track presence.

```ts
declare const readAwarenessEntries: (update: Uint8Array) => AwarenessEntry[];
```

## readCommentsMessage

Read one comment message (after its message type); throws on bytes that do not decode.

```ts
declare const readCommentsMessage: (decoder: decoding.Decoder) => CommentMessage;
```

## readProtocolVersion

Read and verify the generation word. Returns `true` iff the message is
this generation's and the caller may dispatch on the next varuint (the
message type). On `false` the caller MUST NOT read further or apply
anything.

```ts
declare const readProtocolVersion: (decoder: decoding.Decoder) => boolean;
```

## readVarUint

## readVarUint8Array

## registryEmpty

True iff the `blocks` registry holds at least one entry (live or deleted).

```ts
declare const registryEmpty: (doc: EngineDoc) => boolean;
```

## SCHEMA_VERSION

```ts
declare const SCHEMA_VERSION: 6;
```

## SchemaMismatchDetail

Inbound refusal detail — emitted on `'schema-mismatch'` (and mirrored
through `'message-error'` as a `SchemaMismatchError`) when a
received update would write a foreign schema stamp (`unsupported`
version, `foreign` manifest, or a deleted stamp — `unversioned`). The
update is never integrated, persisted, or rebroadcast.

```ts
export type SchemaMismatchDetail = {
    docName: string;
    problem: SchemaProblem;
};
```

## SchemaMismatchError

Error raised by `assertSchema` — carries the detected problem.

```ts
export declare class SchemaMismatchError extends Error {
    readonly docName: string;
    readonly problem: SchemaProblem;
    constructor(docName: string, problem: SchemaProblem);
}
```

## SchemaProblem

A document's relationship to this build's schema:

- `unversioned` — registry state exists but `meta.v` is absent. Someone
  wrote replicated content without running the schema path (a rogue or
  v13-era write). This state must NEVER be persisted/broadcast as a
  document update by a provider.
- `unsupported` — `meta.v` names a version this build does not speak
  (e.g. `99` written by a future build). Content still applies (a replica
  cannot refuse structs it already shares a protocol with), but providers
  surface a `schema-mismatch` signal so operators can detect skew.
- `foreign` — `meta.v` is the supported version but `meta.schema` is
  missing or names a DIFFERENT manifest (`'not-edytor'`, a next-gen name,
  an app-local doc kind). A valid version number alone does not make the
  payload an edytor document — the manifest name is part of the contract
  (the version-only check let foreign `meta.schema` values
  cross the staging boundary).

```ts
export type SchemaProblem = {
    kind: 'unversioned' | 'unsupported' | 'foreign';
    version?: number;
    schema?: unknown;
};
```

- `version`: The observed `meta.v` (undefined for `unversioned`).
- `schema`: The observed `meta.schema` (undefined when absent).

## schemaVersion

The replicated schema version (`meta.v`) — `undefined` before init.
Read-only: `doc.get` on a root emits no update.

```ts
declare const schemaVersion: (doc: EngineDoc) => number | undefined;
```

## storeState

Compact an `IndexeddbPersistence`'s store into one snapshot now (it settles once stored).

```ts
declare const storeState: ProviderStack['storeState'];
```

## SyncProtocol

```ts
export type SyncProtocol = ReturnType<typeof bindSync>;
```

## ThreadComment

One comment of a thread.

```ts
export type ThreadComment = {
    id: string;
    author: string;
    body: string;
    createdAt: number;
};
```

- `author`: The verified user who wrote it.
- `body`: Plain text (line breaks kept).
- `createdAt`: ms since the epoch.

## UndecodableUpdateError

Raised when a candidate update cannot even be decoded or integrated —
refused before the schema question is ever asked. Distinct from the
schema refusals: this payload was never document-shaped.

```ts
export declare class UndecodableUpdateError extends Error {
    readonly docName: string;
    readonly cause: unknown;
    constructor(docName: string, cause: unknown);
}
```

- `docName`: What the update was offered as (e.g.

## UnsupportedDocError

Error raised by `assertUsableDoc` — the doc cannot host a v14 facade:
a foreign engine object (a v13 `yjs` Doc — a different CRDT implementation
entirely).

```ts
export declare class UnsupportedDocError extends Error {
    readonly kind: 'foreign';
    constructor(kind: 'foreign');
}
```

## WebsocketPolyfill

```ts
export type WebsocketPolyfill = {
    new (url: string): WebSocket;
    prototype: WebSocket;
    readonly OPEN: number;
};
```

## WebsocketProvider

```ts
declare const WebsocketProvider: ProviderStack['WebsocketProvider'];
```

## WebsocketProviderEvents

```ts
export type WebsocketProviderEvents = {
    status: (event: {
        status: 'connected' | 'disconnected' | 'connecting';
    }) => void;
    synced: (state: boolean) => void;
    'connection-close': (event: CloseEvent | null, provider: unknown) => void;
    'connection-error': (event: Event, provider: unknown) => void;
    'protocol-mismatch': (mismatch: ProtocolMismatch, provider: unknown) => void;
    'message-error': (error: unknown, provider: unknown) => void;
    'schema-mismatch': (detail: SchemaMismatchDetail, provider: unknown) => void;
    saved: (state: {
        saved: boolean;
        unsaved: number;
    }, provider: unknown) => void;
    'permission-denied': (reason: string, provider: unknown) => void;
    refused: (refusal: SyncRefusedError, provider: unknown) => void;
    expired: (state: {
        reason: string;
        attempts: number;
        nextRetryMs: number;
    }, provider: unknown) => void;
    unreachable: (state: {
        attempts: number;
        nextRetryMs: number;
    }, provider: unknown) => void;
    failed: (error: unknown, provider: unknown) => void;
};
```

- `'message-error'`: Fired when a v14-tagged frame could not be decoded (truncated/corrupt frame or an unknown message type), or when a sync payload failed to apply.
- `'schema-mismatch'`: A received update wrote a foreign schema stamp and was refused (SchemaMismatchDetail).
- `saved`: The count of local updates the room has not yet acknowledged as persisted changed (store-before-ack: a `messageSaved` frame carries the room's state vector after it stored what it holds).
- `'permission-denied'`: Server refused access — the auth reply carried a denial reason.
- `refused`: The server closed the socket with a refusal code (`1008`, `4xxx`): the provider stopped dialing.
- `expired`: The server closed the socket with `4401`: the credentials expired.
- `unreachable`: A dial ended before its connection synced (refused upgrade, dropped handshake, server down, not open within `connectTimeout`): `attempts` in a row, the next in `nextRetryMs`.
- `failed`: Terminal sync failure: the provider never synced — destroyed before any handshake completed, refused, or the server denied permission.

## WebsocketProviderOptions

```ts
export type WebsocketProviderOptions = {
    connect?: boolean;
    awareness?: Awareness;
    params?: Record<string, string>;
    WebSocketPolyfill?: WebsocketPolyfill;
    resyncInterval?: number;
    maxBackoffTime?: number;
    connectTimeout?: number;
    disableBc?: boolean;
    maxFrameBytes?: number;
};
```

- `params`: Query parameters (auth tokens), read at every dial.
- `resyncInterval`: Re-send a Step1 every `resyncInterval` ms on the live socket (off by default): heals frames a test harness drops; the join rule needs no timer.
- `maxBackoffTime`: Max reconnect backoff (exponential backoff is used).
- `connectTimeout`: ms a dial may take to open before it is closed like a failed one (default 10 000; `Infinity` waits for as long as the browser does).
- `disableBc`: Opt out of cross-tab sync over the BroadcastChannel (on by default).
- `maxFrameBytes`: Largest frame sent whole (default 32 MiB, Cloudflare's WebSocket message limit): a larger one — a reconnect's backlog, a big paste — goes out as a chunk sequence the room reassembles.

## writeAwarenessEntries

Instance-free awareness codec: encode entries as an update.

```ts
declare const writeAwarenessEntries: (entries: readonly AwarenessEntry[]) => Uint8Array;
```

## writeCommentsChange

```ts
declare const writeCommentsChange: (encoder: encoding.Encoder, change: CommentChange) => void;
```

## writeCommentsSnapshot

```ts
declare const writeCommentsSnapshot: (encoder: encoding.Encoder, snapshot: CommentSnapshot) => void;
```

## writeCommentsSubscribe

```ts
declare const writeCommentsSubscribe: (encoder: encoding.Encoder, on: boolean) => void;
```

## writePermissionDenied

```ts
declare const writePermissionDenied: (encoder: encoding.Encoder, reason: string) => void;
```

## writeReadOnly

```ts
declare const writeReadOnly: (encoder: encoding.Encoder) => void;
```

## writeVarUint8Array

## YDoc

```ts
export type YDoc = InstanceType<typeof Y.Doc>;
```

## YItem

```ts
export type YItem = Y.Item;
```

## YNode

```ts
export type YNode = InstanceType<typeof Y.Node>;
```

## YTransaction

```ts
export type YTransaction = Y.Transaction;
```

## YUndoManager

The document's undo manager (`doc/history.ts`).

```ts
export type YUndoManager = import('./doc/history.js').UndoManager;
```
