From 10da01711d69c58b63e42fba2a1b16d42e6d9db6 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 9 Jul 2026 09:32:32 +0000 Subject: [PATCH] docs: add 0.6 migration guide, link from README Covers every breaking change since v0.5.4: required defineDevframe metadata fields, the anonymous: auth RPC renames + opt-in enforcement, WS origin allowlisting, zigpty replacing the node-pty peer, StartedServer.wss -> .ws, and the removed devframe/utils/human-id. Also fixes a stale StartedServer.wss reference in standalone-cli.md. --- README.md | 4 ++ docs/.vitepress/config.ts | 1 + docs/guide/migration-0.6.md | 103 +++++++++++++++++++++++++++++++++++ docs/guide/standalone-cli.md | 2 +- 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 docs/guide/migration-0.6.md diff --git a/README.md b/README.md index c505d82..4e2fd2a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Framework-neutral foundation for building devframes. Documentation: https://devfra.me/

+

+Upgrading from 0.5.x? See the 0.6 migration guide (source: docs/guide/migration-0.6.md). +

+ ## Sponsors

diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 0d72b6e..8b4aca2 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -33,6 +33,7 @@ function guideItems(prefix: string): DefaultTheme.NavItemWithLink[] { { text: 'Hub (multi-tool)', link: `${prefix}/guide/hub` }, { text: 'Client Scripts & Context', link: `${prefix}/guide/client-context` }, { text: 'Agent-Native (experimental)', link: `${prefix}/guide/agent-native` }, + { text: 'Migrating to 0.6', link: `${prefix}/guide/migration-0.6` }, ] } diff --git a/docs/guide/migration-0.6.md b/docs/guide/migration-0.6.md new file mode 100644 index 0000000..9343f34 --- /dev/null +++ b/docs/guide/migration-0.6.md @@ -0,0 +1,103 @@ +--- +outline: deep +--- + +# Migrating to 0.6 + +0.6 tightens `defineDevframe`'s metadata contract, replaces the terminal and WebSocket transports, and ships a ready-made authentication layer with real enforcement. This page covers every breaking change between 0.5.x and 0.6 and how to move past each one. + +## `defineDevframe` requires four more fields + +`version`, `packageName`, `homepage`, and `description` are now required alongside `id` and `name`. Source them from your own `package.json` so they stay in sync with what you publish: + +```ts +import pkg from '../package.json' with { type: 'json' } + +export default defineDevframe({ + id: 'my-devframe', + name: 'My Devframe', // display label + version: pkg.version, + packageName: pkg.name, // maps from package.json's `name` + homepage: pkg.homepage, + description: pkg.description, + setup(ctx) { /* … */ }, +}) +``` + +See [Devframe Definition](./devframe-definition#sourcing-metadata-from-package-json) for the full field reference, including the new optional `duplicationStrategy`. + +## Auth handshake methods are renamed + +The two pre-trust RPC methods moved under the `anonymous:` prefix so `isAnonymousRpcMethod` (the rule an authorization gate checks) covers them without a separate allowlist: + +| 0.5.x | 0.6 | +|-------|-----| +| `devframe:anonymous:auth` | `anonymous:devframe:auth` | +| `devframe:auth:exchange` | `anonymous:devframe:auth:exchange` | + +Calling through the client API (`rpc.requestTrustWithToken()`, `rpc.requestTrustWithCode()`) needs no change — only a custom node-side handler that registered these method names directly, or an `authorize` gate that pattern-matched on the old names, needs updating. + +## WebSocket connections now enforce origin and (optionally) trust + +Two independent gates landed on the RPC socket: + +- **Cross-origin upgrades are rejected by default.** Only loopback origins (`localhost`/`127.0.0.1`/`::1`) and requests with no `Origin` header (native, non-browser clients) are accepted. Reaching the tool from another host — a LAN address, a tunnel, a reverse proxy — needs an explicit allowlist: + + ```ts + await startHttpAndWs({ + context: ctx, + port: 9999, + allowedOrigins: ['https://my-tunnel.example.com'], + }) + ``` + + Pass `allowedOrigins: false` to disable the check entirely (not recommended). + +- **Real authorization enforcement is now available, opt-in.** `auth: true` (the default) keeps 0.5.x's behavior — every registered method stays callable regardless of trust. Passing a `DevframeAuthHandler` instead turns on the gate described in [Security](./security#the-pre-trust-gate): an untrusted caller can only reach `anonymous:`-prefixed methods, and everything else throws [`DF0036`](../errors/DF0036). The [Interactive Auth](/helpers/interactive-auth) recipe (`createInteractiveAuth`) builds one of these for you — a code/link banner, the handshake handlers, and the connect-time trust hook — so a host doesn't reimplement the protocol: + + ```ts + import { startHttpAndWs } from 'devframe/node' + import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' + + const auth = createInteractiveAuth(ctx) + const server = await startHttpAndWs({ context: ctx, port: 9999, auth }) + auth.printBanner() + ``` + +## Terminals run on `zigpty`, not the `node-pty` peer + +Interactive PTY sessions (`ctx.terminals.startPtySession()`) now spawn through [`zigpty`](https://github.com/pithings/zigpty)'s prebuilt native bindings, bundled with `@devframes/hub` — there's no more optional `node-pty` peer dependency to install. Drop it from your own `package.json` if you added it for terminal support; where `zigpty`'s bindings can't load for a platform, sessions degrade to pipe-based emulation automatically. + +## `StartedServer.wss` is now `StartedServer.ws` + +The RPC socket transport moved from `ws` to [`crossws`](https://crossws.unjs.io/), so the handle `startHttpAndWs`/`createDevServer` return changed shape: + +```ts +// 0.5.x +const server = await startHttpAndWs({ context: ctx, port: 9999 }) +server.wss.clients // ws.WebSocketServer + +// 0.6 +const server = await startHttpAndWs({ context: ctx, port: 9999 }) +server.ws // crossws NodeAdapter +``` + +If you only read `server.close()`, `.origin`, `.port`, or `.rpcGroup`, nothing else changes. Code that reached into `.wss` for the raw `ws` server needs the equivalent `crossws` `NodeAdapter` API instead. + +## `devframe/utils/human-id` is gone + +The human-readable ID generator was removed with no direct replacement. Use `devframe/utils/nanoid` for a short random ID, or `devframe/utils/crypto-token`'s `randomToken()` / `randomDigits()` for anything security-sensitive (bearer tokens, one-time codes): + +```ts +// 0.5.x +import { humanId } from 'devframe/utils/human-id' + +humanId() // 'bright-orange-tiger' +``` + +```ts +// 0.6 +import { nanoid } from 'devframe/utils/nanoid' + +nanoid() // short URL-safe ID, no word-list dependency +``` diff --git a/docs/guide/standalone-cli.md b/docs/guide/standalone-cli.md index c003ca8..fc1cff6 100644 --- a/docs/guide/standalone-cli.md +++ b/docs/guide/standalone-cli.md @@ -340,7 +340,7 @@ program await program.parseAsync() ``` -`createDevServer` returns the underlying `StartedServer` handle (`origin`, `port`, `app`, `wss`, `rpcGroup`, `close()`) so the surrounding program can drive graceful shutdown — SIGINT, hot reload, integration tests. +`createDevServer` returns the underlying `StartedServer` handle (`origin`, `port`, `app`, `ws`, `rpcGroup`, `connectionMeta()`, `close()`) so the surrounding program can drive graceful shutdown — SIGINT, hot reload, integration tests. For typed flag schemas, `parseCliFlags(schema, rawBag)` (from `devframe/adapters/cli`) validates a commander/yargs flag bag against a `CliFlagsSchema` (the same `defineCliFlags(...)` value you'd put on `cli.flags`). Typed-schema validation works with any CLI framework.