You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/content/1.guide/1.tutorial-server-data-inspector.md
+18-18Lines changed: 18 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,15 @@
1
1
---
2
2
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.'
4
4
---
5
5
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.
7
7
8
8
You'll need [Node 24+](https://nodejs.org/) and a terminal. Every code block is complete, so you can copy them as you go.
9
9
10
-
## The shape of a devframe app
10
+
## The shape of a devframe
11
11
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.
`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.)
86
86
87
87
## Step 2 — Add a UI
88
88
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.
90
90
91
91
```sh
92
92
npm install react react-dom @devframes/vite
@@ -128,8 +128,8 @@ export function App() {
128
128
const [result, setResult] =useState<unknown>()
129
129
130
130
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.
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.
198
198
199
199
> [!WARNING]
200
200
> `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;
203
203
204
204
## Step 4 — Dock it in a hub
205
205
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:
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.)
247
247
248
248
## Step 5 — Build a static version
249
249
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`:
251
251
252
252
```ts
253
253
ctx.rpc.register({
@@ -273,7 +273,7 @@ npx vite build # refresh dist/client
273
273
node scripts/build.mjs # → dist-static/
274
274
```
275
275
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)).
277
277
278
278
## Step 6 — Run it standalone
279
279
@@ -295,7 +295,7 @@ Same UI, same live calls, no bundler in the loop — this is what you'd drop int
295
295
296
296
## Step 7 — Give it a CLI
297
297
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:
node bin.mjs dev # the standalone server from Step 6
311
+
node bin.mjs dev # the standalone dev server from Step 6
312
312
node bin.mjs build # the static build from Step 5
313
313
node bin.mjs mcp # expose the tool to a coding agent over MCP
314
314
```
315
315
316
316
You can also assemble your own CLI from the adapter functions used above.
317
317
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.
Copy file name to clipboardExpand all lines: docs/content/1.guide/10.standalone-cli.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -131,7 +131,7 @@ defineDevframe({
131
131
132
132
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).
133
133
134
-
## Connecting from the client
134
+
## Connecting from the browser side
135
135
136
136
With the Nuxt helper, use `$rpc`:
137
137
@@ -207,7 +207,7 @@ It's the no-args fallback for any deployed `rpc.call('my-tool:get-payload', …)
207
207
208
208
## On-disk caching
209
209
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`.
211
211
212
212
```ts
213
213
import { resolve } from'pathe'
@@ -238,7 +238,7 @@ defineDevframe({
238
238
239
239
## Live-reload on config changes
240
240
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.
242
242
243
243
```ts [src/cli.ts]
244
244
defineDevframe({
@@ -267,7 +267,7 @@ defineDevframe({
267
267
})
268
268
```
269
269
270
-
On the client:
270
+
On the browser side:
271
271
272
272
```ts
273
273
const my = (awaitconnectDevframe()).scope('my-tool')
Copy file name to clipboardExpand all lines: docs/content/1.guide/11.client.md
+24-24Lines changed: 24 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,9 +1,9 @@
1
1
---
2
2
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.'
4
4
---
5
5
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.
7
7
8
8
## Connecting
9
9
@@ -25,7 +25,7 @@ One SPA artifact serves at `/`, `/__<id>/`, or any subpath, no rebuild. Build wi
25
25
26
26
### Sharing a connection with an external viewer
27
27
28
-
`setupDevframeConnection()` prepares a serializable connection for a cross-origin viewer:
28
+
`setupDevframeConnection()` prepares a serializable connection for an external viewer:
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`).
47
47
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)):
@@ -77,12 +77,12 @@ Per the `__devframe/__connection.json` backend:
77
77
78
78
## Trust & auth (WebSocket mode)
79
79
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:
81
81
82
82
```ts
83
83
const rpc =awaitconnectDevframe()
84
84
85
-
// Blocks until the server trusts this client (default timeout 60s)
85
+
// Blocks until the node side trusts this RPC client (default timeout 60s)
86
86
const trusted =awaitrpc.ensureTrusted()
87
87
88
88
if (!trusted) {
@@ -100,7 +100,7 @@ The dev server prints a single-use 6-digit code (expires in five minutes, rotate
100
100
const ok =awaitrpc.requestTrustWithCode('047204')
101
101
```
102
102
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()`.
104
104
105
105
### Re-using an existing token
106
106
@@ -112,7 +112,7 @@ const ok = await rpc.requestTrustWithToken('a1b2c3…')
112
112
113
113
### Broadcast-channel sync
114
114
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.
See [Cross-Plugin Services](/guide/services#wire-services).
182
+
See [Cross-Devframe Services](/guide/services#wire-services).
183
183
184
184
## Settings
185
185
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`):
187
187
188
188
```ts
189
189
awaitmy.settings.project.set('theme', 'dark')
@@ -213,7 +213,7 @@ Devframe writes a JSON descriptor at `<base>/__connection.json`. The socket shar
213
213
}
214
214
```
215
215
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.
217
217
218
218
For static mode:
219
219
@@ -231,7 +231,7 @@ await connectDevframe({
231
231
232
232
## Remote docks
233
233
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:
// Already wired to the local dev server via the injected descriptor.
241
241
```
242
242
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:
244
244
245
245
```ts
246
246
import {
@@ -261,7 +261,7 @@ Emitted over `rpc.events`:
261
261
|`rpc:is-trusted:updated`| Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. |
262
262
|`connection:status`| The [connection status](#handling-connection-and-auth-errors) changes. Carries `(status, previous)`. |
263
263
|`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)`. |
0 commit comments