devframe 0.8.2 → 0.9.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/_shared-BPmX9fqK.d.mts +41 -0
  2. package/dist/_shared-CbZ_yhbz.mjs +68 -0
  3. package/dist/adapters/build.d.mts +10 -12
  4. package/dist/adapters/build.mjs +26 -29
  5. package/dist/adapters/cac.d.mts +1 -1
  6. package/dist/adapters/cac.mjs +156 -1
  7. package/dist/adapters/dev.d.mts +38 -46
  8. package/dist/adapters/dev.mjs +2 -1
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +224 -0
  11. package/dist/adapters/initiate.mjs +2 -0
  12. package/dist/adapters/mcp.d.mts +24 -7
  13. package/dist/adapters/mcp.mjs +2 -2
  14. package/dist/{agent-tool-name-C3b5vEwJ.mjs → agent-tool-name-EgfoFO8C.mjs} +0 -3
  15. package/dist/cli/main.d.mts +0 -2
  16. package/dist/cli/main.mjs +4 -8
  17. package/dist/client/index.d.mts +71 -7
  18. package/dist/client/index.mjs +720 -1540
  19. package/dist/constants.d.mts +28 -7
  20. package/dist/constants.mjs +28 -7
  21. package/dist/{context-DoSozfvx.d.mts → context-B3YUu_95.d.mts} +19 -1
  22. package/dist/{host-h3-D2hYZvDK.mjs → context-CEe4PBz1.mjs} +25 -557
  23. package/dist/{context-CBg8iRbQ.mjs → context-xdynGSLP.mjs} +10 -1
  24. package/dist/dev--rAPzbvO.mjs +239 -0
  25. package/dist/{devframe-mQ4qZAuo.d.mts → devframe-DJMg0WLe.d.mts} +181 -134
  26. package/dist/{diagnostics-hwjXp_UV.mjs → diagnostics-CD8nlgll.mjs} +1 -3
  27. package/dist/{diagnostics-D7wM2cwM.mjs → diagnostics-DOQPnQmX.mjs} +51 -5
  28. package/dist/dist-eNI9qM_I.mjs +228 -0
  29. package/dist/host-agent-xLCSe65D.mjs +264 -0
  30. package/dist/host-h3-Crkzm42q.mjs +26 -0
  31. package/dist/{fetch-BKaD0Vb3.mjs → http-DYpK0cUi.mjs} +42 -11
  32. package/dist/{index-b64Uuhy2.d.mts → index-CB-fSUyn.d.mts} +2 -2
  33. package/dist/{index-Dbw1p5ch.d.mts → index-tdrk1bzV.d.mts} +3 -32
  34. package/dist/index.d.mts +12 -5
  35. package/dist/index.mjs +8 -1
  36. package/dist/{instance-registry-BnnA2Eoh.mjs → instance-registry-WvQkt42E.mjs} +9 -8
  37. package/dist/instance-shell-CMFyszWJ.mjs +486 -0
  38. package/dist/instance-shell-CljiKq1c.d.mts +255 -0
  39. package/dist/internal/index.d.mts +397 -0
  40. package/dist/internal/index.mjs +9 -0
  41. package/dist/node/auth.d.mts +2 -2
  42. package/dist/node/auth.mjs +1 -1
  43. package/dist/node/hub-internals.d.mts +2 -14
  44. package/dist/node/hub-internals.mjs +2 -2
  45. package/dist/node/index.d.mts +4 -268
  46. package/dist/node/index.mjs +3 -5
  47. package/dist/nostics-CzECRXpE.mjs +59 -0
  48. package/dist/nostics-SPGDgHEP.d.mts +33 -0
  49. package/dist/recipes/common-rpc-functions.d.mts +4 -4
  50. package/dist/recipes/interactive-auth.d.mts +3 -3
  51. package/dist/recipes/interactive-auth.mjs +8 -8
  52. package/dist/remote-assets-Bg4gCUZ_.d.mts +123 -0
  53. package/dist/remote-assets-nTTxY2MU.mjs +636 -0
  54. package/dist/rolldown-runtime-JspESFgx.mjs +35 -0
  55. package/dist/rpc/dump.d.mts +77 -1
  56. package/dist/rpc/dump.mjs +1 -1
  57. package/dist/rpc/index.d.mts +3 -3
  58. package/dist/rpc/index.mjs +4 -18
  59. package/dist/rpc/transports/sse-client.d.mts +2 -0
  60. package/dist/rpc/transports/sse-client.mjs +142 -0
  61. package/dist/rpc/transports/sse-server.d.mts +61 -0
  62. package/dist/rpc/transports/sse-server.mjs +209 -0
  63. package/dist/rpc/transports/ws-bun.d.mts +35 -0
  64. package/dist/rpc/transports/ws-bun.mjs +31 -0
  65. package/dist/rpc/transports/ws-client.d.mts +1 -1
  66. package/dist/rpc/transports/ws-client.mjs +10 -18
  67. package/dist/rpc/transports/ws-server.d.mts +2 -2
  68. package/dist/rpc/transports/ws-server.mjs +2 -235
  69. package/dist/rpc-core-Cc4lucI0.d.mts +48 -0
  70. package/dist/rpc-core-DMTe-hLo.mjs +81 -0
  71. package/dist/{serialization-C8Mnw9hK.mjs → serialization-BGzEwAdr.mjs} +2 -2
  72. package/dist/{shared-state-6kHolYZy.mjs → shared-state-fRRbRUtD.mjs} +1 -1
  73. package/dist/sse-client-CFBOIaUi.d.mts +37 -0
  74. package/dist/state-Cc1IeSmQ.mjs +1291 -0
  75. package/dist/{dump-CgZShDRB.mjs → static-BPZ1_OPA.mjs} +3 -266
  76. package/dist/storage-CYye7P7L.mjs +137 -0
  77. package/dist/types/index.d.mts +6 -4
  78. package/dist/types/index.mjs +1 -6
  79. package/dist/{types-CnJSgRVa.d.mts → types-Djq7CBXh.d.mts} +0 -7
  80. package/dist/utils/agent-tool-name.d.mts +0 -3
  81. package/dist/utils/agent-tool-name.mjs +0 -3
  82. package/dist/utils/events.d.mts +1 -1
  83. package/dist/utils/get-port.d.mts +17 -0
  84. package/dist/utils/get-port.mjs +2 -0
  85. package/dist/utils/launch-editor.mjs +1 -25
  86. package/dist/utils/nostics.d.mts +2 -0
  87. package/dist/utils/nostics.mjs +2 -0
  88. package/dist/utils/open.d.mts +2 -10
  89. package/dist/utils/open.mjs +56 -1
  90. package/dist/utils/remote-assets.d.mts +15 -0
  91. package/dist/utils/remote-assets.mjs +2 -0
  92. package/dist/utils/serve-static.d.mts +13 -5
  93. package/dist/utils/serve-static.mjs +119 -9
  94. package/dist/utils/shared-state.d.mts +1 -1
  95. package/dist/utils/shared-state.mjs +1 -1
  96. package/dist/utils/simple-schema.d.mts +101 -1
  97. package/dist/utils/streaming-channel.d.mts +1 -1
  98. package/dist/validation-CpXFB6Dz.mjs +266 -0
  99. package/dist/wire-codec-0K-o5MYW.mjs +56 -0
  100. package/dist/{ws-client-B6Tnr0ic.d.mts → ws-client-DhjNyQo3.d.mts} +7 -2
  101. package/dist/ws-server-BdSLrhxE.mjs +267 -0
  102. package/dist/{ws-server-uKQcClcJ.d.mts → ws-server-D1d3QM9f.d.mts} +90 -9
  103. package/package.json +13 -12
  104. package/skills/devframe/SKILL.md +91 -93
  105. package/dist/_shared-bWRzeSa0.mjs +0 -19
  106. package/dist/adapters/cli.d.mts +0 -11
  107. package/dist/adapters/cli.mjs +0 -6
  108. package/dist/cac-D4_9ok0z.mjs +0 -157
  109. package/dist/dev-Bc49u3qg.mjs +0 -439
  110. package/dist/diagnostics-reporter-CsIG85Q5.mjs +0 -38
  111. package/dist/helpers/vite.d.mts +0 -100
  112. package/dist/helpers/vite.mjs +0 -105
  113. package/dist/http-C4T68YV6.mjs +0 -38
  114. package/dist/index-vAX6bYuc.d.mts +0 -78
  115. package/dist/open-Deb5xmIT.mjs +0 -547
  116. package/dist/recipes/open-helpers.d.mts +0 -6
  117. package/dist/recipes/open-helpers.mjs +0 -6
  118. package/dist/server-CD8XmBXl.mjs +0 -167
  119. package/dist/server-UHWae43Q.d.mts +0 -149
  120. package/dist/simple-schema-BDzLeJDk.d.mts +0 -102
  121. package/dist/state-BeUHDDjk.mjs +0 -108
  122. package/dist/storage-CTNVbuFB.mjs +0 -1122
  123. package/dist/utils/promise.d.mts +0 -8
  124. package/dist/utils/promise.mjs +0 -15
  125. package/dist/utils/scope.d.mts +0 -11
  126. package/dist/utils/scope.mjs +0 -15
  127. package/skills/devframe/templates/spa-devframe.ts +0 -38
