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

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, attachDocument and the EdytorDocument class. 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 (sideEffects lists 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 import codePlugin.
  • The engine is pruned. edytor/crdt is 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 imports edytor/crdt itself 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/edytor has 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 yjs package 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'.

Was this page helpful?