@durable-streams/y-durable-streams

中文文档
0.2.9发布于 2026/09/11Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 1.4万

Yjs provider for Durable Streams - sync Yjs documents over append-only streams

原始使用文档
文档目录22 节
  1. Overview
  2. Installation
  3. Quick Start
  4. Usage
  5. Document Only (No Presence)
  6. With Authentication
  7. Manual Connection
  8. Event Handling
  9. Cleanup
  10. API
  11. YjsProvider
  12. Options
  13. Server
  14. Snapshot webhooks
  15. Conformance Tests
  16. Server Protocol API
  17. Base URL Structure
  18. Key Operations
  19. Compaction
  20. Error Responses
  21. How It Works
  22. License

@durable-streams/y-durable-streams

Yjs provider for Durable Streams - sync Yjs documents over HTTP with automatic server-side compaction and optional awareness (presence) support.

Overview

This package provides a Yjs provider that syncs documents using the Yjs Durable Streams Protocol. Unlike WebSocket-based providers, it uses standard HTTP (SSE by default, with long-polling as an alternative) plus automatic server-side compaction, making it simpler to deploy and scale.

Key benefits:

  • No WebSocket infrastructure - Works with standard HTTP load balancers and CDNs
  • Automatic compaction - Server manages document snapshots to keep sync fast
  • Snapshot webhooks - Wake external workers to persist the latest snapshot
  • Scalable - Stateless server design, documents stored in durable streams
  • Presence support - Optional awareness for cursors, selections, and user status

Installation

npm install @durable-streams/y-durable-streams yjs y-protocols lib0

Quick Start

import { YjsProvider } from "@durable-streams/y-durable-streams"
import * as Y from "yjs"
import { Awareness } from "y-protocols/awareness"

const doc = new Y.Doc()
const awareness = new Awareness(doc)

const provider = new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-document",
  awareness,
})

provider.on("synced", (synced) => {
  console.log("Synced:", synced)
})

Usage

Document Only (No Presence)

const provider = new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-document",
})

With Authentication

const provider = new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-document",
  awareness,
  headers: {
    Authorization: "Bearer your-token",
  },
})

Manual Connection

const provider = new YjsProvider({
  doc,
  baseUrl,
  docId,
  connect: false, // Don't connect automatically
})

// Set up listeners first
provider.on("synced", handleSync)
provider.on("error", handleError)

// Then connect
await provider.connect()

Event Handling

// Sync state changes
provider.on("synced", (synced: boolean) => {
  if (synced) {
    console.log("Document is synced with server")
  }
})

// Connection status changes
provider.on("status", (status: YjsProviderStatus) => {
  console.log("Status:", status) // "disconnected" | "connecting" | "connected"
})

// Error handling
provider.on("error", (error: Error) => {
  console.error("Provider error:", error)
})

Cleanup

// Disconnect temporarily
provider.disconnect()

// Reconnect
await provider.connect()

// Destroy permanently
provider.destroy()

API

YjsProvider

class YjsProvider {
  constructor(options: YjsProviderOptions)

  // Properties
  readonly doc: Y.Doc
  readonly synced: boolean
  readonly connected: boolean
  readonly connecting: boolean

  // Methods
  connect(): Promise<void>
  disconnect(): Promise<void>
  destroy(): void

  // Events
  on(event: "synced", handler: (synced: boolean) => void): void
  on(event: "status", handler: (status: YjsProviderStatus) => void): void
  on(event: "error", handler: (error: Error) => void): void
}

Options

interface YjsProviderOptions {
  doc: Y.Doc
  baseUrl: string // Yjs server URL, e.g. "http://localhost:4438/v1/yjs/my-service"
  docId: string // Document identifier (may contain forward slashes)
  awareness?: Awareness // Optional awareness for presence
  headers?: HeadersRecord // Optional auth headers (static strings or () => string)
  liveMode?: "sse" | "long-poll" // Live update transport (default: "sse")
  connect?: boolean // Auto-connect on construction (default: true)
}

Server

The package includes a Yjs server that implements the protocol. For development/testing:

import { YjsServer } from "@durable-streams/y-durable-streams/server"

const server = new YjsServer({
  port: 4438,
  dsServerUrl: "http://localhost:4437", // Durable streams server
})

await server.start()
console.log(`Yjs server running at ${server.url}`)

Snapshot webhooks

Subscribe a webhook to be woken whenever a newer snapshot is available for a matching document:

await fetch(
  `${server.url}/v1/yjs/my-service/__ds/subscriptions/snapshot-archive`,
  {
    method: "PUT",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      type: "webhook",
      events: ["snapshot.available"],
      document_pattern: "projects/**",
      webhook: { url: "https://archive.example/hooks/yjs" },
      lease_ttl_ms: 30_000,
    }),
  }
)

document_pattern is relative to the service's document namespace. * matches one path segment and ** matches recursively. The underlying Durable Streams server must support webhook subscriptions.

