Skip to content

Commit 81fd1be

Browse files
antfubotantfu
andauthored
docs: regulate the terminology with a canonical Terms page (#298)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent 22510b1 commit 81fd1be

181 files changed

Lines changed: 1129 additions & 969 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 28 additions & 13 deletions
Large diffs are not rendered by default.

docs/app/app.config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default defineAppConfig({
2222
sections: ['adapters', 'frameworks', 'helpers'],
2323
},
2424
{ label: 'Plugins', sections: ['plugins'], link: 'section' as const },
25+
{ label: 'Reference', sections: ['references'], link: 'section' as const },
2526
{ label: 'Errors', sections: ['errors'], link: 'section' as const },
2627
{
2728
label: `v${devframePkg.version}`,
@@ -87,7 +88,6 @@ export default defineAppConfig({
8788
'/guide/scoped-context',
8889
'/guide/json-render',
8990
'/guide/diagnostics',
90-
'/guide/when-clauses',
9191
],
9292
},
9393
{
@@ -110,7 +110,6 @@ export default defineAppConfig({
110110
'/guide/hub-initiate',
111111
'/guide/services',
112112
'/guide/deep-linking',
113-
'/guide/events',
114113
],
115114
},
116115
{
@@ -171,7 +170,7 @@ export default defineAppConfig({
171170
{
172171
category: 'Hub',
173172
items: [
174-
'How do I compose multiple integrations into a hub?',
173+
'How do I compose multiple devframes into a hub?',
175174
'How do I build my own hub UI on top of the hub protocol?',
176175
],
177176
},

docs/content/1.guide/1.tutorial-server-data-inspector.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
---
22
title: 'Tutorial: Build a Server Data Inspector'
3-
description: 'Build a devtool that displays and queries live server-side data, then ship it as a hub dock, a static build, a standalone server, and a CLI.'
3+
description: 'Build a devtool that displays and queries live server-side data, then ship it as a hub dock entry, a static build, a standalone dev server, and a CLI.'
44
---
55

6-
Let's build a real devtool from scratch: a **Data Inspector** that shows the shape of your server's live state and lets you read any value out of it. We'll get it working first, then teach it new tricks one at a time: a dock in a hub, a static build, a standalone server, and a CLI.
6+
Let's build a real devtool from scratch: a **Data Inspector** that shows the shape of live server-side state and lets you read any value out of it. We'll get it working first, then teach it new tricks one at a time: a dock entry in a hub, a static build, a standalone dev server, and a CLI.
77

88
You'll need [Node 24+](https://nodejs.org/) and a terminal. Every code block is complete, so you can copy them as you go.
99

10-
## The shape of a devframe app
10+
## The shape of a devframe
1111

12-
A devframe app is two halves talking over a typed connection: a **server** in your Node process that exposes functions, and a **browser** client that calls them and renders the results. Devframe is everything in between: the wire, the UI hosting, auth, builds, and a CLI.
12+
A devframe is two halves talking over a typed connection: the **node side** exposes functions, and the **browser side** calls them and renders the results. Devframe is everything in between: the wire, the UI hosting, auth, builds, and a CLI.
1313

1414
## Step 1 — Define the tool
1515

@@ -24,8 +24,8 @@ npm install devframe && npm install -D typescript
2424
```ts [src/data-inspector.ts]
2525
import { defineDevframe } from 'devframe'
2626

27-
// Some example server-side data — whatever you want to peek at while your app
28-
// runs: config, a cache, a DB handle.
27+
// Some example server-side data — whatever you want to peek at while your
28+
// user app runs: config, a cache, a DB handle.
2929
const serverState = {
3030
config: { name: 'Acme', port: 3000, debug: false },
3131
users: [
@@ -82,11 +82,11 @@ const dataInspectorFrame = defineDevframe({
8282
export default dataInspectorFrame
8383
```
8484

85-
`ctx.rpc.register` publishes a function the browser can call: a namespaced `name`, a `type` (`query` is read-only), and a `handler` that takes the call's arguments and returns JSON. That's the whole server. ([RPC](/guide/rpc) has the other types; [Devframe Definition](/guide/devframe-definition) has every field.)
85+
`ctx.rpc.register` publishes a function the browser side can call: a namespaced `name`, a `type` (`query` is read-only), and a `handler` that takes the call's arguments and returns JSON. That's the whole node side. ([RPC](/guide/rpc) has the other types; [Devframe Definition](/guide/devframe-definition) has every field.)
8686

8787
## Step 2 — Add a UI
8888

89-
Now the browser half. We'll use React here, but any framework works — the only devframe-specific line is `connectDevframe`, which opens the connection back to the server.
89+
Now the browser side. We'll use React here, but any framework works — the only devframe-specific line is `connectDevframe`, which opens the connection back to the node side.
9090

9191
```sh
9292
npm install react react-dom @devframes/vite
@@ -128,8 +128,8 @@ export function App() {
128128
const [result, setResult] = useState<unknown>()
129129

130130
useEffect(() => {
131-
// No argument: the client finds the server from the page's own URL, so
132-
// this line never changes no matter how the tool is hosted.
131+
// No argument: the RPC client finds the node side from the page's own
132+
// URL, so this line never changes no matter how the tool is hosted.
133133
connectDevframe().then(async (client) => {
134134
setRpc(client)
135135
const call = client.call as (name: string, ...args: unknown[]) => Promise<any>
@@ -194,7 +194,7 @@ export default defineConfig({
194194
npx vite --config vite.client.config.ts
195195
```
196196

197-
Open the printed URL. The three keys and their types show up, and typing `config.port` or `users.0.name` and hitting **Query** prints the value. Button → `call` → your `handler` → back to the page: that's the whole app working.
197+
Open the printed URL. The three keys and their types show up, and typing `config.port` or `users.0.name` and hitting **Query** prints the value. Button → `call` → your `handler` → back to the page: that's the whole devframe working.
198198

199199
> [!WARNING]
200200
> `auth: false` trusts anything that can reach the port. It's off here to keep the tutorial simple — turn it on for anything you publish or expose beyond localhost. See [Security](/guide/security).
@@ -203,7 +203,7 @@ From here on we reuse this same `src/data-inspector.ts` and `client/` unchanged;
203203

204204
## Step 4 — Dock it in a hub
205205

206-
A [hub](/guide/hub) puts many devframes behind one interface, each a **dock** you switch between — the tool's own UI in an iframe. Since our client uses a bare `connectDevframe()`, it already works anywhere; the hub just needs the built UI, so point the definition at it:
206+
A [hub](/guide/hub) puts many devframes behind one interface, each a **dock entry** you switch between — the tool's own UI in an iframe. Since our SPA uses a bare `connectDevframe()`, it already works anywhere; the hub just needs the built UI, so point the definition at it:
207207

208208
```ts [src/data-inspector.ts]
209209
import { fileURLToPath } from 'node:url'
@@ -243,11 +243,11 @@ export default defineConfig({
243243
npx vite --config vite.hub.config.ts
244244
```
245245

246-
Your inspector now sits in the hub's rail as a dock. Add more to `devframes: [...]` — your own or the [built-in plugins](/plugins) — and each gets its own. (The hub prints a code to authorize on first connect.)
246+
Your inspector now sits in the hub's dock rail as a dock entry. Add more to `devframes: [...]` — your own or the [built-in devframes](/plugins) — and each gets its own. (The hub prints a code to authorize on first connect.)
247247

248248
## Step 5 — Build a static version
249249

250-
Some tools should work with no server at all — a report you can drop on any static host. `createBuild` renders the UI and **bakes in** the results of read-only calls. Opt one in with `snapshot: true`:
250+
Some tools should work with no node side at all — a report you can drop on any static hosting. `createBuild` renders the UI and **bakes in** the results of read-only calls. Opt one in with `snapshot: true`:
251251

252252
```ts
253253
ctx.rpc.register({
@@ -273,7 +273,7 @@ npx vite build # refresh dist/client
273273
node scripts/build.mjs # → dist-static/
274274
```
275275

276-
Serve `dist-static/` anywhere and the meta list renders from the baked snapshot, no Node in sight. `query` takes an argument, so it still needs the live server (next) — or you can bake specific inputs ([Client Assets](/guide/client-assets)).
276+
Serve `dist-static/` anywhere and the meta list renders from the baked snapshot, no Node in sight. `query` takes an argument, so it still needs the live node side (next) — or you can bake specific inputs ([Client Assets](/guide/client-assets)).
277277

278278
## Step 6 — Run it standalone
279279

@@ -295,7 +295,7 @@ Same UI, same live calls, no bundler in the loop — this is what you'd drop int
295295

296296
## Step 7 — Give it a CLI
297297

298-
Finally, wrap that server in a command shell. `devframe/adapters/cac` turns a devframe into a CLI with `dev`, `build`, and `mcp` commands:
298+
Finally, wrap that dev server in a CLI. `devframe/adapters/cac` turns a devframe into a CLI with `dev`, `build`, and `mcp` commands:
299299

300300
```js [bin.mjs]
301301
#!/usr/bin/env node
@@ -308,14 +308,14 @@ createCac(dataInspectorFrame).parse()
308308
```sh
309309
npm pkg set bin.data-inspector=bin.mjs
310310

311-
node bin.mjs dev # the standalone server from Step 6
311+
node bin.mjs dev # the standalone dev server from Step 6
312312
node bin.mjs build # the static build from Step 5
313313
node bin.mjs mcp # expose the tool to a coding agent over MCP
314314
```
315315

316316
You can also assemble your own CLI from the adapter functions used above.
317317

318-
That's it for this tutorial. For a full-featured version, there's a ready-to-use [Data Inspector plugin](/plugins/data-inspector) to use or read for reference.
318+
That's it for this tutorial. For a full-featured version, there's a ready-to-use [Data Inspector built-in devframe](/plugins/data-inspector) to use or read for reference.
319319

320320
## What's next
321321

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ defineDevframe({
131131

132132
Call `connectDevframe()` in a Client Component — see [Client](/guide/client) and [`examples/next-runtime-snapshot`](https://github.com/devframes/devframe/tree/main/examples/next-runtime-snapshot).
133133

134-
## Connecting from the client
134+
## Connecting from the browser side
135135

136136
With the Nuxt helper, use `$rpc`:
137137

@@ -207,7 +207,7 @@ It's the no-args fallback for any deployed `rpc.call('my-tool:get-payload', …)
207207

208208
## On-disk caching
209209

210-
Persistence is the app's job ([`unstorage`](https://unstorage.unjs.io/) recommended); keep cache paths under `node_modules/.cache/<your-devtool-id>/` to rotate with `pnpm install`.
210+
Persistence is your tool's job ([`unstorage`](https://unstorage.unjs.io/) recommended); keep cache paths under `node_modules/.cache/<your-devtool-id>/` to rotate with `pnpm install`.
211211

212212
```ts
213213
import { resolve } from 'pathe'
@@ -238,7 +238,7 @@ defineDevframe({
238238

239239
## Live-reload on config changes
240240

241-
Filesystem watching is the app's job — wire chokidar, signal the client via shared state.
241+
Filesystem watching is your tool's job — wire chokidar, signal the browser side via shared state.
242242

243243
```ts [src/cli.ts]
244244
defineDevframe({
@@ -267,7 +267,7 @@ defineDevframe({
267267
})
268268
```
269269

270-
On the client:
270+
On the browser side:
271271

272272
```ts
273273
const my = (await connectDevframe()).scope('my-tool')
Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
title: 'Client'
3-
description: 'The browser client connects any surface — dock iframe, remote page, standalone SPA — to the Devframe server with type-safe RPC, shared state, and a trust handshake.'
3+
description: 'The RPC client connects any surface — dock iframe, remote page, standalone SPA — to a devframe''s node side with type-safe RPC, shared state, and a trust handshake.'
44
---
55

6-
The browser client connects any surface — dock iframe, remote page, standalone SPA — to the Devframe server with type-safe RPC, shared state, and a trust handshake.
6+
The RPC client connects any surface — dock iframe, remote page, standalone SPA — to a devframe's node side with type-safe RPC, shared state, and a trust handshake.
77

88
## Connecting
99

@@ -25,7 +25,7 @@ One SPA artifact serves at `/`, `/__<id>/`, or any subpath, no rebuild. Build wi
2525

2626
### Sharing a connection with an external viewer
2727

28-
`setupDevframeConnection()` prepares a serializable connection for a cross-origin viewer:
28+
`setupDevframeConnection()` prepares a serializable connection for an external viewer:
2929

3030
```ts
3131
import { setupDevframeConnection } from 'devframe/client'
@@ -35,17 +35,17 @@ const connection = await setupDevframeConnection({
3535
})
3636
```
3737

38-
In the viewer:
38+
In the external viewer:
3939

4040
```ts
4141
import { connectDevframe } from 'devframe/client'
4242

4343
const rpc = await connectDevframe({ connection })
4444
```
4545

46-
The client retains it as `rpc.connection`; cross-realm viewers read it via `getDevframeConnection()` or `DEVFRAME_CONNECTION_KEY` (`devframe/constants`).
46+
The RPC client retains it as `rpc.connection`; cross-realm viewers read it via `getDevframeConnection()` or `DEVFRAME_CONNECTION_KEY` (`devframe/constants`).
4747

48-
An external viewer registers its origin before the WebSocket opens (needs `viewerOriginToken` in the host's connection metadata; see [External viewer origins](/guide/security#external-viewer-origins)):
48+
An external viewer registers its origin before the WebSocket opens (needs `viewerOriginToken` in the host framework's connection metadata; see [External viewer origins](/guide/security#external-viewer-origins)):
4949

5050
```ts
5151
import { registerDevframeViewerOrigin } from 'devframe/client'
@@ -77,12 +77,12 @@ Per the `__devframe/__connection.json` backend:
7777

7878
## Trust & auth (WebSocket mode)
7979

80-
`ensureTrusted()` resolves once the server trusts the client's stored token:
80+
`ensureTrusted()` resolves once the node side trusts the RPC client's stored token:
8181

8282
```ts
8383
const rpc = await connectDevframe()
8484

85-
// Blocks until the server trusts this client (default timeout 60s)
85+
// Blocks until the node side trusts this RPC client (default timeout 60s)
8686
const trusted = await rpc.ensureTrusted()
8787

8888
if (!trusted) {
@@ -100,7 +100,7 @@ The dev server prints a single-use 6-digit code (expires in five minutes, rotate
100100
const ok = await rpc.requestTrustWithCode('047204')
101101
```
102102

103-
A host can embed the code in a link (`buildOtpAuthUrl(origin)`); `connectDevframe` reads the `devframe_otp` fragment, exchanges it, and strips the URL. Rename it with `otpParam`, or set `otpParam: false` to drive it yourself via `authenticateWithUrlOtp(rpc)` / `consumeOtpFromUrl()`.
103+
A host framework can embed the code in a link (`buildOtpAuthUrl(origin)`); `connectDevframe` reads the `devframe_otp` fragment, exchanges it, and strips the URL. Rename it with `otpParam`, or set `otpParam: false` to drive it yourself via `authenticateWithUrlOtp(rpc)` / `consumeOtpFromUrl()`.
104104

105105
### Re-using an existing token
106106

@@ -112,7 +112,7 @@ const ok = await rpc.requestTrustWithToken('a1b2c3…')
112112

113113
### Broadcast-channel sync
114114

115-
`connectDevframe` listens on a shared `BroadcastChannel` (`devframe-auth`) for `auth-update` messages; one tab authenticating trusts every open client.
115+
`connectDevframe` listens on a shared `BroadcastChannel` (`devframe-auth`) for `auth-update` messages; one tab authenticating trusts every open RPC client.
116116

117117

118118
## Calling functions
@@ -132,11 +132,11 @@ const maybe = await my.rpc.callOptional('get-modules', { limit: 10 })
132132
my.rpc.callEvent('notify', { message: 'hello' })
133133
```
134134

135-
Types flow from the server's `defineRpcFunction` definitions.
135+
Types flow from the node side's `defineRpcFunction` definitions.
136136

137137
## Registering client functions
138138

139-
Register functions the server calls via `rpc.broadcast`:
139+
Register functions the node side calls via `rpc.broadcast`:
140140

141141
```ts
142142
import { defineRpcFunction } from 'devframe'
@@ -172,18 +172,18 @@ See [Shared State](/guide/shared-state).
172172

173173
## Services
174174

175-
`rpc.services` mirrors the server's wire-service advertisements:
175+
`rpc.services` mirrors the node side's wire-service advertisements:
176176

177177
```ts
178178
if (rpc.services.has('@devframes/service-open'))
179179
await rpc.services.get('@devframes/service-open')!.rpc.call('open-in-editor', { path })
180180
```
181181

182-
See [Cross-Plugin Services](/guide/services#wire-services).
182+
See [Cross-Devframe Services](/guide/services#wire-services).
183183

184184
## Settings
185185

186-
A scoped client exposes a persisted `settings` store, per-user (`global`) or per-workspace (`project`):
186+
A scoped client exposes a persisted `settings` store, per-user (`global`) or per-checkout (`project`):
187187

188188
```ts
189189
await my.settings.project.set('theme', 'dark')
@@ -213,7 +213,7 @@ Devframe writes a JSON descriptor at `<base>/__connection.json`. The socket shar
213213
}
214214
```
215215

216-
The client resolves it against its origin (`http``ws` / `https``wss`). The field also accepts a `number` (port on the page's host), a full `ws://`/`wss://` URL, or `{ port }` / `{ host }` for a cross-origin side-car.
216+
The RPC client resolves it against its origin (`http``ws` / `https``wss`). The field also accepts a `number` (port on the page's host), a full `ws://`/`wss://` URL, or `{ port }` / `{ host }` for a cross-origin side-car server.
217217

218218
For static mode:
219219

@@ -231,7 +231,7 @@ await connectDevframe({
231231

232232
## Remote docks
233233

234-
Supporting hosts (Vite DevTools; see [its remote-client docs](https://devtools.vite.dev/kit/remote-client)) inject a connection descriptor into the iframe URL that `connectDevframe` auto-detects:
234+
Supporting host frameworks (Vite DevTools; see [its remote-client docs](https://devtools.vite.dev/kit/remote-client)) inject a connection descriptor into the iframe URL that `connectDevframe` auto-detects:
235235

236236
```ts
237237
import { connectDevframe } from 'devframe/client'
@@ -240,7 +240,7 @@ const rpc = await connectDevframe()
240240
// Already wired to the local dev server via the injected descriptor.
241241
```
242242

243-
The descriptor's session-only, pre-approved token makes `ensureTrusted()` resolve immediately. An external hub builds a viewer URL from a trusted connection with `buildRemoteDevframeUrl()`, keeping the token in the URL fragment:
243+
The descriptor's session-only, pre-approved token makes `ensureTrusted()` resolve immediately. An external hub builds an external-viewer URL from a trusted connection with `buildRemoteDevframeUrl()`, keeping the token in the URL fragment:
244244

245245
```ts
246246
import {
@@ -261,7 +261,7 @@ Emitted over `rpc.events`:
261261
| `rpc:is-trusted:updated` | Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. |
262262
| `connection:status` | The [connection status](#handling-connection-and-auth-errors) changes. Carries `(status, previous)`. |
263263
| `connection:error` | A connection-level failure — socket error or trust refused. Carries the `Error`. |
264-
| `rpc:error` | An `rpc.call` rejects, from the server or a down connection. Carries `(error, method)`. |
264+
| `rpc:error` | An `rpc.call` rejects, from the node side or a down connection. Carries `(error, method)`. |
265265

266266
```ts
267267
rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
@@ -295,10 +295,10 @@ A `static` backend has no live socket, so `rpc.status` stays `connected`.
295295
When the socket closes or trust is refused, in-flight and new `rpc.call` promises reject with a `DevframeConnectionError`, its `kind`:
296296

297297
- `'connection'` — the transport is down (`disconnected` / `error`).
298-
- `'auth'` — the client is `unauthorized`.
298+
- `'auth'` — the RPC client is `unauthorized`.
299299
- `'timeout'` — the call outlived `callTimeout`.
300300

301-
Set `callTimeout` to cap an unresponsive server:
301+
Set `callTimeout` to cap an unresponsive node side:
302302

303303
```ts
304304
const rpc = await connectDevframe({ callTimeout: 10_000 })
@@ -343,13 +343,13 @@ async function loadModules() {
343343

344344
### Recovering
345345

346-
The client doesn't reconnect on its own — reload or re-run your connect routine:
346+
The RPC client doesn't reconnect on its own — reload or re-run your connect routine:
347347

348348
```ts
349349
async function reconnect() {
350-
rpc = await connectDevframe() // a new client; re-subscribe your listeners
350+
rpc = await connectDevframe() // a new RPC client; re-subscribe your listeners
351351
render()
352352
}
353353
```
354354

355-
In a hub, a viewer reads this status from [`context.connection`](/guide/client-context#the-client-context).
355+
In a hub, a hub UI provider reads this status from [`context.connection`](/guide/client-context#the-client-context).

0 commit comments

Comments
 (0)