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

edytor/crdt/edytor

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

Every name edytor/crdt/edytor 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. 119 names.

ActorId

The durable per-block attribution record a replica sees.

export type ActorId = string;

ActorProfile

Replicated actor profile record payload (u/ values).

export type ActorProfile = {
    name?: string;
    color?: string;
};

AnchorAffinity

Selection-endpoint affinity — which side of a position the anchor binds to (see T.atomAnchorAt):

  • 'left' — bound to the atom BEFORE the position; resolves right after it, so a concurrent insert exactly at the position lands to the anchor’s right. Used for carets and range ENDS.
  • 'right' — bound to the atom AT the position; resolves right before it, so a concurrent insert lands to the anchor’s left — outside a range starting here. Used for range STARTS.
export type AnchorAffinity = 'left' | 'right';

attachDocument

See DocumentBinding.attachDocument.

declare const attachDocument: (doc: YDoc, options?: DocumentOptions) => EdytorDocument;

AttributionActor

The stable application-level author identity (mirrors DocumentActor).

export type AttributionActor = {
    id: string;
    name?: string;
    color?: string;
};

AttributionController

export type AttributionController = {
    readonly view: DocumentAttribution;
    setProfile(profile: ActorProfile): void;
    destroy(): void;
};
  • view: The public read surface handed to EdytorDocument.attribution.
  • setProfile: Re-publish the local actor’s profile record (u/<actorId> LWW).
  • destroy: Release the controller; setProfile becomes a no-op.

Awareness

Simple shared state protocol for non-persistent data (cursor, username, status…). Semantics are verbatim upstream: clock-ordered LWW per client, remote null states mark peers offline, local state is re-published when outdated, and remote states expire after outdatedTimeout.

export declare class Awareness extends IsolatedObservable<AwarenessEvents> {
    #private;
    doc: AwarenessDoc;
    clientID: number;
    states: AwarenessStates;
    meta: Map<number, MetaClientState>;
    private _destroyed;
    constructor(doc: AwarenessDoc);
    destroy(): void;
    getLocalState(): Record<string, unknown> | null;
    setLocalState(state: Record<string, unknown> | null): void;
    setLocalStateField(field: string, value: unknown): void;
    getStates(): AwarenessStates;
}
  • states: Maps from client id to client state

AwarenessDoc

Structural minimum an Awareness host must satisfy. Y.Doc (vendored v14) satisfies this; the structural type keeps Awareness free of any engine runtime import.

export interface AwarenessDoc {
    clientID: number;
    on(name: 'destroy', f: (doc: unknown) => void): void;
}

AwarenessStates

export type AwarenessStates = Map<number, Record<string, unknown>>;

AwarenessUpdate

export type AwarenessUpdate = {
    added: number[];
    updated: number[];
    removed: number[];
};

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;
    };
};

BlockAttribution

export type BlockAttribution = {
    createdBy?: ActorId;
    contributors: ReadonlySet<ActorId>;
    lastChangedBy?: ActorId;
};
  • createdBy: The actor that created the block — assigned at creation, never rewritten.
  • contributors: Union set of actors that committed an edit addressing this block id, plus the pre-split snapshot a split/merge copies to siblings — block-identity LINEAGE, add-only.
  • lastChangedBy: The actor whose state change currently wins the LWW resolution.

BlockId

Logical block identifier — caller-assigned, immutable per block.

export type BlockId = string;

BlockRole

Structural role of a block type (plugin-side policy, resolved per op).

export type BlockRole = {
    void?: boolean;
    island?: boolean;
    lines?: boolean;
    layout?: boolean;
    table?: boolean;
    atomic?: readonly (string | readonly string[])[];
};
  • void: Not editable through normal structural flow; no children, no merges.
  • island: Editable, but its subtree is structurally sealed from outside blocks.
  • lines: An island of lines (code): each direct child displays as its defaultChild kind and holds no children.
  • layout: A layout (columns): it displays only its items — its defaultChild kind, a container that renders no content — side by side, and only while it shows two or more (layout.* in the delete contract).
  • table: A table: it displays only its rows — its defaultChild kind, a container whose own defaultChild is the cell kind (a text island) — and each row only its cells, in the order of the table’s data.columns (table.* in the delete contract).
  • atomic: Data paths written as one leaf (data.atomic): a top-level key, or an array of keys for a nested one (['link', ['media', 'source']]).

BlockSpec

Declarative block description used for inserts (and by seeders).

export type BlockSpec = {
    id: BlockId;
    type: string;
    data?: Record<string, unknown>;
    content?: ContentItem[];
    children?: BlockSpec[];
};

codeKinds

createCodePlugin()’s structural rows: the code block is an island of codeLines (lines).

declare const codeKinds: {
    code: {
        island: true;
        lines: true;
        rendersContent: false;
        defaultChild: string;
    };
};

codeSemantics

createCodePlugin()’s block roles.

declare const codeSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

commentMarks

The comments plugin’s mark edge: a comment’s anchor (comment:<id>) never grows at its ends, so text typed or inserted concurrently right after commented text stays out of the comment (Notion).

declare const commentMarks: {
    comment: {
        edge: "exclusive";
    };
};

ContentItem

One inline content element in a block spec / projection.

export type ContentItem = {
    kind: 'text';
    text: string;
    marks?: Record<string, unknown>;
} | {
    kind: 'inline';
    id: string;
    type: string;
    data?: Record<string, unknown>;
};

ContentRun

One visible run of a block — the maintained form of ContentItem. marks/data are interned: equal payloads share one frozen instance, so === compares formatting without deep walks. A run carries no authorship: runs never split at author boundaries, and durable attribution is the compact per-block record (blockattr).

