Skip to content
Edytor
Esc
↑↓navigate↵open⌘Jpreview
On this page

edytor/protocol

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

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.

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.
export type AdmissionVerdict = 'fresh' | 'initialized';

applyAwarenessUpdate

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

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.

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.

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.

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

AwarenessEntry

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

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

bindCrdt

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.

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.

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

ChunkLimitError

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

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.

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.

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).

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.

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

commentsChange

Room → client: one change.

declare const commentsChange = 2;

CommentSnapshot

The document’s threads at sequence number seq.

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

commentsSnapshot

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

declare const commentsSnapshot = 1;

commentsSubscribe

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

declare const commentsSubscribe = 0;

CommentThread

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

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

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).

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).

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.

export type EngineApi = typeof Engine;

EngineDoc

Structural minimum of the vendored Y.Doc.

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 applyUpdates), 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 applyUpdates), 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 applyUpdates), 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).

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).

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.

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

frame

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

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

GENERATION

This build’s generation word.

declare const GENERATION: number;

GENERATION_RECORD

This generation’s record.

declare const GENERATION_RECORD: GenerationRecord;

GenerationMismatchError

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).

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

generationWord

The frame word a build of application schema schema writes.

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

IndexeddbPersistence

declare const IndexeddbPersistence: ProviderStack['IndexeddbPersistence'];

IndexeddbPersistenceApi

Instance type of the bound provider class.

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

IndexeddbPersistenceOptions

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.

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.

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

MAX_FRAME_BYTES

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

declare const MAX_FRAME_BYTES: number;

messageAuth

declare const messageAuth = 2;

messageAwareness

declare const messageAwareness = 1;

messageChunk

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

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.

declare const messageComments = 6;

messagePermissionDenied

declare const messagePermissionDenied = 0;

messageQueryAwareness

declare const messageQueryAwareness = 3;

messageReadOnly

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

declare const messageReadOnly = 1;

messageSaved

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

declare const messageSaved = 4;

messageSync

declare const messageSync = 0;

messageYjsSyncStep1

Sync message subtypes (the varuint after messageSync).

declare const messageYjsSyncStep1 = 0;

messageYjsSyncStep2

declare const messageYjsSyncStep2 = 1;

messageYjsUpdate

declare const messageYjsUpdate = 2;

META_KEY

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.

declare const PROTOCOL_VERSION = 14;

ProtocolMismatch

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

ProviderStack

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.

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

readCommentsMessage

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

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.

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

readVarUint

readVarUint8Array

registryEmpty

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

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

SCHEMA_VERSION

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.

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

SchemaMismatchError

Error raised by assertSchema — carries the detected problem.

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).
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.

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

storeState

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

declare const storeState: ProviderStack['storeState'];

SyncProtocol

export type SyncProtocol = ReturnType<typeof bindSync>;

ThreadComment

One comment of a thread.

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.

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).

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

WebsocketPolyfill

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

WebsocketProvider

declare const WebsocketProvider: ProviderStack['WebsocketProvider'];

WebsocketProviderEvents

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

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.

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

writeCommentsChange

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

writeCommentsSnapshot

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

writeCommentsSubscribe

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

writePermissionDenied

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

writeReadOnly

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

writeVarUint8Array

YDoc

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

YItem

export type YItem = Y.Item;

YNode

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

YTransaction

export type YTransaction = Y.Transaction;

YUndoManager

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

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

Was this page helpful?