Skip to content

Commit cb81c0e

Browse files
antfuclaude
andcommitted
Merge branch 'main' into antfu/rpc-json-serializable
Resolves a numbering conflict: main's #302 introduced DF0018 for the `ctx.logs` deprecation warning, so my jsonSerializable diagnostics shift up by one. New numbering on this branch: - DF0018 (main) — `ctx.logs` deprecated. - DF0019 — Agent Requires JSON-Serializable RPC. - DF0020 — Non-JSON Value in JSON-Serializable RPC. - DF0021..DF0028 — migrated from DTK0001..DTK0008. Updates code, callsites, docs pages, sidebar count (28), error index table, and skill / guide references to the new numbers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 parents 31de7cf + 1a2a81d commit cb81c0e

77 files changed

Lines changed: 1476 additions & 689 deletions

Some content is hidden

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

devframe/docs/.vitepress/sidebar.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export default function devframeSidebar(prefix = ''): DefaultTheme.SidebarItem[]
1313
{ text: 'Dock System', link: `${prefix}/guide/dock-system` },
1414
{ text: 'Commands', link: `${prefix}/guide/commands` },
1515
{ text: 'When Clauses', link: `${prefix}/guide/when-clauses` },
16-
{ text: 'Logs & Notifications', link: `${prefix}/guide/logs` },
16+
{ text: 'Messages & Notifications', link: `${prefix}/guide/messages` },
17+
{ text: 'Structured Diagnostics', link: `${prefix}/guide/diagnostics` },
1718
{ text: 'Terminals', link: `${prefix}/guide/terminals` },
1819
{ text: 'Client', link: `${prefix}/guide/client` },
1920
{ text: 'Standalone CLI', link: `${prefix}/guide/standalone-cli` },
@@ -25,7 +26,7 @@ export default function devframeSidebar(prefix = ''): DefaultTheme.SidebarItem[]
2526
text: 'Error Reference',
2627
link: `${prefix}/errors/`,
2728
collapsed: true,
28-
items: Array.from({ length: 27 }, (_, i) => {
29+
items: Array.from({ length: 28 }, (_, i) => {
2930
const code = `DF${String(i + 1).padStart(4, '0')}`
3031
return { text: code, link: `${prefix}/errors/${code}` }
3132
}),

devframe/docs/errors/DF0018.md

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,51 @@
22
outline: deep
33
---
44

5-
# DF0018: Agent Requires JSON-Serializable RPC
5+
# DF0018: `ctx.logs` Deprecated
66

77
> Package: `devframe`
88
99
## Message
1010

11-
> RPC function "`{name}`" has `agent` set but `jsonSerializable` is not `true` — MCP requires JSON-serializable data.
11+
> `` `ctx.logs` is deprecated and will be removed in a future release. Use `ctx.messages` instead. ``
1212
1313
## Cause
1414

15-
The `agent` field exposes an RPC function as an MCP tool. MCP and the underlying schema-conversion path (`@valibot/to-json-schema`) only consume JSON-shaped data. Functions whose payloads can include `Map`, `Set`, `Date`, `BigInt`, circular references, or class instances cannot be safely advertised to agents.
15+
The user-facing message subsystem has been renamed from `logs` to `messages` to disambiguate it from the structured diagnostics surface (`ctx.diagnostics`, powered by [`logs-sdk`](https://github.com/vercel-labs/logs-sdk)).
1616

17-
A registered function is rejected when `agent` is present and `jsonSerializable` is not explicitly `true`.
17+
`ctx.logs` continues to work as an alias of `ctx.messages` for one release cycle, but emits this warning the first time it is accessed in a given process.
1818

1919
## Example
2020

21+
Code that triggers it:
22+
2123
```ts
22-
defineRpcFunction({
23-
name: 'my-plugin:summary',
24-
agent: { description: 'Returns a summary' },
25-
// missing `jsonSerializable: true` → registration throws DF0018
26-
handler: () => ({ items: [1, 2, 3] }),
27-
})
24+
ctx.logs.add({ message: 'something happened', level: 'info' })
2825
```
2926

3027
## Fix
3128

32-
Either declare the payload as JSON-safe:
29+
Replace `ctx.logs` with `ctx.messages`:
3330

3431
```ts
35-
defineRpcFunction({
36-
name: 'my-plugin:summary',
37-
jsonSerializable: true,
38-
agent: { description: 'Returns a summary' },
39-
handler: () => ({ items: [1, 2, 3] }),
40-
})
32+
ctx.messages.add({ message: 'something happened', level: 'info' })
4133
```
4234

43-
Or remove `agent` to keep the function as an internal RPC (no agent exposure):
35+
The runtime behavior is identical — the same host instance backs both fields.
4436

45-
```ts
46-
defineRpcFunction({
47-
name: 'my-plugin:summary',
48-
handler: () => new Map([['a', 1]]),
49-
})
50-
```
37+
The associated type names have been renamed too (with deprecated aliases kept for one release):
38+
39+
| Old | New |
40+
|-----|-----|
41+
| `DevToolsLogsHost` | `DevToolsMessagesHost` |
42+
| `DevToolsLogsClient` | `DevToolsMessagesClient` |
43+
| `DevToolsLogEntry` | `DevToolsMessageEntry` |
44+
| `DevToolsLogEntryInput` | `DevToolsMessageEntryInput` |
45+
| `DevToolsLogHandle` | `DevToolsMessageHandle` |
46+
| `DevToolsLogLevel` | `DevToolsMessageLevel` |
47+
48+
The event names emitted by the host have changed from `log:added` / `log:updated` / `log:removed` / `log:cleared` to `message:added` / `message:updated` / `message:removed` / `message:cleared`.
5149

5250
## Source
5351

54-
`packages/devframe/src/rpc/collector.ts`
52+
`packages/devframe/src/node/context.ts`

devframe/docs/errors/DF0019.md

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,53 @@
22
outline: deep
33
---
44

5-
# DF0019: Non-JSON Value in JSON-Serializable RPC
5+
# DF0019: Agent Requires JSON-Serializable RPC
66

77
> Package: `devframe`
88
99
## Message
1010

11-
> RPC function "`{name}`" declares `jsonSerializable: true` but the value at "`{path}`" is a `{type}`.
11+
> RPC function "`{name}`" has `agent` set but `jsonSerializable` is not `true` — MCP requires JSON-serializable data.
1212
1313
## Cause
1414

15-
The function is declared `jsonSerializable: true`, which means its args and return value are encoded with strict `JSON.stringify` (both on the wire and in build dumps). The strict serializer rejects any value that JSON cannot round-trip losslessly:
15+
The `agent` field exposes an RPC function as an MCP tool. MCP and the underlying schema-conversion path (`@valibot/to-json-schema`) only consume JSON-shaped data. Functions whose payloads can include `Map`, `Set`, `Date`, `BigInt`, circular references, or class instances cannot be safely advertised to agents.
1616

17-
- `Map`, `Set`, `WeakMap`, `WeakSet`
18-
- `Date` (silently coerced to ISO string by JSON)
19-
- `BigInt`
20-
- circular references
21-
- non-plain class instances
22-
- `undefined` leaves
23-
- `Symbol`
24-
- `Function`
25-
26-
When the strict serializer encounters one of these, it throws synchronously at the offending call rather than producing a corrupt payload.
17+
A registered function is rejected when `agent` is present and `jsonSerializable` is not explicitly `true`.
2718

2819
## Example
2920

3021
```ts
3122
defineRpcFunction({
32-
name: 'my-plugin:graph',
33-
jsonSerializable: true,
34-
handler: () => ({
35-
nodes: new Map([['a', 1]]), // ← throws DF0019 with type=Map, path="nodes"
36-
}),
23+
name: 'my-plugin:summary',
24+
agent: { description: 'Returns a summary' },
25+
// missing `jsonSerializable: true` → registration throws DF0019
26+
handler: () => ({ items: [1, 2, 3] }),
3727
})
3828
```
3929

4030
## Fix
4131

42-
Either drop `jsonSerializable: true` so the function uses `structured-clone-es` (round-trips `Map`, `Set`, etc.):
32+
Either declare the payload as JSON-safe:
4333

4434
```ts
4535
defineRpcFunction({
46-
name: 'my-plugin:graph',
47-
// jsonSerializable: false (default) — Map/Set survive the wire and the dump
48-
handler: () => ({
49-
nodes: new Map([['a', 1]]),
50-
}),
36+
name: 'my-plugin:summary',
37+
jsonSerializable: true,
38+
agent: { description: 'Returns a summary' },
39+
handler: () => ({ items: [1, 2, 3] }),
5140
})
5241
```
5342

54-
Or convert the payload to a JSON-safe shape (e.g. an array of entries, an ISO string, a plain object) before returning. Note: removing `jsonSerializable: true` also disables `agent` exposure; if you need MCP, you must use a JSON-safe shape.
43+
Or remove `agent` to keep the function as an internal RPC (no agent exposure):
44+
45+
```ts
46+
defineRpcFunction({
47+
name: 'my-plugin:summary',
48+
handler: () => new Map([['a', 1]]),
49+
})
50+
```
5551

5652
## Source
5753

58-
`packages/devframe/src/rpc/serialization.ts`
54+
`packages/devframe/src/rpc/collector.ts`

devframe/docs/errors/DF0020.md

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,57 @@
22
outline: deep
33
---
44

5-
# DF0020: RPC Function Already Registered
5+
# DF0020: Non-JSON Value in JSON-Serializable RPC
66

77
> Package: `devframe`
88
9-
> Migrated from `DTK0001`.
10-
119
## Message
1210

13-
> RPC function "`{name}`" is already registered
11+
> RPC function "`{name}`" declares `jsonSerializable: true` but the value at "`{path}`" is a `{type}`.
1412
1513
## Cause
1614

17-
`ctx.rpc.register()` was called twice with the same `name`. RPC names must be unique within a devtool.
15+
The function is declared `jsonSerializable: true`, which means its args and return value are encoded with strict `JSON.stringify` (both on the wire and in build dumps). The strict serializer rejects any value that JSON cannot round-trip losslessly:
16+
17+
- `Map`, `Set`, `WeakMap`, `WeakSet`
18+
- `Date` (silently coerced to ISO string by JSON)
19+
- `BigInt`
20+
- circular references
21+
- non-plain class instances
22+
- `undefined` leaves
23+
- `Symbol`
24+
- `Function`
25+
26+
When the strict serializer encounters one of these, it throws synchronously at the offending call rather than producing a corrupt payload.
27+
28+
## Example
29+
30+
```ts
31+
defineRpcFunction({
32+
name: 'my-plugin:graph',
33+
jsonSerializable: true,
34+
handler: () => ({
35+
nodes: new Map([['a', 1]]), // ← throws DF0020 with type=Map, path="nodes"
36+
}),
37+
})
38+
```
1839

1940
## Fix
2041

21-
Either give the second registration a distinct name, or pass `force: true` to overwrite the previous one (e.g. during HMR-driven re-registration).
42+
Either drop `jsonSerializable: true` so the function uses `structured-clone-es` (round-trips `Map`, `Set`, etc.):
2243

2344
```ts
24-
ctx.rpc.register(defineRpcFunction({ name: 'my-plugin:fn', handler: () => 1 }), true /* force */)
45+
defineRpcFunction({
46+
name: 'my-plugin:graph',
47+
// jsonSerializable: false (default) — Map/Set survive the wire and the dump
48+
handler: () => ({
49+
nodes: new Map([['a', 1]]),
50+
}),
51+
})
2552
```
2653

54+
Or convert the payload to a JSON-safe shape (e.g. an array of entries, an ISO string, a plain object) before returning. Note: removing `jsonSerializable: true` also disables `agent` exposure; if you need MCP, you must use a JSON-safe shape.
55+
2756
## Source
2857

29-
`packages/devframe/src/rpc/collector.ts`
58+
`packages/devframe/src/rpc/serialization.ts`

devframe/docs/errors/DF0021.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@
22
outline: deep
33
---
44

5-
# DF0021: RPC Function Not Registered (Update)
5+
# DF0021: RPC Function Already Registered
66

77
> Package: `devframe`
88
9-
> Migrated from `DTK0002`.
9+
> Migrated from `DTK0001`.
1010
1111
## Message
1212

13-
> RPC function "`{name}`" is not registered. Use register() to add new functions.
13+
> RPC function "`{name}`" is already registered
1414
1515
## Cause
1616

17-
`ctx.rpc.update()` was called for a function that was never registered. `update()` is for replacing an existing definition.
17+
`ctx.rpc.register()` was called twice with the same `name`. RPC names must be unique within a devtool.
1818

1919
## Fix
2020

21-
Call `ctx.rpc.register()` first, or pass `force: true` to `update()` to register-or-replace in one call.
21+
Either give the second registration a distinct name, or pass `force: true` to overwrite the previous one (e.g. during HMR-driven re-registration).
22+
23+
```ts
24+
ctx.rpc.register(defineRpcFunction({ name: 'my-plugin:fn', handler: () => 1 }), true /* force */)
25+
```
2226

2327
## Source
2428

devframe/docs/errors/DF0022.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
outline: deep
33
---
44

5-
# DF0022: RPC Function Not Registered (Get)
5+
# DF0022: RPC Function Not Registered (Update)
66

77
> Package: `devframe`
88
9-
> Migrated from `DTK0003`.
9+
> Migrated from `DTK0002`.
1010
1111
## Message
1212

13-
> RPC function "`{name}`" is not registered
13+
> RPC function "`{name}`" is not registered. Use register() to add new functions.
1414
1515
## Cause
1616

17-
A consumer asked for the schema or handler of a function that has never been registered with `ctx.rpc.register()`.
17+
`ctx.rpc.update()` was called for a function that was never registered. `update()` is for replacing an existing definition.
1818

1919
## Fix
2020

21-
Confirm the function name matches a registration. RPC names are namespaced — typos in the prefix are a common cause.
21+
Call `ctx.rpc.register()` first, or pass `force: true` to `update()` to register-or-replace in one call.
2222

2323
## Source
2424

devframe/docs/errors/DF0023.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22
outline: deep
33
---
44

5-
# DF0023: Missing RPC Handler
5+
# DF0023: RPC Function Not Registered (Get)
66

77
> Package: `devframe`
88
9-
> Migrated from `DTK0004`.
9+
> Migrated from `DTK0003`.
1010
1111
## Message
1212

13-
> Either handler or setup function must be provided for RPC function "`{name}`"
13+
> RPC function "`{name}`" is not registered
1414
1515
## Cause
1616

17-
The RPC definition has neither a `handler` nor a `setup` returning `{ handler }`. devframe has nothing to invoke when the function is called.
17+
A consumer asked for the schema or handler of a function that has never been registered with `ctx.rpc.register()`.
1818

1919
## Fix
2020

21-
Add either `handler: ...` directly on the definition, or `setup: ctx => ({ handler: ... })` if the handler depends on context.
21+
Confirm the function name matches a registration. RPC names are namespaced — typos in the prefix are a common cause.
2222

2323
## Source
2424

25-
`packages/devframe/src/rpc/handler.ts`
25+
`packages/devframe/src/rpc/collector.ts`

devframe/docs/errors/DF0024.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22
outline: deep
33
---
44

5-
# DF0024: Function Not in Dump Store
5+
# DF0024: Missing RPC Handler
66

77
> Package: `devframe`
88
9-
> Migrated from `DTK0005`.
9+
> Migrated from `DTK0004`.
1010
1111
## Message
1212

13-
> Function "`{name}`" not found in dump store
13+
> Either handler or setup function must be provided for RPC function "`{name}`"
1414
1515
## Cause
1616

17-
A static-mode client called an RPC function that was not baked into the build dump. This usually means the function was added after the dump was generated, or its name changed between build and runtime.
17+
The RPC definition has neither a `handler` nor a `setup` returning `{ handler }`. devframe has nothing to invoke when the function is called.
1818

1919
## Fix
2020

21-
Re-run `createBuild` to regenerate the dump, or check that the call site uses the same name registered on the server.
21+
Add either `handler: ...` directly on the definition, or `setup: ctx => ({ handler: ... })` if the handler depends on context.
2222

2323
## Source
2424

25-
`packages/devframe/src/rpc/dumps.ts`
25+
`packages/devframe/src/rpc/handler.ts`

0 commit comments

Comments
 (0)