export type ContentRun = {
    kind: 'text';
    text: string;
    marks?: Record<string, unknown>;
} | {
    kind: 'inline';
    id: string;
    type: string;
    data?: Record<string, unknown>;
};

Crdt

export type Crdt = ReturnType<typeof bindCrdt>;

createDocument

See DocumentBinding.createDocument.

declare const createDocument: (options?: CreateDocumentOptions) => EdytorDocument;

CreateDocumentOptions

export type CreateDocumentOptions = DocumentOptions & {
    value?: JSONDoc;
};

DataPatch

One data edit at path (object keys and array indexes from the data’s root): splice takes Array.prototype.splice’s arguments and order the array’s current indexes in their new order; else it sets value, or deletes the key or removes the item when there is none.

export type DataPatch = {
    readonly path: readonly string[];
    readonly value?: unknown;
    readonly splice?: readonly [
        start: number,
        deleteCount?: number,
        ...items: unknown[]
    ];
    readonly order?: readonly number[];
};

DataTarget

What a data patch edits: a block, one of its inline atoms, or the document (null).

export type DataTarget = BlockId | null | {
    block: BlockId;
    atom: string;
};

DEFAULT_HISTORY_LIMIT

The undo steps a document’s history keeps by default: older ones are released.

declare const DEFAULT_HISTORY_LIMIT = 200;

DEFAULT_READINESS_BOUND

How long (ms) an empty document waits for a provider that has not settled before it decides without it (settle-or-bound) — the bound a provider that cannot report “settled” gets, counted from its attach. A factory sets its own with sync.bound, or arms it from transport state (bound: Infinity + the payload’s armBound, as the websocket sync does: from the socket’s open, so a slow dial never counts).

declare const DEFAULT_READINESS_BOUND = 1000;

defaultSemantics

The rich-text, code, image, media, columns, page, table of contents, table and equation plugins’ block roles together (and the rich-text and comment mark edges) — what the room and a headless createDocument/loadDocument adopt by default (semantics: {} checks none). The media, columns, page, table of contents, table and equation plugins are not default plugins of <Edytor>, but their roles are here so their blocks read the same on every replica.

declare const defaultSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
} & {
    marks: Record<string, {
        edge: MarkEdge;
    }>;
};

Destination

Where a block goes: parent = logical block id or null for root.

export type Destination = {
    parent: BlockId | null;
    index: number;
};

DocAnchor

A selection endpoint: b is the home block of the backing text the position lives in (NOT necessarily the block that displays it — merges and splits reroute display while the anchor stays on the same items), a an engine relative position whose a carries the side (< 0 left, >= 0 right). The containing stream and the side are two facts in two fields. JSON-serializable — the presence and history wire shape.

export type DocAnchor = {
    b: BlockId;
    a: Anchor;
};

DocChange

One committed transaction’s semantic diff — the payload EdytorDoc.onChange subscribers receive. Every collection names the affected ids; order carries the NEW child-id list per changed parent so a mirror can apply the diff without re-reading the doc. The report is shared: every subscriber of the document (each view over it, its cells included) receives the same object, so it is read-only.

