@durable-streams/y-durable-streams
Version:
Yjs provider for Durable Streams - sync Yjs documents over append-only streams
179 lines (134 loc) • 4.58 kB
Markdown
---
name: yjs-getting-started
description: >
First-time setup for @durable-streams/y-durable-streams. Install peer deps,
start dev servers (DurableStreamTestServer + YjsServer), create a collaborative
Y.Doc, connect with YjsProvider, verify sync, add awareness for presence.
Load when setting up Yjs collaborative editing for the first time.
type: lifecycle
library: durable-streams
library_version: "0.2.3"
sources:
- "durable-streams/durable-streams:packages/y-durable-streams/src/yjs-provider.ts"
- "durable-streams/durable-streams:packages/y-durable-streams/src/server/yjs-server.ts"
- "durable-streams/durable-streams:packages/y-durable-streams/README.md"
---
# Durable Streams — Yjs Getting Started
Sync Yjs documents over HTTP durable streams. No WebSocket infrastructure
needed — uses standard HTTP with SSE or long-poll transport.
## Install
```bash
npm install @durable-streams/y-durable-streams yjs y-protocols lib0
```
`yjs`, `y-protocols`, and `lib0` are peer dependencies — missing them causes
runtime import errors.
For the dev server (not needed if using Electric Cloud):
```bash
npm install -D @durable-streams/server
```
## Start dev servers
Two servers are needed: a Durable Streams storage server and a Yjs protocol
server that sits in front of it.
```typescript
import { DurableStreamTestServer } from "@durable-streams/server"
import { YjsServer } from "@durable-streams/y-durable-streams/server"
// 1. Storage server
const dsServer = new DurableStreamTestServer({ port: 4437 })
await dsServer.start()
// 2. Yjs protocol server (proxies to storage server)
const yjsServer = new YjsServer({
port: 4438,
dsServerUrl: `http://localhost:4437`,
})
await yjsServer.start()
console.log(`Yjs server ready at http://localhost:4438`)
```
## Create a collaborative document
```typescript
import { YjsProvider } from "@durable-streams/y-durable-streams"
import * as Y from "yjs"
const doc = new Y.Doc()
const provider = new YjsProvider({
doc,
baseUrl: "http://localhost:4438/v1/yjs/my-service",
docId: "my-doc",
})
provider.on("synced", (synced) => {
if (synced) {
console.log("Document synced with server")
// Edit the document — changes sync automatically
doc.getText("content").insert(0, "Hello from Yjs!")
}
})
```
`baseUrl` is the service root. The provider builds URLs as
`{baseUrl}/docs/{docId}` internally — do not include `/docs/` in baseUrl.
## Add presence
```typescript
import { Awareness } from "y-protocols/awareness"
const awareness = new Awareness(doc)
awareness.setLocalStateField("user", {
name: "Alice",
color: "#ff0000",
})
const provider = new YjsProvider({
doc,
baseUrl: "http://localhost:4438/v1/yjs/my-service",
docId: "my-doc",
awareness,
})
// Listen for remote users
awareness.on("change", () => {
const users = Array.from(awareness.getStates().values())
.filter((s) => s?.user)
.map((s) => s.user.name)
console.log("Online:", users)
})
```
Use `setLocalStateField("user", ...)` (merges) not `setLocalState(...)` (replaces).
`setLocalState` overwrites all awareness fields, breaking cursor tracking or
other awareness data set by editor bindings.
## Common Mistakes
### CRITICAL Missing peer dependencies
Wrong:
```bash
npm install @durable-streams/y-durable-streams
```
Correct:
```bash
npm install @durable-streams/y-durable-streams yjs y-protocols lib0
```
Source: packages/y-durable-streams/package.json peerDependencies
### HIGH Including `/docs/` in baseUrl
Wrong:
```typescript
new YjsProvider({
doc,
baseUrl: "http://localhost:4438/v1/yjs/my-service/docs/my-doc",
docId: "my-doc",
})
```
Correct:
```typescript
new YjsProvider({
doc,
baseUrl: "http://localhost:4438/v1/yjs/my-service",
docId: "my-doc",
})
```
The provider appends `/docs/{docId}` internally. Doubling `/docs/` produces 404s.
Source: packages/y-durable-streams/src/yjs-provider.ts docUrl()
### HIGH Starting YjsServer without a backing DS server
```typescript
// This will fail — YjsServer needs a running DS server
const yjsServer = new YjsServer({
port: 4438,
dsServerUrl: "http://localhost:4437", // Must be running first
})
```
YjsServer proxies all storage operations to the DS server. Start
`DurableStreamTestServer` (or Caddy) before starting `YjsServer`.
## See also
- [yjs-editors](../yjs-editors/SKILL.md) — TipTap and CodeMirror integration
- [yjs-sync](../yjs-sync/SKILL.md) — Provider lifecycle, events, error recovery
- [yjs-server](../yjs-server/SKILL.md) — Production deployment with Caddy or Electric Cloud