Webhook requests use the standard Durable Streams subscription payload and signature. A notification means one or more newer snapshots are available; it does not carry the snapshot bytes and may coalesce multiple compactions. For each pending .index stream, derive the document path and fetch its latest snapshot with ?offset=snapshot. Return { "done": true } only after the snapshot has been persisted successfully. New subscriptions observe future snapshots and do not replay the snapshot that was current when they were created.

Conformance Tests

The package includes conformance tests to verify Yjs server implementations. By default, tests run against local test servers. To test against an external server:

# Run tests against an external Yjs server
YJS_CONFORMANCE_URL=http://localhost:4438/v1/yjs/test pnpm vitest run --project y-durable-streams

# Run tests with local test servers (default)
pnpm vitest run --project y-durable-streams

Note: The "Server Restart" test is skipped when using an external URL since it requires starting/stopping local servers.

Server Protocol API

For the complete protocol specification, see YJS-PROTOCOL.md.

Base URL Structure

Each document is accessed via a single URL with query parameters:

{baseUrl}/docs/{docPath}?{queryParams}

Where:

  • baseUrl is typically http://host:port/v1/yjs/{service}
  • docPath can include forward slashes (e.g., project/chapter-1)

Key Operations

Snapshot Discovery

GET {baseUrl}/docs/{docPath}?offset=snapshot

Returns a 307 redirect to either:

  • ?offset={N}_snapshot if a snapshot exists
  • ?offset=-1 if no snapshot (read from beginning)

Read Snapshot

GET {baseUrl}/docs/{docPath}?offset={N}_snapshot

Returns binary Yjs snapshot with stream-next-offset header indicating where to continue reading updates.

Read/Write Updates

GET  {baseUrl}/docs/{docPath}?offset={N}&live=true
POST {baseUrl}/docs/{docPath}
  • Read: Get updates from offset, optionally with live=true for long-polling
  • Write: POST raw Yjs update bytes (server handles lib0 framing)

Awareness (Presence)

GET  {baseUrl}/docs/{docPath}?awareness=default&offset=now&live=true
POST {baseUrl}/docs/{docPath}?awareness=default

Named awareness streams via query parameter. Uses SSE for real-time delivery.

Compaction

The server automatically compacts documents when updates exceed a threshold:

  1. Read current state (snapshot + updates)
  2. Create new snapshot at current offset
  3. Update internal index stream
  4. Delete old snapshot

Compaction is transparent to clients - existing connections continue uninterrupted.

Error Responses

StatusCodeMeaning
400INVALID_REQUESTInvalid path or offset
401UNAUTHORIZEDMissing/invalid auth
404SNAPSHOT_NOT_FOUNDSnapshot deleted (retry)
404DOCUMENT_NOT_FOUNDDocument doesn't exist
410OFFSET_EXPIREDOffset too old

How It Works

The provider connects to a Yjs server which manages document storage using durable streams:

  1. Snapshot Discovery - Client requests ?offset=snapshot, server redirects to current snapshot or beginning
  2. Snapshot Loading - Binary Yjs state with stream-next-offset header for where to continue
  3. Live Updates - Long-poll for incremental updates from the offset
  4. Awareness - Optional SSE stream for presence (cursors, selections, user info)

The server automatically compacts documents when updates exceed a threshold, creating new snapshots. This keeps initial sync fast for new clients. The protocol uses a single URL per document with query parameters for different operations.

License

Apache-2.0

版本与发布记录

@durable-streams/y-durable-streams 共发布 12 个版本,首次发布于 2026/01/09;过去 12 个月发布了 12 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.9latest2026/09/112 个月前
0.2.82026/07/173 个月前
0.2.72026/06/015 个月前
0.2.62026/05/285 个月前
0.2.52026/05/195 个月前
0.2.42026/04/137 个月前

关于 @durable-streams/y-durable-streams 的常见问题

@durable-streams/y-durable-streams 是什么?

Yjs provider for Durable Streams - sync Yjs documents over append-only streams

如何安装 @durable-streams/y-durable-streams?

在项目目录运行 npm install @durable-streams/y-durable-streams,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:lib0(^0.2.0)、y-protocols(^1.0.0)、yjs(^13.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。它还提供命令行工具 intent,可以用 npx intent 直接运行。

@durable-streams/y-durable-streams 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@durable-streams/y-durable-streams 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@durable-streams/y-durable-streams 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@durable-streams/y-durable-streams 可以商用吗?

@durable-streams/y-durable-streams 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@durable-streams/y-durable-streams 的下载量有多少?

根据 npm 官方下载统计,@durable-streams/y-durable-streams 在 2026/10/13 – 2026/11/11 这 30 天内被下载 13,715 次,日均约 457 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@durable-streams/y-durable-streams 还在维护吗?

最新版本 0.2.9 发布于 2026/09/11(2 个月前);至今共发布 12 个版本,其中过去 12 个月发布了 12 个;首次发布于 2026/01/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。