export type DocChange = {
    origin: unknown;
    local: boolean;
    version: number;
    added: ReadonlyMap<BlockId, ProjectedBlock>;
    removed: ReadonlySet<BlockId>;
    moved: ReadonlySet<BlockId>;
    meta: ReadonlyMap<BlockId, {
        type: string;
        data?: Record<string, unknown>;
    }>;
    content: ReadonlyMap<BlockId, readonly ContentRun[]>;
    order: ReadonlyMap<BlockId | null, readonly BlockId[]>;
    data?: Record<string, unknown>;
};
  • origin: Transaction origin (local origin object, remote marker, …).
  • local: transaction.local — false for remote-applied updates.
  • version: Monotonic event counter per facade.
  • added: Newly visible blocks → full projected subtree (incl.
  • removed: Ids no longer visible (deleted, merged-away, or hidden with subtree).
  • moved: Ids whose display parent or sibling index changed.
  • meta: Ids whose type/data payload changed → new values.
  • content: Ids whose visible content changed → the new maintained runs.
  • order: Parents (null = root) whose visible child list changed → new order (frozen — shared with the retained snapshot baseline).
  • data: The document’s own data (docData()), when this commit changed it.

DocPosition

A position in one document version: a block and a display offset.

export type DocPosition = {
    block: BlockId;
    offset: number;
};

DOCUMENT_OPERATIONS

Every name of DocumentOperations, for the document’s own members (EdytorDocument).

declare const DOCUMENT_OPERATIONS: readonly [
    "insertBlocks",
    "moveBlocks",
    "nestBlock",
    "unNestBlock",
    "unNestBlocks",
    "liftOut",
    "wrapInLayout",
    "placeBeside",
    "splitBlock",
    "mergeBlocks",
    "mergeBackward",
    "mergeForward",
    "deleteBlock",
    "deleteBlocks",
    "setBlock",
    "setBlockType",
    "patchData",
    "duplicateBlock",
    "insertText",
    "deleteText",
    "formatRange",
    "clearMarks",
    "insertInline",
    "removeInline",
    "deleteRange",
    "replaceRange",
    "insertFlow",
    "toJSON",
    "docData",
    "dataItemIds",
    "project",
    "blockJSON",
    "childrenIds",
    "parentOf",
    "ancestorsOf",
    "positionOf",
    "pathOf",
    "blockTypeOf",
    "blockDataOf",
    "blockText",
    "contentItems",
    "displayLength",
    "runs",
    "hasBlock",
    "isVisibleBlock",
    "listBlockIds",
    "blockAttribution",
    "isVoid",
    "isIsland",
    "isLines",
    "islandOf",
    "insideIsland",
    "isLayout",
    "isLayoutItem",
    "besideAt",
    "isTable",
    "isTableRow",
    "isTableCell",
    "tableOf",
    "tableColumns",
    "tableGrid",
    "order",
    "compare",
    "next",
    "previous",
    "canPlace",
    "canMerge",
    "fits",
    "nestParent",
    "landingOf",
    "anchorAt",
    "resolveAnchor",
    "prepare",
    "apply",
    "compose",
    "transact",
    "onChange",
    "version"
];

DOCUMENT_WRITES

Every write of DocumentWrites: what a view dispatches under the same names (edytor.insertBlocks(…)).

declare const DOCUMENT_WRITES: readonly [
    "insertBlocks",
    "moveBlocks",
    "nestBlock",
    "unNestBlock",
    "unNestBlocks",
    "liftOut",
    "wrapInLayout",
    "placeBeside",
    "splitBlock",
    "mergeBlocks",
    "mergeBackward",
    "mergeForward",
    "deleteBlock",
    "deleteBlocks",
    "setBlock",
    "setBlockType",
    "patchData",
    "duplicateBlock",
    "insertText",
    "deleteText",
    "formatRange",
    "clearMarks",
    "insertInline",
    "removeInline",
    "deleteRange",
    "replaceRange",
    "insertFlow"
];

DocumentActor

Local actor identity — durable across replicas, independent of presence profiles.

export type DocumentActor = {
    id: string;
    name?: string;
    color?: string;
};
  • id: Stable author identifier (used by awareness and, later, native attribution).

DocumentAttribution

The document-level attribution surface. actors/actorOf/block read replicated doc state directly — they resolve remote-applied records identically and stay correct as old replicas append records.

export type DocumentAttribution = {
    readonly actors: ReadonlyMap<string, ActorProfile>;
    actorOf(client: number): string | undefined;
    setProfile(profile: ActorProfile): void;
    block(blockId: string): BlockAttribution | undefined;
};
  • actors: actorId → profile — the replicated actor dictionary (u/ records).
  • actorOf: Resolve an item’s inserting replica (clientID) to an actor id (c/ records).
  • setProfile: Re-publish the local actor’s profile record (u/<actorId> — LWW).
  • block: Compact per-block attribution for blockId ({createdBy, contributors, lastChangedBy} — durable actor ids, never replica clientIDs), or undefined for system/foreign blocks that carry no record.

DocumentDestroyedError

Raised when an operation runs against a torn-down document — every attach reference has been released and the facade/history/awareness teardown already ran. Distinct from DocumentNotReadyError: destroyed is terminal, pending may still resolve.

export declare class DocumentDestroyedError extends Error {
    constructor(service?: string);
}

DocumentNotReadyError

Raised when a readiness-gated service is used on a pending document.

export declare class DocumentNotReadyError extends Error {
    constructor(service: string);
}

DocumentOperations

The document’s public operations: the writes, each also prepared (prepare.<op>(…), pure, then apply(plan); compose joins plans), the reads, transact, onChange and version. See the document API reference.

export interface DocumentOperations extends DocumentWrites, DocumentReads {
    readonly prepare: {
        readonly [K in keyof DocumentWrites]: (...args: Parameters<DocumentWrites[K]>) => Prepared;
    };
    apply(plan: Prepared): OpResult;
    compose(...parts: Prepared[]): Prepared;
    transact<R>(fn: () => R, origin?: unknown): R;
    onChange(listener: (change: DocChange) => void): () => void;
    readonly version: number;
}
  • prepare: Every write, prepared: a plan of named steps and its effect, or refused.
  • apply: Write a prepared plan exactly (a refusal passes through).
  • compose: One plan of parts, applied in order.
  • transact: Group writes in one transaction and one change event (no rollback on a throw).
  • onChange: Hear each transaction’s change; answers the unsubscribe.
  • version: Changes on every write that changed the tree.

DocumentOptions

export type DocumentOptions = {
    actor?: DocumentActor;
    semantics?: DocumentSemanticsConfig;
    awareness?: Awareness;
    history?: {
        captureTimeout?: number;
        limit?: number;
    };
    requireHydration?: boolean;
};
  • actor: Local actor — anonymous opaque id when absent.
  • semantics: Up-front semantic configuration (views may also seed via adoptSemantics).
  • awareness: Borrow an existing awareness instance instead of creating one — destroy() will NOT destroy it (same owned/borrowed rule as the doc).
  • history: History tuning — applied when the document’s undo manager attaches.
  • requireHydration: Decide an EMPTY document only from a provider that synced: the room answered, or a local store hydrated.

DocumentReadiness

How the document’s content state was decided — the distinction the readiness contract requires:

  • pending — undecided (created without a value or attached before sync(); a provider may still hydrate — nothing bootstrapped, nothing broadcast). Reads/attaches/sync() legal, history refuses;
  • local — seeded locally (createDocument({value}), or sync() on a still-fresh doc — seed-if-empty bootstrap included). Full surface legal;
  • hydrated — the doc was already initialized when sync() ran: provider-applied remote state or a loadDocument restore (schema asserted, content untouched). Full surface legal.

sync() is the only transition out of pending, and it is the document-side admission re-check: a doc that arrived in a problem state (unversioned/unsupported/foreign — e.g. via raw applyUpdate bypass writes) refuses there with a typed error, stays pending, and preserves the state — never silently becoming local.

export type DocumentReadiness = 'pending' | 'local' | 'hydrated';

DocumentReads

The document’s reads (transaction-aware where the reference says so).

export interface DocumentReads {
    toJSON(): JSONDoc;
    docData(): JsonObj;
    dataItemIds(target: DataTarget, path: readonly string[]): string[];
    project(): ProjectedDoc;
    blockJSON(id: BlockId): JSONBlock;
    childrenIds(parent: BlockId | null): BlockId[];
    parentOf(id: BlockId): BlockId | null;
    ancestorsOf(id: BlockId): BlockId[];
    positionOf(id: BlockId): Destination | null;
    pathOf(id: BlockId): number[] | null;
    blockTypeOf(id: BlockId): string | undefined;
    blockDataOf(id: BlockId): Record<string, unknown> | undefined;
    blockText(id: BlockId): string | null;
    contentItems(id: BlockId): ContentItem[];
    displayLength(id: BlockId): number;
    runs(id: BlockId): readonly ContentRun[];
    hasBlock(id: BlockId): boolean;
    isVisibleBlock(id: BlockId): boolean;
    listBlockIds(): BlockId[];
    blockAttribution(id: BlockId): BlockAttribution | undefined;
    isVoid(id: BlockId): boolean;
    isIsland(id: BlockId): boolean;
    isLines(id: BlockId): boolean;
    islandOf(id: BlockId): BlockId | null;
    insideIsland(id: BlockId): boolean;
    isLayout(id: BlockId): boolean;
    isLayoutItem(id: BlockId): boolean;
    besideAt(id: BlockId, kind?: string): BlockId;
    isTable(id: BlockId): boolean;
    isTableRow(id: BlockId): boolean;
    isTableCell(id: BlockId): boolean;
    tableOf(id: BlockId): BlockId | null;
    tableColumns(id: BlockId): {
        id: string;
        width?: number;
    }[] | null;
    tableGrid(id: BlockId): {
        columns: string[];
        rows: {
            id: BlockId;
            cells: (BlockId | null)[];
        }[];
    } | null;
    order(): readonly BlockId[];
    compare(a: BlockId, b: BlockId): number;
    next(id: BlockId, policy?: OrderPolicy): BlockId | null;
    previous(id: BlockId, policy?: OrderPolicy): BlockId | null;
    canPlace(ids: readonly BlockId[], parent?: BlockId | null): boolean;
    canMerge(from: BlockId, into: BlockId): boolean;
    fits(parent: BlockId | null, kind: string): boolean;
    nestParent(ids: readonly BlockId[], parent: BlockId): BlockId;
    landingOf(id: BlockId, kind: string, after?: boolean): {
        parent: BlockId | null;
        levels: BlockId[];
    };
    anchorAt(id: BlockId, offset: number, affinity?: AnchorAffinity): DocAnchor | null;
    resolveAnchor(anchor: DocAnchor): {
        blockId: BlockId;
        offset: number;
    } | null;
}

DocumentSemanticsConfig

Document-level semantic configuration — the structural subset of what plugin BlockDefinitions carry (roles, rendersContent, defaultChild) plus the default block type. Snippets/DOM hooks are deliberately NOT part of this: they are view-side rendering policy.

export type DocumentSemanticsConfig = {
    roles?: Record<string, BlockRole>;
    rendersContent?: Record<string, boolean>;
    defaultChild?: Record<string, string>;
    defaultType?: string;
    marks?: Record<string, {
        edge?: MarkEdge;
    }>;
};
  • roles: Structural role per block type ({void?, island?, lines?, layout?} — absent flags mean false).
  • rendersContent: Whether a kind renders its own content slot (undeclared kinds do).
  • defaultChild: Default child type per parent type (undeclared parents take defaultType).
  • defaultType: Default block type — the root’s default child and the bootstrap block.
  • marks: Per mark, its edge (its record’s edge) — where a concurrent insert at each end of a mark lands.

DocumentWrites

The document’s writes: each one transaction, answering what it did (OpResult).

export interface DocumentWrites {
    insertBlocks(dest: Destination, specs: readonly (JSONBlock | BlockSpec)[]): OpResult;
    moveBlocks(ids: readonly BlockId[], dest: Destination): OpResult;
    nestBlock(id: BlockId, parent: BlockId): OpResult;
    unNestBlock(id: BlockId): OpResult;
    unNestBlocks(ids: readonly BlockId[]): OpResult;
    liftOut(id: BlockId, kind: string, options?: {
        keep?: boolean;
        after?: readonly BlockSpec[];
    }): OpResult;
    wrapInLayout(ids: readonly BlockId[], kind?: string, columns?: number): OpResult;
    placeBeside(ids: readonly BlockId[], target: BlockId, side: 'left' | 'right', kind?: string): OpResult;
    splitBlock(id: BlockId, offset: number, newId: BlockId, tail?: SplitTail): OpResult;
    mergeBlocks(fromId: BlockId, intoId: BlockId): OpResult;
    mergeBackward(id: BlockId): OpResult;
    mergeForward(id: BlockId): OpResult;
    deleteBlock(id: BlockId, options?: {
        keepChildren?: boolean;
    }): OpResult;
    deleteBlocks(ids: readonly BlockId[]): OpResult;
    setBlock(id: BlockId, value: {
        type?: string;
        data?: Record<string, unknown>;
        content?: (ContentItem | JSONText | JSONInlineBlock)[];
        children?: (BlockSpec | JSONBlock)[];
    }): OpResult;
    setBlockType(id: BlockId, type: string): OpResult;
    patchData(target: DataTarget, patches: readonly DataPatch[]): OpResult;
    duplicateBlock(id: BlockId, freshId?: (oldId: string, kind: 'block' | 'inline') => string): OpResult;
    insertText(id: BlockId, offset: number, text: string, marks?: Record<string, unknown>): OpResult;
    deleteText(id: BlockId, offset: number, length: number): OpResult;
    formatRange(id: BlockId, offset: number, length: number, marks: Record<string, unknown>): OpResult;
    clearMarks(id: BlockId, offset: number, length: number): OpResult;
    insertInline(id: BlockId, offset: number, atom: NewInline): OpResult;
    removeInline(id: BlockId, inlineId: string): OpResult;
    deleteRange(from: DocPosition, to: DocPosition, view?: RangeView): OpResult;
    replaceRange(from: DocPosition, to: DocPosition, view?: RangeView): OpResult;
    insertFlow(target: FlowTarget, flow: Flow, view?: FlowView): OpResult;
}
  • duplicateBlock: freshId names each copy (fresh ids by default).
  • insertInline: An atom without an id gets a fresh one.

EdytorDoc

export type EdytorDoc = ReturnType<EdytorDocBinding['create']>;

EdytorDocDisposedError

Raised when a mutating facade op runs after dispose() — disposal is terminal for writes (reads stay dead-safe: a stale handle may still be inspected while its document outlives the facade). The facade-level counterpart of DocumentDestroyedError — kept in this module because a bare bindEdytorDoc facade has no document layer above it.

export declare class EdytorDocDisposedError extends Error {
    constructor(service?: string);
}

EdytorDocument

The document’s operations and reads are its own members (document.insertBlocks(…), document.toJSON()): see DocumentOperations. transact is the document’s (its local origin by default).

export interface EdytorDocument extends Omit<DocumentOperations, 'transact'> {
}
export declare class EdytorDocument {
    #private;
    readonly doc: YDoc;
    readonly awareness: Awareness;
    readonly actor: DocumentActor;
    get attribution(): DocumentAttribution;
    readonly transaction: TRANSACTION;
    private _destroyed;
    readonly requireHydration: boolean;
    get clientID(): number;
    get ready(): boolean;
    get readiness(): DocumentReadiness;
    get destroyed(): boolean;
    get writable(): boolean;
    onWritableChange: (listener: (writable: boolean) => void) => (() => void);
    get historyLimit(): number;
    get semantics(): {
        defaultType: string;
        roles: Map<string, BlockRole>;
        rendersContent: Map<string, boolean>;
        defaultChild: Map<string, string>;
        marks: Map<string, MarkEdge>;
    };
    defaultChild: (parentType: string | null) => string;
    rendersContent: (type: string) => boolean;
    adoptSemantics: (config: DocumentSemanticsConfig) => void;
    sync: (value?: JSONDoc) => void;
    get history(): YUndoManager;
    trackOrigin: (origin: unknown) => void;
    untrackOrigin: (origin: unknown) => void;
    clearHistory: () => void;
    transact: <T>(cb: () => T, origin?: unknown) => T;
    onReady: (listener: () => void) => (() => void);
    get syncPending(): boolean;
    get syncRefusal(): SyncRefusedError | undefined;
    onSyncRefused: (listener: (refusal: SyncRefusedError) => void) => (() => void);
    private _decide;
    attachSync: (sync: EdytorSync, opts?: {
        value?: JSONDoc;
    }) => EdytorSyncCleanup | void;
    encode: () => Uint8Array;
    retain: () => (() => void);
    destroy: () => void;
}
  • doc: The underlying engine doc — raw reads/providers borrow it; they never own it.
  • awareness: One shared awareness instance for every view/provider of this document.
  • actor: The local actor identity (anonymous opaque id when none was supplied).
  • attribution: The attribution surface — compact per-block records and the replicated actor dictionary (u/ profiles, c/ replica bindings).
  • transaction: The document’s own local-edit transaction origin — headless edits via transact carry it so history capture attributes them.
  • requireHydration: DocumentOptions.requireHydration: an empty document waits for a provider’s synced.
  • clientID: The replica id (doc.clientID) — identifies the replica, not the actor.
  • ready: true once the document’s content state is decided — seeded locally or hydrated then synced.
  • readiness: pending | local | hydrated — distinguishes a locally-seeded ready from a provider-hydrated/restored ready (the contract consumers need to tell “I decided this content” from “sync brought it”).
  • writable: false while the document carries a schema stamp this build cannot own (a foreign stamp got in despite the transport’s inbound refusal): every write refuses with a SchemaMismatchError, and the providers neither persist nor broadcast it.
  • onWritableChange: Subscribe to writable transitions — the visible signal that the document turned read-only (once per transition, not per refused edit).
  • historyLimit: The undo steps this document’s history keeps: the configured history.limit, else DEFAULT_HISTORY_LIMIT.
  • semantics: The document-level semantic configuration (snapshot).
  • defaultChild: The default child type under a parent of parentType (null = the root) — the one answer split, paragraph insert, merge-unnest, clear and root normalization apply against the new block’s actual parent.
  • rendersContent: Whether kind type renders its own content slot (undeclared kinds do).
  • adoptSemantics: Contribute document-level semantics — the seam views use to seed the structural roles implied by their plugin block definitions.
  • sync: The readiness transition — decide the document’s content state.
  • history: The default local history (the registry-scoped undo manager — undo/redo/stopCapturing/stacks).
  • trackOrigin: Track a local-edit transaction origin for history capture — the seam views use to enroll their own TRANSACTION instance in this document’s history.
  • untrackOrigin: Release a previously-tracked origin — the view-teardown counterpart of trackOrigin.
  • clearHistory: Drop the undo/redo stacks.
  • transact: Local document transaction — headless edits, one undo step per call (origin: another origin, which the document’s history tracks only when it is tracked).
  • onReady: Subscribe to the readiness transition — fires once, synchronously, inside sync when _readiness leaves 'pending' (every decision path goes through sync(): provider synced, local seed, explicit call).
  • syncPending: Whether an attached provider has neither settled nor reached its bound.
  • syncRefusal: The server’s refusal of a provider (a 1008/4xxx close — see SyncRefusedError), the latest still standing: that provider stopped.
  • onSyncRefused: Subscribe to provider refusals (syncRefusal).
  • attachSync: Attach a provider sync factory to this document (headless EdytorSync path — the same contract views use).
  • encode: Full replicated state as a v14 update — loadDocument restores it on a fresh replica.
  • retain: Acquire one more attach reference and return its ONE-SHOT release capability.
  • destroy: Release ONE attach reference.

EdytorSync

export type EdytorSync = ((payload: EdytorSyncPayload) => void | EdytorSyncCleanup) & {
    bound?: number;
    target?: string;
};

EdytorSyncCleanup

export type EdytorSyncCleanup = () => void | Promise<void>;

EdytorSyncPayload

Payload a sync factory receives — the v13 contract plus failed: the terminal half of the sync lifecycle. A provider that can never reach synced (destroyed before syncing, persistence load failure, refused hydration, denied auth) reports it here exactly once; a transient disconnect or a provider that already synced never does. A SyncRefusedError is the exception: the server refused this client for good, reported synced or not, and an empty document does not seed over it.

export type EdytorSyncPayload = {
    doc: YDoc;
    awareness: Awareness;
    synced: (provider?: unknown) => void;
    failed?: (error: unknown, provider: unknown) => void;
    armBound?: () => void;
    holdBound?: () => void;
    attach?: (sync: EdytorSync) => EdytorSyncCleanup | void;
};
  • armBound: (Re)start this provider’s readiness bound (DEFAULT_READINESS_BOUND ms from now) — for a factory whose bound is Infinity because only its transport knows when waiting starts to count (the websocket sync: from the socket’s open, or its first failed dial).
  • holdBound: Stop this provider’s readiness bound: an empty document waits for it to settle (or for the next armBound()), as the websocket sync does after expired credentials on a first visit.
  • attach: Attach another sync to the same document as its own provider (its own target, bound and settle): how a sync brings a companion, e.g.

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>>;
}

