@pedit/serve

中文文档
0.4.0发布于 2026/11/02MITTypeScriptES Module构建来源已验证

Run pedit serve for a local app: the file's Yjs document over a Unix socket, with Hono routes and a browser client

原始使用文档
文档目录7 节
  1. Requirements
  2. Install
  3. Server
  4. Browser
  5. API
  6. Security model
  7. Known limits

@pedit/serve

Run pedit serve for a local app. pedit holds one file's Yjs document and writes the file; this package starts it, checks every request, and bridges a browser's WebSocket to pedit's Unix socket. Your page edits the file live, with several pages at once, and there is no room, relay or account.

Experimental (0.x): the API may change. The package is published with every pedit release and carries the same version number; the pedit it needs is listed below.

Requirements

  • pedit 0.4.0 or later on the PATH (or pass bin). Older ones are refused with a message on how to update.
  • Node 22 or later, on macOS or Linux (Unix sockets; not Windows).

Install

npm install @pedit/serve yjs y-protocols y-websocket   # the browser client's peers
npm install hono @hono/node-server @hono/node-ws       # for the Hono routes

@pedit/serve/client needs yjs, y-protocols and y-websocket; @pedit/serve/hono needs hono. They are peers, so your app keeps one copy of Yjs.

Server

import { serve } from '@hono/node-server'
import { createNodeWebSocket } from '@hono/node-ws'
import { peditRoutes } from '@pedit/serve/hono'
import { Hono } from 'hono'

const app = new Hono()
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app })
const server = serve({ fetch: app.fetch, port: 3000, hostname: '127.0.0.1' })
const routes = peditRoutes({
  upgradeWebSocket,
  root: '/home/me/notes', // only files under it are served
  origins: ['http://127.0.0.1:3000'],
  app: 'my-app',
  resolve: async (id) => (id === 'todo' ? { path: '/home/me/notes/todo.md', role: 'edit' } : null),
})
app.route('/edit', routes)
injectWebSocket(server)
process.on('SIGINT', () => routes.close().finally(() => process.exit(0)))

Browser

import { connect } from '@pedit/serve/client'
import { yCollab } from 'y-codemirror.next'

const conn = await connect('/edit', 'todo', { name: 'Ann' })
conn.status.subscribe((status, error) => {
  if (error?.code === 'gone') showReload() // your UI
})
const extensions = [yCollab(conn.text, conn.awareness)] // plus basicSetup, EditorState.readOnly for 'read'

API

@pedit/serve/hono

Export
peditRoutes(options)A Hono app: POST /:id/session and the WebSocket GET /:id/doc. Has close().
options.resolve(id, c)Maps an id to { path, role: 'edit' | 'read' }, or null for 404.
options.root, origins, appThe served directory, the exact page origins, and a label shown if another process holds the file.
options.bin, idleMs, allowRemote, onEventAbsolute path to pedit; idle stop (default 60 s); accept non-loopback peers (default false); started/stopped/error events.

@pedit/serve/client

Export
connect(base, id, { name, color })Resolves after the first sync with { doc, text, awareness, role, status, synced, destroy }.
conn.statusget() and subscribe(cb); states connecting, connected, reconnecting, closed.
PeditError.codenot-found, held, busy, forbidden, gone, unavailable.

@pedit/serve

Export
ServedFilesThe layer below the routes: acquire(path) starts or reuses a child, close() ends all.
resolvePedit({ bin }), MIN_PEDIT_VERSIONFinds pedit, checks the binary and its version.
HeldError, LimitError, NoPeditErrorAnother process serves the file; 32 files or 8 clients; pedit missing or too old.

Security model

  • One hook, resolve, decides which ids exist and their role. Every other request is refused by default.
  • Files must be under root (realpath checked); ids are [A-Za-z0-9_-] only.
  • Host and Origin must match origins, and peers must be on loopback unless allowRemote is set.
  • A session token is single use and expires in 60 s; it travels in the WebSocket URL, so log no token.
  • A read role is enforced by pedit itself, not just by the page: updates from a reader close the socket.
  • The browser never sees a path, a pid or a socket name.

Known limits

  • Unix only; one id is one file; at most 32 files and 8 clients per file.
  • Awareness (names, cursors) is unauthenticated: any connected page can claim any name.
  • gone: pedit's saved state was discarded, so the page's copy cannot merge into the new document. The client stops; the app decides whether to offer the text or reload.
  • Don't write the file yourself while a page is connected.

Design: docs/design/serve.md. Sample: examples/serve-app. MIT license.

版本与发布记录

@pedit/serve 共发布 3 个版本,首次发布于 2026/11/02;过去 12 个月发布了 3 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.0latest2026/11/021 天前
0.1.02026/11/021 天前
0.0.0-stage2026/11/021 天前

关于 @pedit/serve 的常见问题

@pedit/serve 是什么?

为本地应用程序运行pedit serve:文件的Yjs文档通过Unix套接字,使用Hono路由和浏览器客户端

如何安装 @pedit/serve?

在项目目录运行 npm install @pedit/serve,或使用 pnpm add / yarn add / bun add。

@pedit/serve 支持 TypeScript 吗?

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

@pedit/serve 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@pedit/serve 需要什么版本的 Node.js?

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

@pedit/serve 可以商用吗?

@pedit/serve 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@pedit/serve 还在维护吗?

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