@@ -1,11 +1,11 @@
1
- import { _ as RpcFunctionDefinition, v as RpcFunctionDefinitionAny } from "./types-CnJSgRVa.mjs";
2
- import { w as RpcFunctionsCollectorBase } from "./index-Dbw1p5ch.mjs";
3
- import { n as DevframeNodeRpcSessionMeta } from "./ws-server-uKQcClcJ.mjs";
1
+ import { d as RpcFunctionsCollectorBase } from "./index-tdrk1bzV.mjs";
2
+ import { _ as RpcFunctionDefinition, v as RpcFunctionDefinitionAny } from "./types-Djq7CBXh.mjs";
3
+ import { d as DevframeRpcConnection, u as DevframeNodeRpcSessionMeta } from "./ws-server-D1d3QM9f.mjs";
4
+ import { m as defineDiagnostics } from "./nostics-SPGDgHEP.mjs";
5
+ import { a as RemoteAssetsStore, o as StaticAssetsSource } from "./remote-assets-Bg4gCUZ_.mjs";
4
6
  import { CAC } from "cac";
5
7
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
- import { Peer } from "crossws";
7
8
  import { BirpcReturn } from "birpc";
8
- import { Diagnostic, DiagnosticDefinition, defineDiagnostics } from "nostics";
9
9
  //#region src/adapters/flags.d.ts
10
10
  /**
11
11
  * Schema map for typed CLI flags. Keys are flag names in camelCase —
@@ -120,9 +120,6 @@ interface EventEmitter<Events extends EventsMap> {
120
120
  * Serializable description of an agent-exposed tool. This is the shape
121
121
  * returned by the agent host manifest and surfaced over the wire by
122
122
  * the `devframe:agent:list-tools` introspection RPC.
123
- *
124
- * @experimental The agent-native surface is experimental and may change
125
- * without a major version bump until it stabilizes.
126
123
  */