equationKinds

The equation plugin’s structural row: a block equation is a void that draws its TeX (data.expression) and shows no text of its own. Its inline equation is an atom, which needs no role.

declare const equationKinds: {
    equation: {
        void: true;
        rendersContent: false;
    };
};

equationSemantics

The equation plugin’s block role.

declare const equationSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

facadeConfigOf

The facade configuration (EdytorDocConfig) a document with no view reads semantics with — the room’s: roles, default children, content-less kinds and mark edges, each answered only for a kind the tables name.

declare const facadeConfigOf: (semantics: DocumentSemanticsConfig) => {
    roleOf: (type: string) => BlockRole | undefined;
    kinds: () => string[];
    defaultChildOf: (type: string) => string | undefined;
    rendersContent: (type: string) => boolean;
    markEdge: (mark: string) => MarkEdge | undefined;
    defaultType: string | undefined;
};

FlowView

What the view tells flow placement beyond range deletion’s view: a container’s flat item kind (numbered-list-item for an ordered-list).

export type FlowView = RangeView & {
    itemKind?: (parent: BlockId) => string | undefined;
    header?: (id: BlockId) => boolean | 'closed';
};

imageKinds

createImagePlugin()’s structural rows: void, its only text is the caption.

declare const imageKinds: {
    image: {
        void: true;
    };
};

