edytor/protocol
Every name edytor/protocol exports, with its declaration and documentation (generated from the published types).
Every name edytor/protocol exports, generated from the package’s published type declarations, with the documentation its JSDoc carries. The guides explain how the pieces fit; this page is the exhaustive list. 91 names.
AdmissionResult
Non-throwing admission result — the audit/read-side counterpart of
assertAdmission.
export type AdmissionResult = {
admitted: true;
verdict: AdmissionVerdict;
} | {
admitted: false;
error: UnsupportedDocError | SchemaMismatchError;
};
AdmissionVerdict
What an admitted doc carries — the sync() readiness decision:
'fresh'— no schema claim and an empty block registry; seeding (facade.init) is legal. Foreign/unrelated ROOTS may still exist — they are not schema claims and coexist next to the seeded schema.'initialized'— supported schema content is committed; the doc is adopted as-is (hydrated), never seeded.
export type AdmissionVerdict = 'fresh' | 'initialized';
applyAwarenessUpdate
Apply an encoded awareness update. origin is forwarded on the emitted
change/update events.
declare const applyAwarenessUpdate: (awareness: Awareness, update: Uint8Array, origin: unknown) => void;
assertAdmission
The document-level admission gate — runs the ordered checks and throws the typed refusal:
UnsupportedDocError'foreign'— not a v14 engine doc (foreign roots/engines may still attach content later; this is about doc shape);SchemaMismatchError'unversioned' | 'unsupported' | 'foreign'— a schema claim this build cannot own.
PURE READS — a refusal leaves the doc byte-identical (the reads may
materialize empty root SHARE entries in the doc’s share map, which do
not encode into updates). Returns the AdmissionVerdict for the
readiness decision.
declare const assertAdmission: (doc: EngineDoc, docName?: string) => AdmissionVerdict;
assertSchema
Hard gate — throws SchemaMismatchError when checkSchema reports a
problem. Used by migration and by Edytor.sync() before
mutating a synced document.
declare const assertSchema: (doc: EngineDoc, docName?: string) => void;
assertUsableDoc
Document-boundary guard run by EdytorDocBinding.create before the
runs view attaches. The facade only speaks the v14 unified-node surface —
without this gate a foreign doc dies obscurely inside buildView
(registry.forEachAttr is not a function); it fails fast with an
actionable error instead.
declare const assertUsableDoc: (doc: EngineDoc) => void;
AwarenessEntry
One awareness entry on the wire: a client’s clock and state (null = removed).
export type AwarenessEntry = {
clientID: number;
clock: number;
state: Record<string, unknown> | null;
};
bindCrdt
declare const bindCrdt: (Y: EngineApi) => {
createDoc: (opts?: ConstructorParameters<EngineApi["Doc"]>[0]) => YDoc;
Awareness: typeof _Awareness;
doc: {
SCHEMA: {
readonly version: 6;
readonly name: "edytor-doc";
readonly roots: {
readonly registry: "blocks";
readonly meta: "meta";
};
readonly metaAttrs: {
readonly version: "v";
readonly schema: "schema";
};
};
SCHEMA_VERSION: 6;
SCHEMA_NAME: "edytor-doc";
META_KEY: "meta";
init: (doc: import("./engine-api.js").EngineDoc, opts?: {
content?: import("./index.js").BlockSpec[];
defaultType?: string;
}) => void;
restore: (doc: import("./engine-api.js").EngineDoc, content: import("./index.js").BlockSpec[]) => void;
seed: (doc: import("./engine-api.js").EngineDoc, value?: import("./index.js").JSONBlock[], defaultType?: string, data?: import("./doc/types.js").JsonObj) => void;
isInitialized: (doc: import("./engine-api.js").EngineDoc) => boolean;
schemaVersion: (doc: import("./engine-api.js").EngineDoc) => number | undefined;
registryEmpty: (doc: import("./engine-api.js").EngineDoc) => boolean;
checkSchema: (doc: import("./engine-api.js").EngineDoc) => import("./edytor-doc.js").SchemaProblem | null;
assertSchema: (doc: import("./engine-api.js").EngineDoc, docName?: string) => void;
SchemaMismatchError: typeof import("./edytor-doc.js").SchemaMismatchError;
create: (doc: import("./engine-api.js").EngineDoc, config?: import("./edytor-doc.js").EdytorDocConfig) => {
prepare: {
insertFlow: (target: import("./flow.js").FlowTarget, flow: import("./flow.js").Flow, view?: import("./flow.js").FlowView) => import("./edytor-doc.js").Prepared;
deleteRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView) => import("./edytor-doc.js").Prepared;
replaceRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView) => import("./edytor-doc.js").Prepared;
insertBlocks: (dest: import("./index.js").Destination, specs: readonly (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[]) => import("./edytor-doc.js").Prepared;
moveBlocks: (ids: readonly import("./index.js").BlockId[], dest: import("./index.js").Destination) => import("./edytor-doc.js").Prepared;
nestBlock: (id: import("./index.js").BlockId, parent: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
unNestBlock: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
unNestBlocks: (ids: readonly import("./index.js").BlockId[]) => import("./edytor-doc.js").Prepared;
liftOut: (id: import("./index.js").BlockId, kind: string, { keep, after }?: {
keep?: boolean;
after?: readonly import("./index.js").BlockSpec[];
}) => import("./edytor-doc.js").Prepared;
placeBeside: (ids: readonly import("./index.js").BlockId[], target: import("./index.js").BlockId, side: "left" | "right", kind?: string) => import("./edytor-doc.js").Prepared;
wrapInLayout: (ids: readonly import("./index.js").BlockId[], kind?: string, columns?: number) => import("./edytor-doc.js").Prepared;
splitBlock: (id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail?: import("./placement/model.js").SplitTail) => import("./edytor-doc.js").Prepared;
mergeBlocks: (fromId: import("./index.js").BlockId, intoId: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
mergeBackward: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
mergeForward: (id: import("./index.js").BlockId) => import("./edytor-doc.js").Prepared;
deleteBlock: (id: import("./index.js").BlockId, opts?: {
keepChildren?: boolean;
}) => import("./edytor-doc.js").Prepared;
setBlock: (id: import("./index.js").BlockId, value: {
type?: string;
data?: Record<string, unknown>;
content?: (import("./index.js").ContentItem | import("./index.js").JSONText | import("./index.js").JSONInlineBlock)[];
children?: (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[];
}) => import("./edytor-doc.js").Prepared;
setBlockType: (id: import("./index.js").BlockId, type: string) => import("./edytor-doc.js").Prepared;
patchData: (target: import("./edytor-doc.js").DataTarget, patches: readonly import("./data.js").DataPatch[]) => import("./edytor-doc.js").Prepared;
duplicateBlock: (id: import("./index.js").BlockId, freshId?: (oldId: string, kind: "block" | "inline") => string) => import("./edytor-doc.js").Prepared;
insertText: (id: import("./index.js").BlockId, offset: number, text: string, marks?: Record<string, unknown>) => import("./edytor-doc.js").Prepared;
deleteText: (id: import("./index.js").BlockId, offset: number, length: number) => import("./edytor-doc.js").Prepared;
formatRange: (id: import("./index.js").BlockId, offset: number, length: number, marks: Record<string, unknown>) => import("./edytor-doc.js").Prepared;
clearMarks: (id: import("./index.js").BlockId, offset: number, length: number) => import("./edytor-doc.js").Prepared;
insertInline: (id: import("./index.js").BlockId, offset: number, atom: import("./doc/content.js").NewInline) => import("./edytor-doc.js").Prepared;
removeInline: (id: import("./index.js").BlockId, inlineId: string) => import("./edytor-doc.js").Prepared;
deleteBlocks: (ids: readonly import("./index.js").BlockId[]) => import("./edytor-doc.js").Prepared;
};
apply: (p: import("./edytor-doc.js").Prepared) => import("./edytor-doc.js").OpResult;
compose: (...parts: import("./edytor-doc.js").Prepared[]) => import("./edytor-doc.js").Prepared;
transact: <R>(fn: () => R, origin?: unknown) => R;
model: {
REGISTRY_KEY: string;
registryOf: (doc: import("./engine-api.js").EngineDoc) => import("./engine-api.js").EngineNode;
blockNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
liveNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
isLive: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => boolean;
candidatesOf: (node: import("./engine-api.js").EngineNode) => import("./placement/model.js").PlacementCand[];
view: (doc: import("./engine-api.js").EngineDoc) => import("./placement/model.js").ModelView;
resolvePlacements: (blocks: Map<import("./index.js").BlockId, import("./placement/model.js").BlockRec>, ownerOf?: (b: import("./index.js").BlockId) => import("./text/model.js").Owner) => Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>;
childrenIndex: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./placement/model.js").DisplayOwnership) => Map<import("./index.js").BlockId | null, import("./placement/model.js").ChildSlot[]>;
positionInView: (v: import("./placement/model.js").ModelView, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
buildInline: (atom: import("./index.js").InlineSpec) => import("./engine-api.js").EngineNode;
isSelfOrDescendant: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./text/model.js").Ownership, id: import("./index.js").BlockId, maybeAncestor: import("./index.js").BlockId) => boolean;
ranksAt: (siblings: readonly {
rank: string;
}[], index: number, count: number, clientId: number, rand?: () => number, run?: boolean) => string[];
writePlacement: (doc: import("./engine-api.js").EngineDoc, node: import("./engine-api.js").EngineNode, p: import("./index.js").BlockId | null, r: string) => void;
withdrawOnUndo: (doc: import("./engine-api.js").EngineDoc) => (item: import("./engine-api.js").EngineItemRef, stackItem: {
inserts: {
has(client: number, clock: number): boolean;
};
}) => boolean;
materializeSpec: (doc: import("./engine-api.js").EngineDoc, sp: import("./index.js").BlockSpec, parent: import("./index.js").BlockId | null, rank: string) => void;
collides: (doc: import("./engine-api.js").EngineDoc, specs: readonly import("./index.js").BlockSpec[]) => boolean;
writeSplit: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail: import("./placement/model.js").SplitTail, place: import("./placement/model.js").PlacementValue) => void;
ownText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => {
from: unknown;
to: number;
};
insertBlocks: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, specs: import("./index.js").BlockSpec[]) => boolean;
insertBlock: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, spec: import("./index.js").BlockSpec) => boolean;
restoreBlocks: (doc: import("./engine-api.js").EngineDoc, specs: import("./index.js").BlockSpec[]) => void;
project: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").ProjectedDoc;
positionOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
listBlockIds: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").BlockId[];
blockText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
crdtId: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
resolveBlock: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
};
text: {
newNode: (name: string) => import("./engine-api.js").EngineNode;
resolveAnchor: (doc: import("./engine-api.js").EngineDoc, text: import("./engine-api.js").EngineNode, anchor: import("./text/model.js").Anchor) => number | null;
anchorAt: (text: import("./engine-api.js").EngineNode, index: number, assoc: number) => import("./text/model.js").Anchor;
openRangeCursor: (text: import("./engine-api.js").EngineNode) => import("./text/model.js").RangeCursor;
itemsOfRange: (text: import("./engine-api.js").EngineNode, i0: number, i1: number) => import("./text/model.js").RangeItem[];
readSegs: (segs: readonly import("./text/model.js").Seg[], stats?: import("./text/model.js").RangeReadStats) => import("./text/model.js").RangeItem[];
computeOwnership: (doc: import("./engine-api.js").EngineDoc, given: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>) => import("./text/model.js").Ownership;
flatten: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").Seg[];
ownedLength: (segs: readonly import("./text/model.js").Seg[]) => number;
contentItemsOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").RangeItem[];
blockTextOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => string;
insertIntoText: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, payload: string | import("./engine-api.js").EngineNode, marks?: Record<string, unknown>) => void;
deleteRange: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number) => void;
formatRangeIn: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number, formats: Record<string, unknown>) => void;
purgeStreams: (streams: readonly import("./text/model.js").Stream[]) => void;
findAtom: (own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, inlineId: string) => {
text: import("./engine-api.js").EngineNode;
at: number;
node: import("./engine-api.js").EngineNode;
} | null;
splitAt: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, newId: import("./text/model.js").BlockId, n: number) => import("./text/model.js").MergeClaim[];
claimInto: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: Pick<import("./text/model.js").Ownership, "streamOf">, from: import("./text/model.js").BlockId, into: import("./text/model.js").BlockId) => void;
ownText: (doc: import("./engine-api.js").EngineDoc, rec: import("./text/model.js").TextBlockRec) => {
from: unknown;
to: number;
};
};
runsView: import("./text/runs.js").RunView;
version: number;
insertFlow: (target: import("./flow.js").FlowTarget, flow: import("./flow.js").Flow, view?: import("./flow.js").FlowView | undefined) => import("./edytor-doc.js").OpResult;
deleteRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView | undefined) => import("./edytor-doc.js").OpResult;
replaceRange: (from: import("./rangeDelete.js").DocPosition, to: import("./rangeDelete.js").DocPosition, view?: import("./rangeDelete.js").RangeView | undefined) => import("./edytor-doc.js").OpResult;
insertBlocks: (dest: import("./index.js").Destination, specs: readonly (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[]) => import("./edytor-doc.js").OpResult;
moveBlocks: (ids: readonly string[], dest: import("./index.js").Destination) => import("./edytor-doc.js").OpResult;
nestBlock: (id: string, parent: string) => import("./edytor-doc.js").OpResult;
unNestBlock: (id: string) => import("./edytor-doc.js").OpResult;
unNestBlocks: (ids: readonly string[]) => import("./edytor-doc.js").OpResult;
liftOut: (id: string, kind: string, args_2?: {
keep?: boolean;
after?: readonly import("./index.js").BlockSpec[];
} | undefined) => import("./edytor-doc.js").OpResult;
placeBeside: (ids: readonly string[], target: string, side: "right" | "left", kind?: string | undefined) => import("./edytor-doc.js").OpResult;
wrapInLayout: (ids: readonly string[], kind?: string | undefined, columns?: number | undefined) => import("./edytor-doc.js").OpResult;
splitBlock: (id: string, offset: number, newId: string, tail?: import("./placement/model.js").SplitTail | undefined) => import("./edytor-doc.js").OpResult;
mergeBlocks: (fromId: string, intoId: string) => import("./edytor-doc.js").OpResult;
mergeBackward: (id: string) => import("./edytor-doc.js").OpResult;
mergeForward: (id: string) => import("./edytor-doc.js").OpResult;
deleteBlock: (id: string, opts?: {
keepChildren?: boolean;
} | undefined) => import("./edytor-doc.js").OpResult;
setBlock: (id: string, value: {
type?: string;
data?: Record<string, unknown>;
content?: (import("./index.js").ContentItem | import("./index.js").JSONText | import("./index.js").JSONInlineBlock)[];
children?: (import("./index.js").BlockSpec | import("./index.js").JSONBlock)[];
}) => import("./edytor-doc.js").OpResult;
setBlockType: (id: string, type: string) => import("./edytor-doc.js").OpResult;
patchData: (target: import("./edytor-doc.js").DataTarget, patches: readonly import("./data.js").DataPatch[]) => import("./edytor-doc.js").OpResult;
duplicateBlock: (id: string, freshId?: ((oldId: string, kind: "block" | "inline") => string) | undefined) => import("./edytor-doc.js").OpResult;
insertText: (id: string, offset: number, text: string, marks?: Record<string, unknown> | undefined) => import("./edytor-doc.js").OpResult;
deleteText: (id: string, offset: number, length: number) => import("./edytor-doc.js").OpResult;
formatRange: (id: string, offset: number, length: number, marks: Record<string, unknown>) => import("./edytor-doc.js").OpResult;
clearMarks: (id: string, offset: number, length: number) => import("./edytor-doc.js").OpResult;
insertInline: (id: string, offset: number, atom: import("./doc/content.js").NewInline) => import("./edytor-doc.js").OpResult;
removeInline: (id: string, inlineId: string) => import("./edytor-doc.js").OpResult;
deleteBlocks: (ids: readonly string[]) => import("./edytor-doc.js").OpResult;
init: (opts?: Parameters<(doc: import("./engine-api.js").EngineDoc, opts?: {
content?: import("./index.js").BlockSpec[];
defaultType?: string;
}) => void>[1]) => void;
seed: (value: import("./index.js").JSONBlock[], data?: import("./doc/types.js").JsonObj) => void;
isInitialized: () => boolean;
schemaVersion: () => number | undefined;
checkSchema: () => import("./edytor-doc.js").SchemaProblem | null;
assertSchema: () => void;
dispose: () => void;
createUndoManager: (options?: import("./doc/history.js").HistoryOptions) => import("./doc/history.js").UndoManager;
project: () => import("./index.js").ProjectedDoc;
toJSON: () => import("./index.js").JSONDoc;
blockJSON: (id: string) => import("./index.js").JSONBlock;
childrenIds: (id: string | null) => string[];
childSlots: (parent: import("./index.js").BlockId | null) => import("./placement/model.js").ChildSlot[];
slotOf: (id: string) => {
parent: import("./index.js").BlockId | null;
rank: string;
} | null;
positionOf: (id: string) => import("./index.js").Destination | null;
pathOf: (id: string) => number[] | null;
parentOf: (id: string) => string | null;
ancestorsOf: (id: string) => string[];
listBlockIds: () => string[];
blockText: (id: string) => string | null;
blockTypeOf: (id: string) => string | undefined;
blockDataOf: (id: string) => Record<string, unknown> | undefined;
docData: () => import("./doc/types.js").JsonObj;
dataItemIds: (target: import("./edytor-doc.js").DataTarget, path: readonly string[]) => string[];
blockAttribution: (id: string) => import("./index.js").BlockAttribution | undefined;
crdtId: (id: string) => string | null;
resolveBlock: (id: string) => import("./engine-api.js").EngineNode | null;
displayLength: (id: string) => number;
contentItems: (id: string) => import("./index.js").ContentItem[];
hasBlock: (id: string) => boolean;
isVisibleBlock: (id: string) => boolean;
order: () => readonly import("./index.js").BlockId[];
compare: (a: import("./index.js").BlockId, b: import("./index.js").BlockId) => number;
next: (id: string, policy?: import("./edytor-doc.js").OrderPolicy | undefined) => string | null;
previous: (id: string, policy?: import("./edytor-doc.js").OrderPolicy | undefined) => string | null;
anchorAt: (id: string, offset: number, affinity?: import("./edytor-doc.js").AnchorAffinity | undefined) => import("./edytor-doc.js").DocAnchor | null;
resolveAnchor: (anchor: import("./edytor-doc.js").DocAnchor) => {
blockId: import("./index.js").BlockId;
offset: number;
} | null;
followUndo: (anchor: import("./edytor-doc.js").DocAnchor) => import("./edytor-doc.js").DocAnchor;
rolesChanged: () => void;
isVoid: (id: string) => boolean;
isIsland: (id: string) => boolean;
isLines: (id: string) => boolean;
isLayout: (id: string) => boolean;
isLayoutItem: (id: string) => boolean;
besideAt: (id: import("./index.js").BlockId, kind?: string) => string;
islandOf: (id: string) => string | null;
isTable: (id: string) => boolean;
isTableRow: (id: string) => boolean;
isTableCell: (id: string) => boolean;
tableOf: (id: string) => string | null;
tableColumns: (id: string) => {
id: string;
width?: number;
}[] | null;
tableGrid: (id: string) => {
columns: string[];
rows: {
id: import("./index.js").BlockId;
cells: (import("./index.js").BlockId | null)[];
}[];
} | null;
insideIsland: (id: string) => boolean;
canPlace: (ids: readonly import("./index.js").BlockId[], parent?: import("./index.js").BlockId | null) => boolean;
canMerge: (from: import("./index.js").BlockId, into: import("./index.js").BlockId) => boolean;
fits: (parent: import("./index.js").BlockId | null, kind: string) => boolean;
nestParent: (ids: readonly import("./index.js").BlockId[], parent: import("./index.js").BlockId) => string;
landingOf: (id: import("./index.js").BlockId, kind: string, after?: boolean) => {
parent: string | null;
levels: string[];
};
defaultChild: (id: string | null) => string;
runs: (id: string) => readonly import("./index.js").ContentRun[];
contentJSON: (id: string) => ({
text: string;
marks?: Record<string, unknown>;
} | {
id?: string;
type: string;
data?: unknown;
})[];
onChange: (cb: (change: import("./edytor-doc.js").DocChange) => void) => (() => void);
};
newDoc: (opts?: ConstructorParameters<EngineApi["Doc"]>[0]) => YDoc;
keepCopies: (doc: import("./engine-api.js").EngineDoc) => void;
purge: (doc: import("./engine-api.js").EngineDoc, facade: {
model: import("./placement/model.js").PlacementModel;
text: import("./text/model.js").TextEngine;
}, horizon: import("./purge.js").Horizon) => import("./purge.js").PurgeReport;
horizonOf: (doc: import("./engine-api.js").EngineDoc) => import("./purge.js").Horizon | null;
restoreTo: <Plan>(doc: import("./engine-api.js").EngineDoc, facade: import("./restore.js").RestoreFacade<Plan>, json: import("./index.js").JSONDoc) => import("./restore.js").RestoreReport;
model: {
REGISTRY_KEY: string;
registryOf: (doc: import("./engine-api.js").EngineDoc) => import("./engine-api.js").EngineNode;
blockNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
liveNodeOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
isLive: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => boolean;
candidatesOf: (node: import("./engine-api.js").EngineNode) => import("./placement/model.js").PlacementCand[];
view: (doc: import("./engine-api.js").EngineDoc) => import("./placement/model.js").ModelView;
resolvePlacements: (blocks: Map<import("./index.js").BlockId, import("./placement/model.js").BlockRec>, ownerOf?: (b: import("./index.js").BlockId) => import("./text/model.js").Owner) => Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>;
childrenIndex: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./placement/model.js").DisplayOwnership) => Map<import("./index.js").BlockId | null, import("./placement/model.js").ChildSlot[]>;
positionInView: (v: import("./placement/model.js").ModelView, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
buildInline: (atom: import("./index.js").InlineSpec) => import("./engine-api.js").EngineNode;
isSelfOrDescendant: (placements: Map<import("./index.js").BlockId, import("./placement/model.js").ResolvedPlacement>, own: import("./text/model.js").Ownership, id: import("./index.js").BlockId, maybeAncestor: import("./index.js").BlockId) => boolean;
ranksAt: (siblings: readonly {
rank: string;
}[], index: number, count: number, clientId: number, rand?: () => number, run?: boolean) => string[];
writePlacement: (doc: import("./engine-api.js").EngineDoc, node: import("./engine-api.js").EngineNode, p: import("./index.js").BlockId | null, r: string) => void;
withdrawOnUndo: (doc: import("./engine-api.js").EngineDoc) => (item: import("./engine-api.js").EngineItemRef, stackItem: {
inserts: {
has(client: number, clock: number): boolean;
};
}) => boolean;
materializeSpec: (doc: import("./engine-api.js").EngineDoc, sp: import("./index.js").BlockSpec, parent: import("./index.js").BlockId | null, rank: string) => void;
collides: (doc: import("./engine-api.js").EngineDoc, specs: readonly import("./index.js").BlockSpec[]) => boolean;
writeSplit: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId, offset: number, newId: import("./index.js").BlockId, tail: import("./placement/model.js").SplitTail, place: import("./placement/model.js").PlacementValue) => void;
ownText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => {
from: unknown;
to: number;
};
insertBlocks: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, specs: import("./index.js").BlockSpec[]) => boolean;
insertBlock: (doc: import("./engine-api.js").EngineDoc, dest: import("./index.js").Destination, spec: import("./index.js").BlockSpec) => boolean;
restoreBlocks: (doc: import("./engine-api.js").EngineDoc, specs: import("./index.js").BlockSpec[]) => void;
project: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").ProjectedDoc;
positionOf: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./index.js").Destination | null;
listBlockIds: (doc: import("./engine-api.js").EngineDoc) => import("./index.js").BlockId[];
blockText: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
crdtId: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => string | null;
resolveBlock: (doc: import("./engine-api.js").EngineDoc, id: import("./index.js").BlockId) => import("./engine-api.js").EngineNode | null;
};
text: {
newNode: (name: string) => import("./engine-api.js").EngineNode;
resolveAnchor: (doc: import("./engine-api.js").EngineDoc, text: import("./engine-api.js").EngineNode, anchor: import("./text/model.js").Anchor) => number | null;
anchorAt: (text: import("./engine-api.js").EngineNode, index: number, assoc: number) => import("./text/model.js").Anchor;
openRangeCursor: (text: import("./engine-api.js").EngineNode) => import("./text/model.js").RangeCursor;
itemsOfRange: (text: import("./engine-api.js").EngineNode, i0: number, i1: number) => import("./text/model.js").RangeItem[];
readSegs: (segs: readonly import("./text/model.js").Seg[], stats?: import("./text/model.js").RangeReadStats) => import("./text/model.js").RangeItem[];
computeOwnership: (doc: import("./engine-api.js").EngineDoc, given: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>) => import("./text/model.js").Ownership;
flatten: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").Seg[];
ownedLength: (segs: readonly import("./text/model.js").Seg[]) => number;
contentItemsOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => import("./text/model.js").RangeItem[];
blockTextOf: (b: import("./text/model.js").BlockId, blocks: unknown, own: import("./text/model.js").Ownership) => string;
insertIntoText: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, payload: string | import("./engine-api.js").EngineNode, marks?: Record<string, unknown>) => void;
deleteRange: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number) => void;
formatRangeIn: (doc: import("./engine-api.js").EngineDoc, blocks: unknown, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, length: number, formats: Record<string, unknown>) => void;
purgeStreams: (streams: readonly import("./text/model.js").Stream[]) => void;
findAtom: (own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, inlineId: string) => {
text: import("./engine-api.js").EngineNode;
at: number;
node: import("./engine-api.js").EngineNode;
} | null;
splitAt: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: import("./text/model.js").Ownership, b: import("./text/model.js").BlockId, offset: number, newId: import("./text/model.js").BlockId, n: number) => import("./text/model.js").MergeClaim[];
claimInto: (blocks: ReadonlyMap<import("./text/model.js").BlockId, import("./text/model.js").TextBlockRec>, own: Pick<import("./text/model.js").Ownership, "streamOf">, from: import("./text/model.js").BlockId, into: import("./text/model.js").BlockId) => void;
ownText: (doc: import("./engine-api.js").EngineDoc, rec: import("./text/model.js").TextBlockRec) => {
from: unknown;
to: number;
};
};
runs: {
attach: (doc: import("./engine-api.js").EngineDoc) => import("./text/runs.js").RunView;
};
};
providers: {
prefetch: (options: PrefetchOptions) => Promise<import("./index.js").PrefetchResult>;
lastUpdated: (options: import("./index.js").LastUpdatedOptions) => Promise<number | null>;
documentSnapshot: (options: import("./index.js").LastUpdatedOptions) => Promise<import("./index.js").JSONDoc | null>;
IndexeddbPersistence: {
new (name: string, doc: YDoc, options?: import("./protocol.js").IndexeddbPersistenceOptions): {
doc: YDoc;
name: string;
dbName: string;
_dbref: number;
_dbsize: number;
db: IDBDatabase | null;
_db: Promise<IDBDatabase>;
_destroyed: boolean;
hasSynced: boolean;
whenSynced: Promise<any>;
_failedEmitted?: boolean;
_settleSynced: import("./providers/room.js").LifecycleHost["_settleSynced"];
_leave: () => void;
loadError: unknown;
_storeTimeout: number;
_storeTimeoutId: ReturnType<typeof setTimeout> | null;
_storeUpdate: (update: Uint8Array, origin: unknown) => void;
awareness: _Awareness;
bcconnected: boolean;
disableBc: boolean;
_ownsAwareness: boolean;
_bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
_awarenessUpdateHandler: (updates: {
added: number[];
updated: number[];
removed: number[];
}, origin: unknown) => void;
get synced(): boolean;
messageHandlers: Record<number, import("./providers/room.js").RoomMessageHandler<any>>;
readMessage: (buf: Uint8Array, emitSynced: boolean) => import("lib0-v14/encoding").Encoder;
broadcastMessage(buf: Uint8Array): void;
connectBc(): void;
disconnectBc(): void;
destroy(): Promise<void>;
emit<N extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: N, args: Parameters<{
synced: (provider: any) => void;
'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
'load-error': (error: unknown, provider: any) => void;
'message-error': (error: unknown, provider: any) => void;
'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
failed: (error: unknown, provider: any) => void;
}[N]>): void;
_observers: Map<string, Set<any>>;
on<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
synced: (provider: any) => void;
'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
'load-error': (error: unknown, provider: any) => void;
'message-error': (error: unknown, provider: any) => void;
'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
failed: (error: unknown, provider: any) => void;
}[NAME]): {
synced: (provider: any) => void;
'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
'load-error': (error: unknown, provider: any) => void;
'message-error': (error: unknown, provider: any) => void;
'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
failed: (error: unknown, provider: any) => void;
}[NAME];
once<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
synced: (provider: any) => void;
'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
'load-error': (error: unknown, provider: any) => void;
'message-error': (error: unknown, provider: any) => void;
'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
failed: (error: unknown, provider: any) => void;
}[NAME]): void;
off<NAME extends "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
synced: (provider: any) => void;
'protocol-mismatch': (mismatch: import("./protocol.js").ProtocolMismatch, provider: any) => void;
'load-error': (error: unknown, provider: any) => void;
'message-error': (error: unknown, provider: any) => void;
'schema-mismatch': (detail: import("./protocol.js").SchemaMismatchDetail, provider: any) => void;
failed: (error: unknown, provider: any) => void;
}[NAME]): void;
};
};
WebsocketProvider: {
new (serverUrl: string, roomname: string, doc: YDoc, { connect, awareness, params, WebSocketPolyfill, resyncInterval, maxBackoffTime, connectTimeout, disableBc, maxFrameBytes }?: import("./protocol.js").WebsocketProviderOptions): {
serverUrl: string;
roomname: string;
doc: YDoc;
awareness: _Awareness;
params: Record<string, string>;
maxBackoffTime: number;
connectTimeout: number;
maxFrameBytes: number;
_WS: import("./protocol.js").WebsocketPolyfill;
shouldConnect: boolean;
ws: WebSocket | null;
wsconnected: boolean;
bcChannel: string;
bcconnected: boolean;
disableBc: boolean;
_bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
_fromTab: {};
wsUnsuccessfulReconnects: number;
wsLastMessageReceived: number;
wsLastPingSent: number;
_synced: boolean;
_chunks: import("./protocol.js").ChunkReader;
_writes: {
pending: {
sv: Map<number, number>;
deletes: import("./protocols/sync.js").IdSet;
}[];
acked: Map<number, number>;
readOnly: boolean;
faults: number;
fault(): number;
readonly doc: YDoc;
readonly changed: (unsaved: number) => void;
trackDocument(): void;
track(sv: Map<number, number>, deletes: import("./protocols/sync.js").IdSet): void;
acknowledge(sv: Uint8Array, deletes?: import("./protocols/sync.js").IdSet | null): void;
deny(): void;
allow(): void;
};
messageHandlers: Record<number, import("./providers/room.js").RoomMessageHandler<any>>;
hasSynced: boolean;
whenSynced: Promise<unknown>;
_destroyed: boolean;
_failedEmitted?: boolean;
_settleSynced: import("./providers/room.js").LifecycleHost["_settleSynced"];
_leave: () => void;
_resync: ReturnType<typeof setInterval> | undefined;
_connectTimer: ReturnType<typeof setTimeout> | undefined;
_checkInterval: ReturnType<typeof setInterval>;
_updateHandler: (update: Uint8Array, origin: unknown, doc?: unknown, transaction?: {
local: boolean;
}) => void;
_awarenessUpdateHandler: (updates: {
added: number[];
updated: number[];
removed: number[];
}, origin: unknown) => void;
get url(): string;
get unsaved(): number;
get saved(): boolean;
get readOnly(): boolean;
get synced(): boolean;
set synced(state: boolean);
destroy(): void;
disconnect(): void;
connect(): void;
emit<N extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: N, args: Parameters<import("./protocol.js").WebsocketProviderEvents[N]>): void;
_observers: Map<string, Set<any>>;
on<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): import("./protocol.js").WebsocketProviderEvents[NAME];
once<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): void;
off<NAME extends "refused" | "status" | "failed" | "schema-mismatch" | "message-error" | "protocol-mismatch" | "synced" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: import("./protocol.js").WebsocketProviderEvents[NAME]): void;
};
};
watchComments: (server: string, roomName: string, listener: (message: import("./protocol.js").CommentMessage) => void) => (() => void);
storeState: (idbPersistence: {
db: IDBDatabase | null;
name: string;
doc: YDoc;
_dbref: number;
_dbsize: number;
_destroyed: boolean;
}, forceStore?: boolean) => Promise<undefined>;
clearDocument: (name: string) => Promise<void>;
PREFERRED_TRIM_SIZE: number;
createIndexeddbSync: (name: string) => import("./index.js").EdytorSync;
createWebsocketSync: (options: import("./index.js").WebsocketSyncOptions) => import("./index.js").WebsocketSync;
};
sync: {
messageYjsSyncStep1: number;
messageYjsSyncStep2: number;
messageYjsUpdate: number;
remoteApplyOrigin: symbol;
writeSyncStep1: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc) => void;
writeSyncStep2: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc, encodedStateVector?: Uint8Array) => void;
writeUpdate: (encoder: import("lib0-v14/encoding").Encoder, update: Uint8Array) => void;
applyRemote: (doc: YDoc, update: Uint8Array, transactionOrigin: unknown, errorHandler?: (error: Error) => unknown) => {
applied: boolean;
problem: import("./edytor-doc.js").SchemaProblem | null;
discarded?: import("./edytor-doc.js").SchemaProblem;
};
lacks: (doc: YDoc, sv: Uint8Array) => boolean;
writeSaved: (encoder: import("lib0-v14/encoding").Encoder, doc: YDoc, deletes?: import("./protocols/sync.js").IdSet, unstored?: import("./protocols/sync.js").IdSet | null) => void;
readSaved: (decoder: import("lib0-v14/decoding").Decoder) => {
stateVector: Uint8Array;
deletes: import("./protocols/sync.js").IdSet | null;
};
};
admission: {
admitUpdate: (update: Uint8Array | ReadonlyArray<Uint8Array>, docName?: string, options?: {
prepare?: (doc: YDoc) => void;
}) => YDoc;
};
attribution: {
attach: (doc: import("./engine-api.js").EngineDoc, opts: {
actor: import("./index.js").AttributionActor;
}) => import("./index.js").AttributionController;
};
};
checkSchema
Inspect the document’s schema record. null = clean (versioned under the
supported schema AND manifest name, or completely untouched). Read-only,
safe mid-transaction.
declare const checkSchema: (doc: EngineDoc) => SchemaProblem | null;
chunkFrame
Split whole (a complete frame) into frames of at most maxFrameBytes:
itself when it fits, else start(total), part(bytes)…, end. A
receiver applies the reassembled frame only once end arrives.
declare const chunkFrame: (whole: Uint8Array, maxFrameBytes?: number) => Uint8Array[];
ChunkLimitError
A chunk sequence announces a frame larger than its reader takes (createChunkReader).
export declare class ChunkLimitError extends Error {
readonly total: number;
readonly limit: number;
constructor(total: number, limit: number);
}
ChunkReader
A chunk reader (createChunkReader): feed it chunk bodies; buffered is what it holds.
export type ChunkReader = {
(decoder: decoding.Decoder): Uint8Array | null;
readonly buffered: number;
};
buffered: Bytes held for the sequence in flight: its announced size, allocated at its start (0: none).
CLOSE
The close codes of the edytor room (edytor/cloudflare) and its router,
as the websocket provider reads them. Only expired and fault are
redialed; every other code here is a isRefusalrefusal.
declare const CLOSE: {
readonly refused: 1008;
readonly fault: 1011;
readonly accessChanged: 1012;
readonly invalidDocument: 4400;
readonly expired: 4401;
readonly denied: 4403;
readonly replicaTaken: 4409;
readonly quota: 4413;
};
CommentChange
What one request changed (the room broadcasts it, onComment receives it).
export type CommentChange = {
type: 'added' | 'replied' | 'resolved' | 'reopened' | 'deleted' | 'removed';
thread: CommentThread;
comment: ThreadComment | null;
user: string;
at: number;
seq: number;
};
type:addeda thread,repliedto one,resolvedorreopenedone,deleteda reply, orremoveda whole thread (its anchor marks go with it).thread: The thread after the change; forremoved, as it was.comment: The comment added (added,replied) or deleted (deleted), elsenull.user: Who made the change.seq: The change’s sequence number in its document (the thread’s newrev).
CommentMessage
A comment message, decoded.
export type CommentMessage = {
type: 'subscribe';
on: boolean;
} | ({
type: 'snapshot';
} & CommentSnapshot) | {
type: 'change';
change: CommentChange;
};
commentsChange
Room → client: one change.
declare const commentsChange = 2;
CommentSnapshot
The document’s threads at sequence number seq.
export type CommentSnapshot = {
seq: number;
threads: CommentThread[];
};
commentsSnapshot
Room → client: every thread, and the document’s last sequence number (an answer to a subscribe).
declare const commentsSnapshot = 1;
commentsSubscribe
Client → room: start (or stop) hearing the document’s comment changes.
declare const commentsSubscribe = 0;
CommentThread
A comment thread: its first comment starts it, the others reply.
export type CommentThread = {
id: string;
block: string | null;
quote: string;
createdBy: string;
createdAt: number;
resolved: {
by: string;
at: number;
} | null;
comments: ThreadComment[];
rev: number;
};
id: The thread’s id, which its anchor mark names (comment:<id>).block: The block it was started in (null: unknown).quote: The text it was started on, as it read then (at mostMAX_QUOTE_LENGTH).resolved: Who resolved it and when;nullwhile it is open.comments: Oldest first; never empty.rev: The sequence number of the last change to it (a later change has a greater one).
Crdt
export type Crdt = ReturnType<typeof bindCrdt>;
createChunkReader
The receiving half of chunkFrame, one per connection: feed it
each chunk frame’s body (after the message type); it returns the whole
frame on end, null before. An out-of-order or oversized sequence
throws and resets; a sequence announcing more than maxBytes throws
ChunkLimitError at its start, before anything is buffered. A
sequence is assembled into ONE buffer of its announced size, allocated
at its start (buffered), never into parts copied at its end.
admit(total) is asked at each start, before that allocation: it may
throw to refuse the sequence, or return false to skip it (its parts
are read and dropped, and its end returns null).
declare const createChunkReader: (maxBytes?: number, admit?: (total: number) => boolean) => ChunkReader;
createDecoder
Decoder
A Decoder handles the decoding of an Uint8Array.
encodeAwarenessUpdate
The update carrying clients’ entries of awareness (their states in states).
declare const encodeAwarenessUpdate: (awareness: Awareness, clients: number[], states?: AwarenessStates) => Uint8Array;
Encoder
A BinaryEncoder handles the encoding to an Uint8Array.
EngineApi
The engine surface every bind* receives: the object in engine.js
(exactly the symbols edytor calls, so consumer bundles tree-shake the
rest). The full namespace import * as Y from 'edytor/crdt' is a
superset and satisfies it.
export type EngineApi = typeof Engine;
EngineDoc
Structural minimum of the vendored Y.Doc.
export interface EngineDoc {
clientID: number;
keepReplaced?: ((item: never) => boolean) | null;
get(key?: string): EngineNode;
transact<T>(f: (transaction: unknown) => T, origin?: unknown): T;
on(name: 'update', f: (update: Uint8Array, origin: unknown, doc: EngineDoc, transaction: unknown) => void): void;
off(name: 'update', f: (update: Uint8Array, origin: unknown, doc: EngineDoc, transaction: unknown) => void): void;
on(name: 'commit', f: (transaction: never) => void): void;
off(name: 'commit', f: (transaction: never) => void): void;
on(name: 'destroy', f: () => void): void;
off(name: 'destroy', f: () => void): void;
readonly store?: {
pendingStructs: null | {
missing: Map<number, number>;
update: Uint8Array;
};
pendingDs: null | Uint8Array;
getClock(client: number): number;
};
readonly _transaction?: EngineTransaction | null;
}
keepReplaced: Which node values a concurrent write of the same key replaced keep their subtree (null: none, upstream’s semantics).on: Doc-levelupdatechannel — fires once per transaction that produced replicated state (local commits AND remoteapplyUpdates), carrying the transaction’s origin and the transaction itself (transaction.localdistinguishes local commits from remote applies).on: Doc-levelupdatechannel — fires once per transaction that produced replicated state (local commits AND remoteapplyUpdates), carrying the transaction’s origin and the transaction itself (transaction.localdistinguishes local commits from remote applies).on: Doc-levelupdatechannel — fires once per transaction that produced replicated state (local commits AND remoteapplyUpdates), carrying the transaction’s origin and the transaction itself (transaction.localdistinguishes local commits from remote applies).store: The doc’s struct store — present on a real engine doc._transaction: The engine’s CURRENT transaction (nulloutside one) — vendoredDoc._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;nullwhile detached.length: Sequence length (invalid read on detached nodes — track offsets instead)._item: The item this node is attached to (identity anchor forcrdtId).
EngineTransaction
Structural minimum of the in-flight engine Transaction — exposed on the
doc as doc._transaction while a transaction is open. changed maps each
touched shared type to the set of parentSub keys whose items changed
(attr names for map-like children, null for sequence edits); the
document index folds it once at commit.
export interface EngineTransaction {
changed?: Map<unknown, Set<string | null>>;
}
frame
One provider frame: the generation word, the message type, then write’s payload.
declare const frame: (type: number, write: (encoder: encoding.Encoder) => void) => Uint8Array;
GENERATION
This build’s generation word.
declare const GENERATION: number;
GENERATION_RECORD
This generation’s record.
declare const GENERATION_RECORD: GenerationRecord;
GenerationMismatchError
export declare class GenerationMismatchError extends Error {
readonly dbName: string;
readonly found: unknown;
constructor(dbName: string, found: unknown);
}
GenerationRecord
Record written to the custom store marking a DB as this generation’s.
Every row of a container holds an update in the engine’s one encoding;
a snapshot row may be gzip-compressed (crdt/storage.ts).
export type GenerationRecord = {
engine: 'yjs-v14';
protocol: number;
schema: number;
};
generationWord
The frame word a build of application schema schema writes.
declare const generationWord: (schema: number) => number;
IndexeddbPersistence
declare const IndexeddbPersistence: ProviderStack['IndexeddbPersistence'];
IndexeddbPersistenceApi
Instance type of the bound provider class.
export type IndexeddbPersistenceApi = InstanceType<IndexeddbProvider['IndexeddbPersistence']>;
IndexeddbPersistenceOptions
export type IndexeddbPersistenceOptions = {
awareness?: Awareness;
disableBc?: boolean;
};
disableBc: Stay off the BroadcastChannel room (no cross-tab sync): storage only.
inspectAdmission
Non-throwing assertAdmission — for audits, diagnostics, and
tests that need the verdict without control flow. Unexpected
(non-admission) errors still throw.
declare const inspectAdmission: (doc: EngineDoc, docName?: string) => AdmissionResult;
isInitialized
True iff the document carries the schema version record. Content alone —
e.g. a raw doc.get('blocks').setAttr('x', …) write — is NOT proof of
initialization: the gate distinguishes “versioned” from “has any registry
state” so rogue unversioned writes never masquerade as an initialized doc.
A replica that learned meta.v purely by applying updates counts.
declare const isInitialized: (doc: EngineDoc) => boolean;
MAX_FRAME_BYTES
A WebSocket message limit on Cloudflare (32 MiB): a larger frame is sent as chunks.
declare const MAX_FRAME_BYTES: number;
messageAuth
declare const messageAuth = 2;
messageAwareness
declare const messageAwareness = 1;
messageChunk
Server → client: one piece of a frame too large to send whole (bounded catch-up).
declare const messageChunk = 5;
messageComments
Both ways: a document’s comment threads (protocols/comments.ts): a
client subscribes, the room answers every thread, then each change. The
room sends it only to a socket that subscribed.
declare const messageComments = 6;
messagePermissionDenied
declare const messagePermissionDenied = 0;
messageQueryAwareness
declare const messageQueryAwareness = 3;
messageReadOnly
The socket may read but not write: sent when it joins, before any write is refused.
declare const messageReadOnly = 1;
messageSaved
Server → client: the room persisted everything under this state vector (store-before-ack).
declare const messageSaved = 4;
messageSync
declare const messageSync = 0;
messageYjsSyncStep1
Sync message subtypes (the varuint after messageSync).
declare const messageYjsSyncStep1 = 0;
messageYjsSyncStep2
declare const messageYjsSyncStep2 = 1;
messageYjsUpdate
declare const messageYjsUpdate = 2;
META_KEY
declare const META_KEY: "meta";
PROTOCOL_VERSION
Provider protocol generation. Chosen so it can never collide with a v13 message type word (0..3) at the same position.
declare const PROTOCOL_VERSION = 14;
ProtocolMismatch
export type ProtocolMismatch = {
expected: number;
found: number | null;
};
ProviderStack
export type ProviderStack = ReturnType<typeof bindProviders>;
readAwarenessEntries
Instance-free awareness codec: decode an update into its entries. Pure —
no Awareness (whose constructor starts an interval), so a relay that
must not hold timers (a hibernating Durable Object) can track presence.
declare const readAwarenessEntries: (update: Uint8Array) => AwarenessEntry[];
readCommentsMessage
Read one comment message (after its message type); throws on bytes that do not decode.
declare const readCommentsMessage: (decoder: decoding.Decoder) => CommentMessage;
readProtocolVersion
Read and verify the generation word. Returns true iff the message is
this generation’s and the caller may dispatch on the next varuint (the
message type). On false the caller MUST NOT read further or apply
anything.
declare const readProtocolVersion: (decoder: decoding.Decoder) => boolean;
readVarUint
readVarUint8Array
registryEmpty
True iff the blocks registry holds at least one entry (live or deleted).
declare const registryEmpty: (doc: EngineDoc) => boolean;
SCHEMA_VERSION
declare const SCHEMA_VERSION: 6;
SchemaMismatchDetail
Inbound refusal detail — emitted on 'schema-mismatch' (and mirrored
through 'message-error' as a SchemaMismatchError) when a
received update would write a foreign schema stamp (unsupported
version, foreign manifest, or a deleted stamp — unversioned). The
update is never integrated, persisted, or rebroadcast.
export type SchemaMismatchDetail = {
docName: string;
problem: SchemaProblem;
};
SchemaMismatchError
Error raised by assertSchema — carries the detected problem.
export declare class SchemaMismatchError extends Error {
readonly docName: string;
readonly problem: SchemaProblem;
constructor(docName: string, problem: SchemaProblem);
}
SchemaProblem
A document’s relationship to this build’s schema:
unversioned— registry state exists butmeta.vis absent. Someone wrote replicated content without running the schema path (a rogue or v13-era write). This state must NEVER be persisted/broadcast as a document update by a provider.unsupported—meta.vnames a version this build does not speak (e.g.99written by a future build). Content still applies (a replica cannot refuse structs it already shares a protocol with), but providers surface aschema-mismatchsignal so operators can detect skew.foreign—meta.vis the supported version butmeta.schemais missing or names a DIFFERENT manifest ('not-edytor', a next-gen name, an app-local doc kind). A valid version number alone does not make the payload an edytor document — the manifest name is part of the contract (the version-only check let foreignmeta.schemavalues cross the staging boundary).
export type SchemaProblem = {
kind: 'unversioned' | 'unsupported' | 'foreign';
version?: number;
schema?: unknown;
};
version: The observedmeta.v(undefined forunversioned).schema: The observedmeta.schema(undefined when absent).
schemaVersion
The replicated schema version (meta.v) — undefined before init.
Read-only: doc.get on a root emits no update.
declare const schemaVersion: (doc: EngineDoc) => number | undefined;
storeState
Compact an IndexeddbPersistence’s store into one snapshot now (it settles once stored).
declare const storeState: ProviderStack['storeState'];
SyncProtocol
export type SyncProtocol = ReturnType<typeof bindSync>;
ThreadComment
One comment of a thread.
export type ThreadComment = {
id: string;
author: string;
body: string;
createdAt: number;
};
author: The verified user who wrote it.body: Plain text (line breaks kept).createdAt: ms since the epoch.
UndecodableUpdateError
Raised when a candidate update cannot even be decoded or integrated — refused before the schema question is ever asked. Distinct from the schema refusals: this payload was never document-shaped.
export declare class UndecodableUpdateError extends Error {
readonly docName: string;
readonly cause: unknown;
constructor(docName: string, cause: unknown);
}
docName: What the update was offered as (e.g.
UnsupportedDocError
Error raised by assertUsableDoc — the doc cannot host a v14 facade:
a foreign engine object (a v13 yjs Doc — a different CRDT implementation
entirely).
export declare class UnsupportedDocError extends Error {
readonly kind: 'foreign';
constructor(kind: 'foreign');
}
WebsocketPolyfill
export type WebsocketPolyfill = {
new (url: string): WebSocket;
prototype: WebSocket;
readonly OPEN: number;
};
WebsocketProvider
declare const WebsocketProvider: ProviderStack['WebsocketProvider'];
WebsocketProviderEvents
export type WebsocketProviderEvents = {
status: (event: {
status: 'connected' | 'disconnected' | 'connecting';
}) => void;
synced: (state: boolean) => void;
'connection-close': (event: CloseEvent | null, provider: unknown) => void;
'connection-error': (event: Event, provider: unknown) => void;
'protocol-mismatch': (mismatch: ProtocolMismatch, provider: unknown) => void;
'message-error': (error: unknown, provider: unknown) => void;
'schema-mismatch': (detail: SchemaMismatchDetail, provider: unknown) => void;
saved: (state: {
saved: boolean;
unsaved: number;
}, provider: unknown) => void;
'permission-denied': (reason: string, provider: unknown) => void;
refused: (refusal: SyncRefusedError, provider: unknown) => void;
expired: (state: {
reason: string;
attempts: number;
nextRetryMs: number;
}, provider: unknown) => void;
unreachable: (state: {
attempts: number;
nextRetryMs: number;
}, provider: unknown) => void;
failed: (error: unknown, provider: unknown) => void;
};
'message-error': Fired when a v14-tagged frame could not be decoded (truncated/corrupt frame or an unknown message type), or when a sync payload failed to apply.'schema-mismatch': A received update wrote a foreign schema stamp and was refused (SchemaMismatchDetail).saved: The count of local updates the room has not yet acknowledged as persisted changed (store-before-ack: amessageSavedframe carries the room’s state vector after it stored what it holds).'permission-denied': Server refused access — the auth reply carried a denial reason.refused: The server closed the socket with a refusal code (1008,4xxx): the provider stopped dialing.expired: The server closed the socket with4401: the credentials expired.unreachable: A dial ended before its connection synced (refused upgrade, dropped handshake, server down, not open withinconnectTimeout):attemptsin a row, the next innextRetryMs.failed: Terminal sync failure: the provider never synced — destroyed before any handshake completed, refused, or the server denied permission.
WebsocketProviderOptions
export type WebsocketProviderOptions = {
connect?: boolean;
awareness?: Awareness;
params?: Record<string, string>;
WebSocketPolyfill?: WebsocketPolyfill;
resyncInterval?: number;
maxBackoffTime?: number;
connectTimeout?: number;
disableBc?: boolean;
maxFrameBytes?: number;
};
params: Query parameters (auth tokens), read at every dial.resyncInterval: Re-send a Step1 everyresyncIntervalms on the live socket (off by default): heals frames a test harness drops; the join rule needs no timer.maxBackoffTime: Max reconnect backoff (exponential backoff is used).connectTimeout: ms a dial may take to open before it is closed like a failed one (default 10 000;Infinitywaits for as long as the browser does).disableBc: Opt out of cross-tab sync over the BroadcastChannel (on by default).maxFrameBytes: Largest frame sent whole (default 32 MiB, Cloudflare’s WebSocket message limit): a larger one — a reconnect’s backlog, a big paste — goes out as a chunk sequence the room reassembles.
writeAwarenessEntries
Instance-free awareness codec: encode entries as an update.
declare const writeAwarenessEntries: (entries: readonly AwarenessEntry[]) => Uint8Array;
writeCommentsChange
declare const writeCommentsChange: (encoder: encoding.Encoder, change: CommentChange) => void;
writeCommentsSnapshot
declare const writeCommentsSnapshot: (encoder: encoding.Encoder, snapshot: CommentSnapshot) => void;
writeCommentsSubscribe
declare const writeCommentsSubscribe: (encoder: encoding.Encoder, on: boolean) => void;
writePermissionDenied
declare const writePermissionDenied: (encoder: encoding.Encoder, reason: string) => void;
writeReadOnly
declare const writeReadOnly: (encoder: encoding.Encoder) => void;
writeVarUint8Array
YDoc
export type YDoc = InstanceType<typeof Y.Doc>;
YItem
export type YItem = Y.Item;
YNode
export type YNode = InstanceType<typeof Y.Node>;
YTransaction
export type YTransaction = Y.Transaction;
YUndoManager
The document’s undo manager (doc/history.ts).
export type YUndoManager = import('./doc/history.js').UndoManager;