Entry points
The package entry points of edytor, what each exports, and where each can run, from the browser to Node and Cloudflare Workers, plus the Notion theme stylesheet.
The edytor package has four code entry points and one stylesheet. Only the root contains Svelte components; the CRDT entries have no Svelte in their import graph and run in Node and in Cloudflare Workers.
| Import | Contains | Runs in |
|---|---|---|
edytor |
The <Edytor> component, bundled plugins, handles, the document API, sync factories |
A Svelte bundler (SvelteKit, Vite) |
edytor/crdt/edytor |
The document API and its types, bindCrdt, awareness, the wire protocol helpers |
Browser, Node 22+, Workers |
edytor/crdt |
The vendored CRDT engine itself (Yjs v14 fork) | Browser, Node 22+, Workers |
edytor/cloudflare |
DocumentRoom (a Durable Object), attachDocument (for your own Durable Object), routeDocumentSocket with requestedReplica, and closedSocket |
Cloudflare Workers only |
edytor/themes/notion.css |
The Notion theme stylesheet | Any bundler that imports CSS |
No other path is exported. Imports such as edytor/dist/... or edytor/crdt/vendor/... fail with ERR_PACKAGE_PATH_NOT_EXPORTED.
edytor
The root entry is what a Svelte app imports:
import {
Edytor, // the component
useEdytor, // the editor instance from inside the component tree
Block, Text, InlineBlock, // handle classes
richTextPlugin, imagePlugin, arrowMovePlugin, // the default plugins
codePlugin, markdownShortcutsPlugin, createImagePlugin,
slashMenuPlugin, createSlashMenuPlugin, toolbarPlugin, createToolbarPlugin,
blockMenuPlugin, createBlockMenuPlugin, blockHandlesPlugin, createBlockHandlesPlugin,
richTextOperations, richTextPlaceholder, convertToKind,
createDocument, loadDocument, attachDocument, // the document API
createIndexeddbSync, createWebsocketSync, clearDocument, // sync factories
IndexeddbPersistence, WebsocketProvider // provider classes
} from 'edytor';
It also re-exports everything from edytor/crdt/edytor, so a Svelte app never needs a second import for the document API or its types (JSONDoc, JSONBlock, OpResult, DocChange, …).
Because it contains .svelte files, the root entry needs a bundler that compiles Svelte. Plain Node cannot import it.
edytor/crdt/edytor
The same document surface without Svelte. Use it on a server, in a script, in a worker or anywhere the component cannot load:
import { createDocument, defaultSemantics, loadDocument } from 'edytor/crdt/edytor';
const document = createDocument({
value: { children: [{ type: 'paragraph', content: [{ text: 'hello' }] }] },
actor: { id: 'user-42', name: 'Ada' },
semantics: defaultSemantics // the bundled kinds' block roles: no view supplies them here
});
const [block] = document.facade.project().children;
document.transact(() => document.facade.insertText(block.id, 5, ' world'));
const saved = document.encode(); // Uint8Array
const restored = loadDocument(saved);
console.log(restored.facade.toJSON());
It exports:
createDocument,loadDocument,attachDocumentand theEdytorDocumentclass. See the document reference.- The JSON and facade types:
JSONDoc,JSONBlock,JSONText,JSONInlineBlock,BlockSpec,Destination,OpResult,DocChange,DocAnchor,DocPosition,RangeView,FlowView,EdytorDoc. Awareness, the sync and provider types (EdytorSync,WebsocketProviderOptions, …), admission checks, attribution types and the v13 migration types.bindCrdt(Y), which binds the providers, migration and sync protocol to an engine you pass in.- The frame and message helpers a server coordinator needs.
The ready-made sync factories (createIndexeddbSync, createWebsocketSync) and the provider classes are exported from the root only. Outside Svelte, reach the providers through bindCrdt:
import * as Y from 'edytor/crdt';
import { bindCrdt } from 'edytor/crdt/edytor';
const crdt = bindCrdt(Y);
const doc = crdt.createDoc();
const awareness = new crdt.Awareness(doc);
const provider = new crdt.providers.IndexeddbPersistence('document-id', doc, { awareness });
await provider.whenSynced;
edytor/crdt
The raw engine: Edytor’s own fork of Yjs v14, pruned to what Edytor uses (documents, nodes, transactions, UndoManager, update encoding and merging, state vectors, relative positions).
import * as Y from 'edytor/crdt';
const merged = Y.mergeUpdates([updateA, updateB]);
You rarely need it directly. Reach for it when you pass the engine to bindCrdt, or when you handle raw updates (merging, state vectors) yourself.
edytor/cloudflare
The server side of real-time collaboration: DocumentRoom, a Durable Object that coordinates one document; attachDocument(this, options), which hosts a document in any Durable Object of yours; routeDocumentSocket, which authorizes a client before its WebSocket upgrade, and requestedReplica, which reads the client id the dial sends; and closedSocket(code, reason), which turns a dial away from your own Worker with a close the provider understands (see authorization).
import { DocumentRoom, routeDocumentSocket, requestedReplica } from 'edytor/cloudflare';
export { DocumentRoom };
It imports cloudflare:workers, so it loads only inside a Worker. It is built on the Worker-safe CRDT entries and has no Svelte or DOM code. Setup is covered in Server quick start and Your own Durable Object. Its attachDocument is unrelated to the attachDocument of edytor, which wraps an engine document on the client.
Bundle size and tree-shaking
- Import what you render. Every JavaScript module in the package is free of side effects (
sideEffectslists only CSS), so a bundler drops the plugins you never import. The code plugin, with TanStack Highlight and its stylesheet, ships only in apps that importcodePlugin. - The engine is pruned.
edytor/crdtis Edytor’s fork of Yjs v14, cut down to what Edytor runs on. The document API reaches the engine through one fixed object of the symbols it calls, so an app that never importsedytor/crdtitself bundles only what those symbols reach.bindCrdt(Y)with the whole namespace (import * as Y from 'edytor/crdt') keeps the whole pruned engine. - Headless code stays small.
edytor/crdt/edytorhas no Svelte and no view code: a server route or Worker that reads and edits documents does not pull in the editor. - One engine. Never add the
yjspackage next to Edytor: it is a second, incompatible engine.
Choosing an entry
- Rendering an editor:
edytor. - Reading, converting or editing a document in Node, a SvelteKit server route or a Worker:
edytor/crdt/edytor. - Handling raw updates, or passing the engine to
bindCrdt:edytor/crdt. - Hosting collaboration on Cloudflare:
edytor/cloudflare. - Notion’s look for the document:
import 'edytor/themes/notion.css'.