imageSemantics

createImagePlugin()’s block roles.

declare const imageSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

IndexeddbSyncOptions

export type IndexeddbSyncOptions = {
    awareness?: Awareness;
};

InlineSpec

export type InlineSpec = {
    id: string;
    type: string;
    data?: Record<string, unknown>;
};

JSONBlock

export type JSONBlock = {
    type: string;
    id?: string;
    data?: Record<string, SerializableContent>;
    children?: JSONBlock[];
    content?: (JSONText | JSONInlineBlock)[];
};

JSONDoc

export type JSONDoc = {
    data?: Record<string, SerializableContent>;
    children: JSONBlock[];
} & Partial<Record<string, unknown>>;

JSONInlineBlock

export type JSONInlineBlock = {
    id?: string;
    data?: any;
    type: string;
};

JSONText

export type JSONText = {
    text: string;
    marks?: Record<string, SerializableContent>;
};

KindRecord

A kind record as a plugin declares it (plugin.blocks[type]): its structural row with whatever else it holds (a snippet, an element, presets), or a bare snippet, a plain kind.

export type KindRecord = KindSemantics | ((...args: never[]) => unknown);

KindSemantics

One kind’s structural row — the fields of its BlockDefinition a document adopts.

export type KindSemantics = BlockRole & {
    rendersContent?: boolean;
    defaultChild?: string;
};

