|
| 1 | +--- |
| 2 | +outline: deep |
| 3 | +--- |
| 4 | + |
| 5 | +# Migrating to 0.6 |
| 6 | + |
| 7 | +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. |
| 8 | + |
| 9 | +## `defineDevframe` requires four more fields |
| 10 | + |
| 11 | +`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: |
| 12 | + |
| 13 | +```ts |
| 14 | +import pkg from '../package.json' with { type: 'json' } |
| 15 | + |
| 16 | +export default defineDevframe({ |
| 17 | + id: 'my-devframe', |
| 18 | + name: 'My Devframe', // display label |
| 19 | + version: pkg.version, |
| 20 | + packageName: pkg.name, // maps from package.json's `name` |
| 21 | + homepage: pkg.homepage, |
| 22 | + description: pkg.description, |
| 23 | + setup(ctx) { /* … */ }, |
| 24 | +}) |
| 25 | +``` |
| 26 | + |
| 27 | +See [Devframe Definition](./devframe-definition#sourcing-metadata-from-package-json) for the full field reference, including the new optional `duplicationStrategy`. |
| 28 | + |
| 29 | +## Auth handshake methods are renamed |
| 30 | + |
| 31 | +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: |
| 32 | + |
| 33 | +| 0.5.x | 0.6 | |
| 34 | +|-------|-----| |
| 35 | +| `devframe:anonymous:auth` | `anonymous:devframe:auth` | |
| 36 | +| `devframe:auth:exchange` | `anonymous:devframe:auth:exchange` | |
| 37 | + |
| 38 | +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. |
| 39 | + |
| 40 | +## WebSocket connections now enforce origin and (optionally) trust |
| 41 | + |
| 42 | +Two independent gates landed on the RPC socket: |
| 43 | + |
| 44 | +- **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: |
| 45 | + |
| 46 | + ```ts |
| 47 | + await startHttpAndWs({ |
| 48 | + context: ctx, |
| 49 | + port: 9999, |
| 50 | + allowedOrigins: ['https://my-tunnel.example.com'], |
| 51 | + }) |
| 52 | + ``` |
| 53 | + |
| 54 | + Pass `allowedOrigins: false` to disable the check entirely (not recommended). |
| 55 | + |
| 56 | +- **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: |
| 57 | + |
| 58 | + ```ts |
| 59 | + import { startHttpAndWs } from 'devframe/node' |
| 60 | + import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' |
| 61 | + |
| 62 | + const auth = createInteractiveAuth(ctx) |
| 63 | + const server = await startHttpAndWs({ context: ctx, port: 9999, auth }) |
| 64 | + auth.printBanner() |
| 65 | + ``` |
| 66 | + |
| 67 | +## Terminals run on `zigpty`, not the `node-pty` peer |
| 68 | + |
| 69 | +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. |
| 70 | + |
| 71 | +## `StartedServer.wss` is now `StartedServer.ws` |
| 72 | + |
| 73 | +The RPC socket transport moved from `ws` to [`crossws`](https://crossws.unjs.io/), so the handle `startHttpAndWs`/`createDevServer` return changed shape: |
| 74 | + |
| 75 | +```ts |
| 76 | +// 0.5.x |
| 77 | +const server = await startHttpAndWs({ context: ctx, port: 9999 }) |
| 78 | +server.wss.clients // ws.WebSocketServer |
| 79 | + |
| 80 | +// 0.6 |
| 81 | +const server = await startHttpAndWs({ context: ctx, port: 9999 }) |
| 82 | +server.ws // crossws NodeAdapter |
| 83 | +``` |
| 84 | + |
| 85 | +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. |
| 86 | + |
| 87 | +## `devframe/utils/human-id` is gone |
| 88 | + |
| 89 | +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): |
| 90 | + |
| 91 | +```ts |
| 92 | +// 0.5.x |
| 93 | +import { humanId } from 'devframe/utils/human-id' |
| 94 | + |
| 95 | +humanId() // 'bright-orange-tiger' |
| 96 | +``` |
| 97 | + |
| 98 | +```ts |
| 99 | +// 0.6 |
| 100 | +import { nanoid } from 'devframe/utils/nanoid' |
| 101 | + |
| 102 | +nanoid() // short URL-safe ID, no word-list dependency |
| 103 | +``` |
0 commit comments