127
124
  interface AgentTool {
128
125
  /** Stable identifier. For RPC-backed tools, matches the RPC name. */
@@ -160,8 +157,6 @@ interface AgentTool {
160
157
  /**
161
158
  * Input accepted by `DevframeAgentHost.registerTool()`. Handler is
162
159
  * stripped from the serializable `AgentTool` projection.
163
- *
164
- * @experimental
165
160
  */
166
161
  interface AgentToolInput {
167
162
  id: string;
@@ -192,8 +187,6 @@ interface AgentToolInput {
192
187
  /**
193
188
  * Serializable description of an agent-readable resource. Resources
194
189
  * surface structured or textual snapshots of devframe state.
195
- *
196
- * @experimental
197
190
  */
198
191
  interface AgentResource {
199
192
  id: string;
@@ -206,8 +199,6 @@ interface AgentResource {
206
199
  }
207
200
  /**
208
201
  * Input accepted by `DevframeAgentHost.registerResource()`.
209
- *
210
- * @experimental
211
202
  */
212
203
  interface AgentResourceInput {
213
204
  id: string;
@@ -221,8 +212,6 @@ interface AgentResourceInput {
221
212
  }
222
213
  /**
223
214
  * Payload returned by `AgentResourceInput.read`. Either `text` or `json` must be set.
224
- *
225
- * @experimental
226
215
  */
227
216
  interface AgentResourceContent {
228
217
  text?: string;
@@ -232,8 +221,6 @@ interface AgentResourceContent {
232
221
  }
233
222
  /**
234
223
  * Unified view of the agent-exposed surface.
235
- *
236
- * @experimental
237
224
  */
238
225
  interface AgentManifest {
239
226
  tools: readonly AgentTool[];
@@ -241,8 +228,6 @@ interface AgentManifest {
241
228
  }
242
229
  /**
243
230
  * Handle returned by `registerTool` / `registerResource`.
244
- *
245
- * @experimental
246
231
  */
247
232
  interface AgentHandle {
248
233
  unregister: () => void;
@@ -257,14 +242,10 @@ interface AgentHandle {
257
242
  * Providers should namespace tool ids like any other tool; on an id
258
243
  * collision the earlier source wins (registered tools, then RPC tools,
259
244
  * then providers in registration order).
260
- *
261
- * @experimental
262
245
  */
263
246
  type AgentToolProvider = () => readonly AgentToolInput[];
264
247
  /**
265
248
  * Handle returned by `registerToolProvider`.
266
- *
267
- * @experimental
268
249
  */
269
250
  interface AgentToolProviderHandle extends AgentHandle {
270
251
  /**
@@ -276,8 +257,6 @@ interface AgentToolProviderHandle extends AgentHandle {
276
257
  }
277
258
  /**
278
259
  * Events emitted by `DevframeAgentHost`.
279
- *
280
- * @experimental
281
260
  */
282
261
  interface DevframeAgentHostEvents {
283
262
  'agent:tool:registered': (tool: AgentTool) => void;
@@ -295,9 +274,6 @@ interface DevframeAgentHostEvents {
295
274
  * RPC functions flagged with `agent` and plugin-registered tools /
296
275
  * resources. Consumed by protocol adapters such as the devframe MCP
297
276
  * adapter.
298
- *
299
- * @experimental The agent-native surface is experimental and may change
300
- * without a major version bump until it stabilizes.
301
277
  */
302
278
  interface DevframeAgentHost {
303
279
  readonly events: EventEmitter<DevframeAgentHostEvents>;
@@ -852,7 +828,7 @@ interface RpcStreamingHost {
852
828
  /**
853
829
  * Adapters call this when a session disconnects so the host can drop
854
830
  * subscribers and abort orphaned streams. Most users do not need this;
855
- * it's wired by `startHttpAndWs` automatically.
831
+ * it's wired by the RPC server binding automatically.
856
832
  *
857
833
  * @internal
858
834
  */
@@ -860,14 +836,6 @@ interface RpcStreamingHost {
860
836
  }
861
837
  //#endregion
862
838
  //#region src/types/diagnostics.d.ts
863
- /**
864
- * A diagnostics definition object built with `defineDiagnostics`. Typed as
865
- * `unknown` because each integration's definition has a distinct narrow shape
866
- * (e.g. specific code keys like `DF0001` / `MYP0001`), and TypeScript's mapped
867
- * types don't allow assigning a narrow-keyed result to a generically-keyed
868
- * one. The host stores them in a heterogeneous registry.
869
- */
870
- type DevframeDiagnosticsDefinition = ReturnType<typeof defineDiagnostics<any, any>>;
871
839
  /**
872
840
  * The shared diagnostics lookup exposed by the host. A `Proxy` that resolves
873
841
  * any registered code name to its `nostics` handle (a callable that builds
@@ -876,16 +844,6 @@ type DevframeDiagnosticsDefinition = ReturnType<typeof defineDiagnostics<any, an
876
844
  * integrations.
877
845
  */
878
846
  type DevframeDiagnosticsLogger = Record<string, any>;
879
- /**
880
- * Options accepted by the host's `defineDiagnostics()` factory — mirrors
881
- * `nostics`'s shape but the host pre-wires its ANSI console reporter, so
882
- * plugins typically omit `reporters`.
883
- */
884
- interface DevframeDefineDiagnosticsOptions<Codes extends Record<string, DiagnosticDefinition>> {
885
- docsBase?: string | ((code: keyof Codes) => string | undefined);
886
- codes: Codes;
887
- reporters?: ReadonlyArray<(d: Diagnostic, o?: any) => void>;
888
- }
889
847
  /**
890
848
  * Host for structured diagnostics — a thin layer over `nostics` that lets
891
849
  * integrations register their own coded errors/warnings into a shared
@@ -928,27 +886,31 @@ interface DevframeDiagnosticsHost {
928
886
  register: (definitions: Record<string, unknown>) => void;
929
887
  /**
930
888
  * Build a typed diagnostics object with the host's ANSI console reporter
931
- * pre-wired. Mirrors `nostics`'s `defineDiagnostics` so integrations don't
932
- * need to take a direct dependency on `nostics`.
889
+ * pre-wired. The same `devframe/utils/nostics` `defineDiagnostics` every
890
+ * built-in plugin's module-level `diagnostics.ts` uses, so integrations
891
+ * don't need to take a direct dependency on `nostics`.
933
892
  */
934
- defineDiagnostics: <const Codes extends Record<string, DiagnosticDefinition>>(options: DevframeDefineDiagnosticsOptions<Codes>) => ReturnType<typeof defineDiagnostics<Codes, any>>;
893
+ defineDiagnostics: typeof defineDiagnostics;
935
894
  }
936
895
  //#endregion
937
896
  //#region src/types/host.d.ts
938
897
  interface DevframeHost {
939
898
  /**
940
- * Serve a static directory at the given URL base. Called by
941
- * `DevframeViewHost.hostStatic`. Implementations map this to whatever
899
+ * Serve static assets at the given URL base — a local directory, or a
900
+ * resolved {@link RemoteAssetsStore} back-proxy. Called by
901
+ * `DevframeViewHost.hostStatic` (which normalizes `RemoteAssets`
902
+ * declarations into stores first). Implementations map this to whatever
942
903
  * the underlying runtime expects (Vite middleware, h3 handler, no-op
943
- * for build snapshots).
904
+ * for build snapshots) — the shared engine in
905
+ * `devframe/utils/serve-static` accepts either shape.
944
906
  */
945
- mountStatic: (base: string, distDir: string) => void | Promise<void>;
907
+ mountStatic: (base: string, source: string | RemoteAssetsStore) => void | Promise<void>;
946
908
  /**
947
909
  * Serve the host's connection meta (`__connection.json`) at the given URL
948
910
  * base, so a devframe SPA mounted there can discover the RPC/WS endpoint
949
911
  * via `connectDevframe()`'s relative `./__connection.json` fetch.
950
912
  *
951
- * Called by `mountDevframe` for each mounted devframe (alongside
913
+ * Called by `ctx.install` for each mounted devframe (alongside
952
914
  * `mountStatic`). Without it, an embedded SPA can only discover the
953
915
  * endpoint by inheriting it from a same-origin parent window — which fails
954
916
  * for cross-origin or sandboxed iframes. Implementations serve the same
@@ -1007,14 +969,17 @@ interface DevframeViewHost {
1007
969
  */
1008
970
  buildStaticDirs: {
1009
971
  baseUrl: string;
1010
- distDir: string;
972
+ source: StaticAssetsSource;
1011
973
  }[];
1012
974
  /**
1013
975
  * Helper to host static files
1014
976
  * - In `dev` mode, it will register middleware to `viteServer.middlewares` to host the static files
1015
977
  * - In `build` mode, it will copy the static files to the dist directory
978
+ *
979
+ * Accepts a local dist directory, or a {@link StaticAssetsSource} remote
980
+ * declaration served through devframe's caching CDN back-proxy.
1016
981
  */
1017
- hostStatic: (baseUrl: string, distDir: string) => void;
982
+ hostStatic: (baseUrl: string, source: StaticAssetsSource) => void;
1018
983
  }
1019
984
  //#endregion
1020
985
  //#region src/types/scope.d.ts
@@ -1304,8 +1269,6 @@ interface DevframeNodeContext {
1304
1269
  diagnostics: DevframeDiagnosticsHost;
1305
1270
  /**
1306
1271
  * Agent host — aggregates the agent-exposed surface of this devtool.
1307
- *
1308
- * @experimental
1309
1272
  */
1310
1273
  agent: DevframeAgentHost;
1311
1274
  /**
@@ -1317,6 +1280,22 @@ interface DevframeNodeContext {
1317
1280
  * absorb setup-order differences between provider and consumer.
1318
1281
  */
1319
1282
  services: DevframeServicesHost;
1283
+ /**
1284
+ * This context's own {@link ConnectionMeta.configs} — static, boot-time
1285
+ * config a host publishes once through the connection handshake and every
1286
+ * client reads read-only. A plain, **non-reactive** object: mutate it
1287
+ * during `setup(ctx)` (a plugin sets its keys, a hub aggregates across
1288
+ * every installed devframe), never during the session — it's serialized
1289
+ * once, after setup, and changing it afterwards reaches no client.
1290
+ *
1291
+ * ```ts
1292
+ * ctx.staticConfig.dock = {
1293
+ * ...ctx.staticConfig.dock,
1294
+ * categoryOrder: { ...ctx.staticConfig.dock?.categoryOrder, ...myOrder },
1295
+ * }
1296
+ * ```
1297
+ */
1298
+ staticConfig: Partial<DevframeConnectionConfigsRegistry>;
1320
1299
  /**
1321
1300
  * Create a namespace-scoped view of this context. The returned
1322
1301
  * `ctx.scope('my-plugin')` auto-namespaces every RPC id, shared-state
@@ -1344,8 +1323,8 @@ interface DevframeNodeContext {
1344
1323
  */
1345
1324
  interface ConnectionMetaWebsocket {
1346
1325
  /**
1347
- * Path to the WS endpoint. Relative paths (the default, e.g. `__devframe_ws`) are
1348
- * resolved against `__connection.json`'s location; absolute paths (`/__devframe_ws`)
1326
+ * Path to the WS endpoint. Relative paths (the default, e.g. `__ws`) are
1327
+ * resolved against `__connection.json`'s location; absolute paths (`/__ws`)
1349
1328
  * resolve against the page origin.
1350
1329
  */
1351
1330
  path?: string;
@@ -1354,8 +1333,32 @@ interface ConnectionMetaWebsocket {
1354
1333
  /** Override the host (`hostname[:port]`). Use for a fully cross-origin endpoint. */
1355
1334
  host?: string;
1356
1335
  }
1336
+ /**
1337
+ * Object form of {@link ConnectionMeta.sse} — the same proxy-safe shape and
1338
+ * resolution rules as {@link ConnectionMetaWebsocket}, producing an
1339
+ * `http(s)://` endpoint instead of a `ws(s)://` one. Set `port` (and/or
1340
+ * `host`) only when the SSE endpoint genuinely lives on a different origin
1341
+ * than the page, e.g. a side-car server on its own port.
1342
+ */
1343
+ interface ConnectionMetaSse {
1344
+ /**
1345
+ * Path to the SSE endpoint. Relative paths (the default, e.g. `__sse`)
1346
+ * are resolved against `__connection.json`'s location; absolute paths
1347
+ * (`/__sse`) resolve against the page origin.
1348
+ */
1349
+ path?: string;
1350
+ /** Override the port. Combined with the page hostname unless `host` is set. */
1351
+ port?: number;
1352
+ /** Override the host (`hostname[:port]`). Use for a fully cross-origin endpoint. */
1353
+ host?: string;
1354
+ }
1357
1355
  interface ConnectionMeta {
1358
- backend: 'websocket' | 'static';
1356
+ /**
1357
+ * The server's primary live-RPC transport (`websocket` / `sse`), `static`
1358
+ * for a pre-computed RPC dump with no live server, or `none` for a server
1359
+ * exposing no RPC transport at all (e.g. an MCP-only deployment).
1360
+ */
1361
+ backend: 'websocket' | 'sse' | 'static' | 'none';
1359
1362
  /**
1360
1363
  * WebSocket endpoint, resolved by the client into a `ws(s)://` URL:
1361
1364
  *
@@ -1366,13 +1369,24 @@ interface ConnectionMeta {
1366
1369
  * URL with its protocol swapped, or a path resolved same-origin.
1367
1370
  */
1368
1371
  websocket?: number | string | ConnectionMetaWebsocket;
1372
+ /**
1373
+ * SSE endpoint (`GET` opens the event stream, `POST` carries RPC calls),
1374
+ * resolved by the client into an `http(s)://` URL with the same
1375
+ * proxy-safe rules as {@link ConnectionMeta.websocket}:
1376
+ *
1377
+ * - {@link ConnectionMetaSse} — the proxy-flexible default; a
1378
+ * same-origin path relative to `__connection.json`.
1379
+ * - `string` — a full `http(s)://` URL used verbatim, or a path
1380
+ * resolved same-origin.
1381
+ */
1382
+ sse?: string | ConnectionMetaSse;
1369
1383
  /**
1370
1384
  * Present when the dev server exposes a route-based MCP endpoint
1371
1385
  * (`cli.mcp`). Advertises the MCP Streamable-HTTP route so in-browser
1372
1386
  * tooling (e.g. an MCP inspector) can discover it without guessing the
1373
1387
  * path. `path` is relative to `__connection.json`'s location, like the
1374
1388
  * WebSocket `path`. `port` is set when the endpoint lives on a side-car
1375
- * server on its own port (bridge mode — `viteDevBridge`,
1389
+ * server on its own port (bridge mode — `devframeViteBridge`,
1376
1390
  * `@devframes/next`): the client combines the page hostname with `port`
1377
1391
  * and resolves `path` against that origin, mirroring
1378
1392
  * {@link ConnectionMetaWebsocket.port}.
@@ -1423,16 +1437,38 @@ interface ConnectionMeta {
1423
1437
  * token same-origin until the requesting origin has been verified.
1424
1438
  */
1425
1439
  viewerOriginToken?: string;
1440
+ /**
1441
+ * Static, host-declared configuration — baked in once at connect time and
1442
+ * fixed for the life of the server (e.g. a hub's UI rebrand, or its
1443
+ * aggregated dock-bar layout preferences). Read-only from the browser: a
1444
+ * client only ever reads `rpc.connectionMeta.configs`, never writes to it.
1445
+ *
1446
+ * Contrast this with {@link DevframeSettingsRegistry} (`ctx.scope(ns).settings`)
1447
+ * and a hub's `devframe:user-settings` shared-state key — both are
1448
+ * mutable, user-editable, and synced bidirectionally over RPC for the
1449
+ * life of the session. `configs` is the opposite: one-way, immutable,
1450
+ * decided by whoever assembled the server.
1451
+ *
1452
+ * Each key is owned by one package, contributed via declaration merging:
1453
+ *
1454
+ * ```ts
1455
+ * declare module 'devframe/types' {
1456
+ * interface DevframeConnectionConfigsRegistry {
1457
+ * 'my-key': { some: 'shape' }
1458
+ * }
1459
+ * }
1460
+ * ```
1461
+ */
1462
+ configs?: Partial<DevframeConnectionConfigsRegistry>;
1426
1463
  }
1427
- //#endregion
1428
- //#region src/types/utils.d.ts
1429
- type Thenable<T> = T | Promise<T>;
1430
- type EntriesToObject<T extends readonly [string, any][]> = { [K in T[number] as K[0]]: K[1]; };
1431
- type PartialWithoutId<T extends {
1432
- id: string;
1433
- }> = Partial<Omit<T, 'id'>> & {
1434
- id: string;
1435
- };
1464
+ /**
1465
+ * Augmentation point for {@link ConnectionMeta.configs}. Empty by default —
1466
+ * a package that wants to publish static, boot-time config through the
1467
+ * connection handshake augments this interface with its own key (see
1468
+ * {@link ConnectionMeta.configs} for the pattern). `@devframes/hub`
1469
+ * augments it with `dock`; `@devframes/hub-ui` augments it with `ui`.
1470
+ */
1471
+ interface DevframeConnectionConfigsRegistry {}
1436
1472
  //#endregion
1437
1473
  //#region src/node/auth/handler.d.ts
1438
1474
  /**
@@ -1442,7 +1478,7 @@ type PartialWithoutId<T extends {
1442
1478
  * the handshake RPC functions, the resolver gate, the connect-time trust
1443
1479
  * hook, and the startup banner.
1444
1480
  *
1445
- * `startHttpAndWs` accepts one of these directly via its `auth` option —
1481
+ * `initDevframe` / `initHub` accept one of these directly via their `auth` option —
1446
1482
  * see {@link https://devfra.me | devframe}'s server docs — or a host can
1447
1483
  * wire the four pieces itself against a lower-level transport.
1448
1484
  */
@@ -1461,12 +1497,12 @@ interface DevframeAuthHandler {
1461
1497
  */
1462
1498
  authorize: (methodName: string, session: DevframeNodeRpcSession) => boolean;
1463
1499
  /**
1464
- * Connect-time trust: reads a bearer token off the peer's upgrade request
1465
- * (an `Authorization: Bearer <token>` header, or a static/pre-shared
1466
- * token from `clientAuthTokens`) and, when valid, marks the session
1500
+ * Connect-time trust: reads a bearer token off the connection's initial
1501
+ * request (a static/pre-shared token from `clientAuthTokens`, or a token
1502
+ * minted by the code exchange) and, when valid, marks the session
1467
1503
  * trusted immediately — before the client's own handshake call.
1468
1504
  */
1469
- onConnect: (peer: Peer, session: DevframeNodeRpcSession) => void;
1505
+ onConnect: (connection: DevframeRpcConnection, session: DevframeNodeRpcSession) => void;
1470
1506
  /**
1471
1507
  * Print the current one-time code and its magic-link URL. Devframe stays
1472
1508
  * headless — call this yourself once the server is listening. Safe to
@@ -1485,12 +1521,11 @@ interface DevframeAuthHandler {
1485
1521
  }
1486
1522
  //#endregion
1487
1523
  //#region src/types/devframe.d.ts
1488
- type DevframeRuntime = 'cli' | 'build' | 'spa' | 'vite' | 'embedded';
1489
1524
  /**
1490
1525
  * Classification of how a devframe is being deployed. Hosted adapters
1491
1526
  * (`vite`, `embedded`) share their origin with a host app and must
1492
1527
  * namespace their mount path under `/__<id>/`. Standalone adapters
1493
- * (`cli`, `spa`, `build`) own the origin and default to `/`.
1528
+ * (`cli`, `build`) own the origin and default to `/`.
1494
1529
  */
1495
1530
  type DevframeDeploymentKind = 'standalone' | 'hosted';
1496
1531
  /**
@@ -1512,7 +1547,7 @@ type DevframeDuplicationStrategy = 'warn' | 'silent' | 'throw' | 'duplicate';
1512
1547
  *
1513
1548
  * 1. **Same server, different route** (default) — leave `port`/`url` unset.
1514
1549
  * The socket shares the HTTP server's port and binds to `route`
1515
- * (`__devframe_ws`). The client connects to its own origin, so the link
1550
+ * (`__ws`). The client connects to its own origin, so the link
1516
1551
  * survives a reverse proxy that rewrites the host/port/subpath.
1517
1552
  *
1518
1553
  * 2. **Different port** — set `port`. The socket binds on its own port on the
@@ -1524,29 +1559,49 @@ type DevframeDuplicationStrategy = 'warn' | 'silent' | 'throw' | 'duplicate';
1524
1559
  interface DevframeWsOptions {
1525
1560
  /**
1526
1561
  * Upgrade route segment the socket binds to and is advertised at, relative
1527
- * to the SPA base. Default: `__devframe_ws`.
1562
+ * to the SPA base. Default: `__ws`.
1528
1563
  */
1529
1564
  route?: string;
1530
1565
  /**
1531
1566
  * Bind the socket on its own port instead of sharing the HTTP port. The
1532
- * browser connects to this port on the page's hostname.
1567
+ * browser connects to this port on the page's hostname. Implies
1568
+ * {@link DevframeWsOptions.sidecar}.
1533
1569
  */
1534
1570
  port?: number;
1571
+ /**
1572
+ * Start a side-car WebSocket server on a free port, for hosts whose request
1573
+ * handlers can't accept upgrades (Next.js route handlers, Nitro, Rsbuild).
1574
+ * The resolved port is advertised in `__connection.json`, so the browser
1575
+ * finds it without any further wiring. Set `port` instead to pin it.
1576
+ */
1577
+ sidecar?: boolean;
1535
1578
  /**
1536
1579
  * Advertise a fixed, fully-qualified endpoint on another origin (a full
1537
1580
  * `ws://`/`wss://` URL). Takes precedence over `port`/`route` in the meta.
1538
1581
  */
1539
1582
  url?: string;
1540
1583
  }
1584
+ /**
1585
+ * Controls the SSE RPC endpoint — the WebSocket-free transport for hosts
1586
+ * and proxies where the upgrade isn't available. It rides whatever HTTP
1587
+ * surface serves the instance (the same one serving `__connection.json`),
1588
+ * so a relative `route` always resolves; there is no port plumbing of its
1589
+ * own. Enabled by default alongside the WebSocket; pass `sse: false` to
1590
+ * disable, or `ws: false` to run SSE-only (`backend: 'sse'`).
1591
+ */
1592
+ interface DevframeSseOptions {
1593
+ /**
1594
+ * Route segment the SSE endpoint binds to and is advertised at, relative
1595
+ * to the SPA base. Default: `__sse`.
1596
+ */
1597
+ route?: string;
1598
+ }
1541
1599
  /**
1542
1600
  * Configuration for the route-based MCP server mounted alongside the dev
1543
1601
  * server (opt-in via {@link DevframeCliOptions.mcp}). The endpoint speaks
1544
1602
  * the MCP Streamable-HTTP transport over the same origin as the SPA,
1545
1603
  * exposing the definition's `ctx.agent` tools + shared-state resources to
1546
1604
  * external MCP clients connected to the *running* server.
1547
- *
1548
- * @experimental The agent-native surface is experimental and may change
1549
- * without a major version bump until it stabilizes.
1550
1605
  */
1551
1606
  interface McpRouteOptions {
1552
1607
  /**
@@ -1588,7 +1643,7 @@ interface DevframeCliOptions {
1588
1643
  /**
1589
1644
  * Authentication for the standalone dev server.
1590
1645
  *
1591
- * - `undefined` / `true` — the standalone adapters (`cli` / `spa` /
1646
+ * - `undefined` / `true` — the standalone adapters (`cli` /
1592
1647
  * served `build`) auto-wire devframe's interactive OTP auth
1593
1648
  * (`createInteractiveAuth`): an untrusted client can only reach
1594
1649
  * `anonymous:` methods until it exchanges the printed one-time code.
@@ -1599,7 +1654,7 @@ interface DevframeCliOptions {
1599
1654
  * The `--no-auth` CLI flag maps here for one-off runs.
1600
1655
  * - A {@link DevframeAuthHandler} — a custom handler (e.g. a tuned
1601
1656
  * `createInteractiveAuth`, or an entirely different scheme) passed
1602
- * straight through to `startHttpAndWs`.
1657
+ * straight through to the RPC transport binding.
1603
1658
  *
1604
1659
  * Hosted adapters (`vite`, `embedded`) ignore this and defer to the host's
1605
1660
  * auth; `@vitejs/devtools` honors the equivalent `devtools.clientAuth`.
@@ -1619,21 +1674,31 @@ interface DevframeCliOptions {
1619
1674
  * - {@link McpRouteOptions} — customise the route path / allowed origins.
1620
1675
  *
1621
1676
  * The `--mcp` / `--no-mcp` CLI flags override this per run.
1622
- *
1623
- * @experimental
1624
1677
  */
1625
1678
  mcp?: boolean | McpRouteOptions;
1626
- /** Author's SPA dist directory (served as the devframe's UI). */
1627
- distDir?: string;
1679
+ /**
1680
+ * Author's SPA dist — served as the devframe's UI. A local directory, or
1681
+ * a {@link StaticAssetsSource} remote declaration (`{ package, version }`)
1682
+ * served through devframe's caching CDN back-proxy so the assets need not
1683
+ * ship inside the node package.
1684
+ */
1685
+ distDir?: StaticAssetsSource;
1628
1686
  /**
1629
1687
  * How the browser reaches the RPC WebSocket. Defaults to sharing the HTTP
1630
- * port on the `__devframe_ws` route. See {@link DevframeWsOptions} for the
1631
- * different-port and remote-origin variants.
1688
+ * port on the `__ws` route. See {@link DevframeWsOptions} for the
1689
+ * different-port and remote-origin variants. Pass `false` to serve no
1690
+ * WebSocket at all — clients connect over SSE instead (`backend: 'sse'`).
1632
1691
  */
1633
- ws?: DevframeWsOptions;
1692
+ ws?: DevframeWsOptions | false;
1693
+ /**
1694
+ * How the browser reaches the SSE RPC endpoint — enabled by default
1695
+ * alongside the WebSocket as the more portable transport. Pass `false`
1696
+ * to disable, or a {@link DevframeSseOptions} to change its route.
1697
+ */
1698
+ sse?: boolean | DevframeSseOptions;
1634
1699
  /**
1635
1700
  * Capability-side CAC hook. Called with the CAC instance after the
1636
- * adapter registers its built-in commands (`build` / `spa` / `mcp`)
1701
+ * adapter registers its built-in commands (`build` / `mcp`)
1637
1702
  * but before `createCac`'s own `configureCli` caller. Use this to
1638
1703
  * contribute tool-specific flags and subcommands from the definition
1639
1704
  * itself.
@@ -1669,12 +1734,12 @@ interface DevframeCliOptions {
1669
1734
  /**
1670
1735
  * Default dock attributes for the iframe entry a hub synthesizes when it
1671
1736
  * mounts this devframe. Framework-neutral metadata only — the hub layer
1672
- * (`mountDevframe`) merges these beneath its per-mount `dock` overrides,
1737
+ * (`ctx.install`) merges these beneath its per-mount `dock` overrides,
1673
1738
  * which in turn sit beneath the locked, derived `id` / `type` / `url`.
1674
1739
  *
1675
1740
  * Every field is optional. `title` / `icon` default to the definition's
1676
1741
  * `name` / `icon` when omitted here; the rest are unset by default.
1677
- * Standalone adapters (`cli` / `spa` / `build`) ignore this entirely.
1742
+ * Standalone adapters (`cli` / `build`) ignore this entirely.
1678
1743
  */
1679
1744
  interface DevframeDockDefaults {
1680
1745
  /** Dock entry title. Defaults to the definition's `name`. */
@@ -1711,22 +1776,6 @@ interface DevframeDockDefaults {
1711
1776
  /** Id of the dock group this entry collapses under, if any. */
1712
1777
  groupId?: string;
1713
1778
  }
1714
- interface DevframeSpaOptions {
1715
- base?: string;
1716
- /**
1717
- * How the deployed SPA loads its data.
1718
- * - `'query'` — read from URL search params.
1719
- * - `'upload'` — accept a file drag-drop.
1720
- * - `'none'` — use the baked RPC dump only.
1721
- */
1722
- loader?: 'query' | 'upload' | 'none';
1723
- }
1724
- interface DevframeBrowserContext {
1725
- /**
1726
- * The connected RPC client (may be write-disabled in static/spa modes).
1727
- */
1728
- rpc: unknown;
1729
- }
1730
1779
  /**
1731
1780
  * Runtime information threaded into `setup(ctx, info)`. Adapters
1732
1781
  * populate the fields that make sense for their deployment. In
@@ -1753,50 +1802,48 @@ interface DevframeDefinition {
1753
1802
  };
1754
1803
  /**
1755
1804
  * Default dock attributes applied when a hub mounts this devframe as an
1756
- * iframe dock entry. Consulted only by hub adapters (`mountDevframe`),
1805
+ * iframe dock entry. Consulted only by the hub install path (`ctx.install`),
1757
1806
  * which merge these beneath the per-mount `dock` overrides; standalone
1758
- * adapters (`cli` / `spa` / `build`) ignore it.
1807
+ * adapters (`cli` / `build`) ignore it.
1759
1808
  *
1760
1809
  * @see {@link DevframeDockDefaults}
1761
1810
  */
1762
1811
  dock?: DevframeDockDefaults;
1763
1812
  /**
1764
1813
  * Mount path override. Defaults depend on the adapter:
1765
- * `/` for standalone (`cli` / `spa` / `build`), `/__<id>/` for hosted
1814
+ * `/` for standalone (`cli` / `build`), `/__<id>/` for hosted
1766
1815
  * (`vite` / `embedded`).
1767
1816
  */
1768
1817
  basePath?: string;
1769
1818
  /**
1770
1819
  * How a hub reacts when another devframe sharing this one's `id` is
1771
1820
  * mounted onto the same hub. Consulted only by hub adapters
1772
- * (`mountDevframe`); standalone adapters (`cli` / `spa` / `build`)
1821
+ * (`ctx.install`); standalone adapters (`cli` / `build`)
1773
1822
  * ignore it.
1774
1823
  *
1775
1824
  * @default 'warn'
1776
1825
  */
1777
1826
  duplicationStrategy?: DevframeDuplicationStrategy;
1778
1827
  /**
1779
- * Declares which runtimes meaningfully support this devframe. Consulted
1780
- * by adapters that can act on a plain `false` before doing any work:
1781
- * `createCac` skips registering the `build` subcommand entirely when
1782
- * `capabilities.build` is `false` — useful for a devframe whose value is
1783
- * inherently live (e.g. it manages real files on disk), so a static
1784
- * export would only ever produce a broken, write-less shell of the tool.
1785
- * The `Record<string, boolean>` shape is reserved for finer-grained
1786
- * sub-capabilities and currently unconsumed by any adapter.
1828
+ * Declares which runtimes meaningfully support this devframe. Adapters
1829
+ * act on a `false` before doing any work:
1830
+ *
1831
+ * - `build: false` — `createCac` skips registering the `build` subcommand,
1832
+ * and `createBuild` refuses (throws `DF0042`) unless `{ force: true }`.
1833
+ * Useful for a devframe whose value is inherently live (e.g. it manages
1834
+ * real files on disk), so a static export would only ever produce a
1835
+ * broken, write-less shell of the tool.
1836
+ * - `dev: false` — `createDevServer` refuses (throws `DF0058`) unless
1837
+ * `{ force: true }`. Useful for a devframe that only makes sense as a
1838
+ * static export (e.g. a report generator with nothing to serve live).
1787
1839
  */
1788
1840
  capabilities?: {
1789
- dev?: boolean | Record<string, boolean>;
1790
- build?: boolean | Record<string, boolean>;
1791
- spa?: boolean | Record<string, boolean>;
1841
+ dev?: boolean;
1842
+ build?: boolean;
1792
1843
  };
1793
1844
  /** Server-side setup — the primary entrypoint. Runs in every runtime. */
1794
1845
  setup: (ctx: DevframeNodeContext, info?: DevframeSetupInfo) => void | Promise<void>;
1795
- /** Browser-only setup for the SPA adapter (bundled into the client). */
1796
- setupBrowser?: (ctx: DevframeBrowserContext) => void | Promise<void>;
1797
1846
  cli?: DevframeCliOptions;
1798
- spa?: DevframeSpaOptions;
1799
1847
  }
1800
- declare function defineDevframe(d: DevframeDefinition): DevframeDefinition;
1801
1848
  //#endregion
1802
- export { DevframeRpcServerFunctions as $, DevframeSettingsStore as A, DevframeAgentHostEvents as At, DevframeDefineDiagnosticsOptions as B, DevframeServicesHost as C, AgentResourceContent as Ct, DevframeScopedStreamingHost as D, AgentToolProvider as Dt, DevframeScopedNodeRpc as E, AgentToolInput as Et, ScopedSharedStates as F, InferCliFlags as Ft, RpcBroadcastOptions as G, DevframeDiagnosticsHost as H, SettingsForNamespace as I, defineCliFlags as It, RpcSharedStateHost as J, RpcFunctionsHost as K, DevframeViewHost as L, parseCliFlags as Lt, ScopedClientFunctions as M, EventUnsubscribe as Mt, ScopedRpcFn as N, EventsMap as Nt, DevframeSettings as O, AgentToolProviderHandle as Ot, ScopedServerFunctions as P, CliFlagsSchema as Pt, DevframeRpcClientFunctions as Q, DevframeHost as R, DevframeServiceOf as S, AgentResource as St, DevframeScopedNodeContext as T, AgentTool as Tt, DevframeDiagnosticsLogger as U, DevframeDiagnosticsDefinition as V, DevframeNodeRpcSession as W, RpcStreamingChannelOptions as X, RpcStreamingChannel as Y, RpcStreamingHost as Z, ConnectionMeta as _, SharedStateOptions as _t, DevframeDockDefaults as a, StreamReader as at, DevframeNodeContext as b, AgentHandle as bt, DevframeSetupInfo as c, createStreamReader as ct, McpRouteOptions as d, ImmutableArray as dt, DevframeRpcSharedStates as et, defineDevframe as f, ImmutableMap as ft, Thenable as g, SharedStateEvents as gt, PartialWithoutId as h, SharedState as ht, DevframeDeploymentKind as i, StreamErrorPayload as it, ScopedBroadcastOptions as j, EventEmitter as jt, DevframeSettingsRegistry as k, DevframeAgentHost as kt, DevframeSpaOptions as l, createStreamSink as lt, EntriesToObject as m, ImmutableSet as mt, DevframeCliOptions as n, CreateStreamReaderOptions as nt, DevframeDuplicationStrategy as o, StreamSink as ot, DevframeAuthHandler as p, ImmutableObject as pt, RpcSharedStateGetOptions as q, DevframeDefinition as r, CreateStreamSinkOptions as rt, DevframeRuntime as s, StreamSinkEvents as st, DevframeBrowserContext as t, BufferedChunk as tt, DevframeWsOptions as u, Immutable as ut, ConnectionMetaWebsocket as v, SharedStatePatch as vt, DevframeServicesRegistry as w, AgentResourceInput as wt, DevframeServiceId as x, AgentManifest as xt, DevframeCapabilities as y, createSharedState as yt, DevframeStorageScope as z };
1849
+ export { StreamReader as $, ScopedServerFunctions as A, defineCliFlags as At, RpcFunctionsHost as B, DevframeScopedStreamingHost as C, DevframeAgentHost as Ct, ScopedBroadcastOptions as D, EventsMap as Dt, DevframeSettingsStore as E, EventUnsubscribe as Et, DevframeStorageScope as F, RpcStreamingHost as G, RpcSharedStateHost as H, DevframeDiagnosticsHost as I, DevframeRpcSharedStates as J, DevframeRpcClientFunctions as K, DevframeDiagnosticsLogger as L, SettingsForNamespace as M, DevframeViewHost as N, ScopedClientFunctions as O, CliFlagsSchema as Ot, DevframeHost as P, StreamErrorPayload as Q, DevframeNodeRpcSession as R, DevframeScopedNodeRpc as S, AgentToolProviderHandle as St, DevframeSettingsRegistry as T, EventEmitter as Tt, RpcStreamingChannel as U, RpcSharedStateGetOptions as V, RpcStreamingChannelOptions as W, CreateStreamReaderOptions as X, BufferedChunk as Y, CreateStreamSinkOptions as Z, DevframeServiceId as _, AgentResourceContent as _t, DevframeDuplicationStrategy as a, ImmutableArray as at, DevframeServicesRegistry as b, AgentToolInput as bt, DevframeWsOptions as c, ImmutableSet as ct, ConnectionMeta as d, SharedStateOptions as dt, StreamSink as et, ConnectionMetaSse as f, SharedStatePatch as ft, DevframeNodeContext as g, AgentResource as gt, DevframeConnectionConfigsRegistry as h, AgentManifest as ht, DevframeDockDefaults as i, Immutable as it, ScopedSharedStates as j, parseCliFlags as jt, ScopedRpcFn as k, InferCliFlags as kt, McpRouteOptions as l, SharedState as lt, DevframeCapabilities as m, AgentHandle as mt, DevframeDefinition as n, createStreamReader as nt, DevframeSetupInfo as o, ImmutableMap as ot, ConnectionMetaWebsocket as p, createSharedState as pt, DevframeRpcServerFunctions as q, DevframeDeploymentKind as r, createStreamSink as rt, DevframeSseOptions as s, ImmutableObject as st, DevframeCliOptions as t, StreamSinkEvents as tt, DevframeAuthHandler as u, SharedStateEvents as ut, DevframeServiceOf as v, AgentResourceInput as vt, DevframeSettings as w, DevframeAgentHostEvents as wt, DevframeScopedNodeContext as x, AgentToolProvider as xt, DevframeServicesHost as y, AgentTool as yt, RpcBroadcastOptions as z };
@@ -1,9 +1,7 @@
1
- import { t as devframeReporter } from "./diagnostics-reporter-CsIG85Q5.mjs";
2
- import { defineDiagnostics } from "nostics";
1
+ import { i as defineDiagnostics } from "./nostics-CzECRXpE.mjs";
3
2
  //#region src/rpc/diagnostics.ts
4
3
  const diagnostics = defineDiagnostics({
5
4
  docsBase: "https://devfra.me/errors",
6
- reporters: [devframeReporter],
7
5
  codes: {
8
6
  DF0019: {
9
7
  why: (p) => `RPC function "${p.name}" has \`agent\` set but \`jsonSerializable\` is not \`true\` — MCP requires JSON-serializable data.`,