LastUpdatedOptions

What lastUpdated takes: the room it asks, and the params (a token) its dial would carry.

export type LastUpdatedOptions = WebsocketTarget & {
    params?: Record<string, string>;
    fetch?: typeof fetch;
};

layoutKinds

The columns plugin’s structural rows: columns is a layout of columns (layout.* in the delete contract), a column a container that holds any block. In defaultSemantics: a document holding no columns block is unchanged by them, and every replica of one that does (a view with the plugin, a headless document, the room) reads the same layout rules.

declare const layoutKinds: {
    columns: {
        layout: true;
        rendersContent: false;
        defaultChild: string;
    };
    column: {
        rendersContent: false;
    };
};

layoutSemantics

The columns plugin’s block roles (a layout of columns).

declare const layoutSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

loadDocument

See DocumentBinding.loadDocument.

declare const loadDocument: (update: Uint8Array, options?: LoadDocumentOptions) => EdytorDocument;

LoadDocumentOptions

export type LoadDocumentOptions = DocumentOptions;

MarkEdge

Whether a mark grows at its edges — always, never, or at its start only.

export type MarkEdge = 'inclusive' | 'exclusive' | 'side-dependent';

markName

The record a mark key names: comment:c1 → comment (a key of its own otherwise).

declare const markName: (key: string) => string;

mediaKinds

The media plugins’ structural rows (createEmbedPlugin(), createBookmarkPlugin(), createFilePlugin(), createVideoPlugin(), createAudioPlugin()): void like the image, their only text is the caption.

declare const mediaKinds: {
    embed: {
        void: true;
    };
    bookmark: {
        void: true;
    };
    file: {
        void: true;
    };
    video: {
        void: true;
    };
    audio: {
        void: true;
    };
};

mediaSemantics

The media plugins’ block roles (embed, bookmark, file, video, audio).

declare const mediaSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

MergedSemantics

The merged config’s fields, each present (empty when no config named one).

export type MergedSemantics = {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
    marks: Record<string, {
        edge?: MarkEdge;
    }>;
    defaultType?: string;
};

mergeSemantics

Several configs as one, deeply frozen, merged field by field (roles, rendersContent, defaultChild, marks, defaultType): the room’s or a headless document’s roles for an app’s own kinds beside the bundled ones, mergeSemantics(defaultSemantics, semanticsOf(myKinds)). A top-level spread of two configs would keep only the last one’s fields. A kind (or mark, or the default type) two configs declare otherwise throws SemanticConflictError, as a view’s conflicting plugin does on a document; an equal declaration merges.

declare const mergeSemantics: (...configs: DocumentSemanticsConfig[]) => MergedSemantics;

MetaClientState

export type MetaClientState = {
    clock: number;
    lastUpdated: number;
};
  • lastUpdated: unix timestamp

OpResult

The observed outcome of one document operation — the one result shape every op returns, empty inputs included. refused: the op did not apply and wrote nothing; noop: it applied and changed nothing; applied: the transaction wrote. Read from the transaction’s effects, never predicted.

export type OpResult = {
    readonly status: 'refused' | 'noop' | 'applied';
    readonly ids: readonly BlockId[];
    readonly reason?: string;
};
  • ids: What the op is about — created, moved, merge target, or its target; empty unless applied.
  • reason: Why a refused op refused, when it names a reason ('id-collision').

OrderPolicy

Island-sealing policy for a walk in document order (see next).

export type OrderPolicy = {
    sealed?: boolean;
};

pageKinds

The page plugin’s structural row: a link to another document (a subpage), void and showing no text of its own, as a divider.

declare const pageKinds: {
    page: {
        void: true;
        rendersContent: false;
    };
};

pageSemantics

The page plugin’s block role (a link to another document).

declare const pageSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

Plan

A prepared operation: its steps, their effect, the ids the op is about, and the document version it was prepared against — valid only there, applied in the same synchronous turn.

export type Plan = {
    readonly ids: readonly BlockId[];
    readonly writes: readonly PlanStep[];
    readonly effect: PlanEffect;
    readonly version: number;
    readonly at?: DocPosition;
};
  • at: Where the op leaves the caret, when it decides one (deleteRange).

PrefetchOptions

What bindProviders’ prefetch takes: a websocket sync’s target and options.

export type PrefetchOptions = (WebsocketSyncOptions extends infer O ? O extends unknown ? Omit<O, 'onExpired' | 'persist' | 'disableBc'> : never : never) & {
    timeout?: number;
};

PrefetchResult

What prefetch found: whether the room sent the store anything it lacked.

export type PrefetchResult = {
    updated: boolean;
};

Prepared

prepare’s answer: a plan, or the op’s refusal.

export type Prepared = Plan | OpResult;

ProjectedBlock

Canonical projected block — the comparison surface for convergence.

export type ProjectedBlock = {
    id: BlockId;
    type: string;
    data?: Record<string, unknown>;
    content: ContentItem[];
    children: ProjectedBlock[];
    malformed?: true;
};
  • malformed: Set when the registry node could not be read completely.

ProjectedDoc

export type ProjectedDoc = {
    children: ProjectedBlock[];
};

ProviderStack

export type ProviderStack = ReturnType<typeof bindProviders>;

RangeView

What the view knows of a range (view state the document does not hold): whether it hides a block, and, given removed, whether the block stays hidden once those go (a removed closed toggle’s children take its place, shown).

export type RangeView = {
    hidden?: (id: BlockId, removed?: ReadonlySet<BlockId>) => boolean;
};

richTextKinds

createRichTextPlugin()’s structural rows (its other kinds are plain).

declare const richTextKinds: {
    divider: {
        void: true;
        rendersContent: false;
    };
    'ordered-list': {
        rendersContent: false;
        defaultChild: string;
    };
    'unordered-list': {
        rendersContent: false;
        defaultChild: string;
    };
};

richTextMarks

createRichTextPlugin()’s mark edges: where a concurrent insert at each end of a mark lands. A link grows at its start only (typing after it stays out of it unless from inside the anchor); the others are inclusive.

declare const richTextMarks: {
    link: {
        edge: "side-dependent";
    };
};

richTextSemantics

createRichTextPlugin()’s block roles and mark edges, for createDocument({ semantics }) and the room.

declare const richTextSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
} & {
    marks: Record<string, {
        edge: MarkEdge;
    }>;
};

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);
}

SemanticConflictError

Raised when two declarations of one kind’s structural facts disagree — a view’s plugin and the document (adoptSemantics), or two configs mergeSemantics is given: no replica may silently read another rule than its peers.

export declare class SemanticConflictError extends Error {
    readonly subject: string;
    readonly existing: unknown;
    readonly incoming: unknown;
    constructor(subject: string, existing: unknown, incoming: unknown);
}
  • subject: What conflicted (e.g.

semanticsDigest

A config’s facts as one short hash per kind, per mark (mark:<name>) and for the default type (@defaultType): what a document advertises in its presence in development builds, so the room can name the kinds it reads otherwise than a client (semanticsMismatch). A plain kind (no role, content, no default child) hashes as an undeclared one.

declare const semanticsDigest: (config: DocumentSemanticsConfig) => Record<string, string>;

semanticsMismatch

The keys of a client’s advertised digest that ours (the room’s semanticsDigest) hashes otherwise: kinds, marks or the default type the two read differently. A kind the client does not name is not its mismatch (a view without that plugin); a kind only the client names counts when it has facts. Anything but a digest compares nothing.

declare const semanticsMismatch: (ours: Record<string, string>, theirs: unknown) => string[];

semanticsOf

Kind tables (type → row) as one DocumentSemanticsConfig, deeply frozen: semanticsOf({ embed: { void: true, rendersContent: false } }). A row may be a plugin’s kind record (plugin.blocks): only its structural fields are read (void, island, lines, layout, table, atomic, rendersContent, defaultChild), and a bare snippet is a plain kind. To add kinds to a bundled config, use mergeSemantics.

declare const semanticsOf: (...tables: Record<string, KindRecord>[]) => {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

SerializableContent

export type SerializableContent = {
    [key: string]: SerializableContent;
} | SerializableContent[] | string | boolean | number | null;

SyncRefusedError

A terminal refusal: the server closed the socket with a policy code (isRefusal), so the next dial would be refused the same way (a stale generation, another user’s replica, a foreign stamp). The provider stops dialing and the document does not seed.

export declare class SyncRefusedError extends Error {
    code: number;
    reason: string;
    constructor(code: number, reason?: string);
}
  • code: The close code.
  • reason: The close reason the server gave, e.g.

tableBlock

A table block in the document JSON: rows × columns cells, the table’s columns and each cell’s column set. It names no block id, so a value holding it seeds the same table every time.

createDocument({
	value: { children: [tableBlock({ cells: [['Name', 'Role'], ['Ada', 'Eng']], headerRow: true })] }
});
declare const tableBlock: (options?: TableBlockOptions) => JSONBlock;

TableBlockOptions

What tableBlock builds.

export type TableBlockOptions = {
    rows?: number;
    columns?: number;
    cells?: readonly (readonly (string | readonly JSONText[])[])[];
    headerRow?: boolean;
    headerColumn?: boolean;
    widths?: readonly (number | undefined)[];
};
  • rows: Rows (default: the rows of cells, else 2).
  • columns: Columns (default: the widest row of cells, else 2).
  • cells: Each cell’s text, by row then column (a string, or rich text).
  • headerRow: The first row is a header row.
  • headerColumn: The first column is a header column.
  • widths: Column widths in pixels, by position (absent: the default width).

tableKinds

The table plugin’s structural rows: table displays only its tableRows, a row only its tableCells, in the order of the table’s data.columns (table.* in the delete contract); a cell is a text island (its text holds its lines, as soft breaks). In defaultSemantics, so every replica of a document holding a table reads the same rules.

declare const tableKinds: {
    table: {
        table: true;
        rendersContent: false;
        defaultChild: string;
    };
    tableRow: {
        rendersContent: false;
        defaultChild: string;
    };
    tableCell: {
        island: true;
    };
};

tableSemantics

The table plugin’s block roles (a table of rows of cells).

declare const tableSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

toBlockSpec

A canonical JSONBlock (from facade.toJSON()/blockJSON, a template, an import) as the BlockSpec facade.insertBlocks takes: ids are kept, and minted where missing; freshIds mints every id (a duplicate).

declare const toBlockSpec: (block: JSONBlock, { freshIds }?: {
    freshIds?: boolean | undefined;
}) => BlockSpec;

tocKinds

The table of contents plugin’s structural row: a void that lists the document’s headings, showing no text of its own.

declare const tocKinds: {
    toc: {
        void: true;
        rendersContent: false;
    };
};

tocSemantics

The table of contents plugin’s block role.

declare const tocSemantics: {
    roles: Record<string, BlockRole>;
    rendersContent: Record<string, boolean>;
    defaultChild: Record<string, string>;
};

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');
}

WebsocketSync

A websocket sync; persistName names its local store (for clearDocument), unset without one.

export type WebsocketSync = EdytorSync & {
    persistName?: string;
};

WebsocketSyncOptions

export type WebsocketSyncOptions = WebsocketTarget & {
    params?: Record<string, string>;
    WebSocketPolyfill?: import('./websocket.js').WebsocketPolyfill;
    maxBackoffTime?: number;
    connectTimeout?: number;
    onExpired?: (state: Parameters<WebsocketProviderEvents['expired']>[0]) => void;
    disableBc?: boolean;
    maxFrameBytes?: number;
    persist?: boolean;
    persistName?: string;
};

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?