devframe 1.3.1 → 1.3.3
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.
- package/dist/{_shared-Cm4iD0L3.d.mts → _shared-BxeuukaL.d.mts} +2 -4
- package/dist/{_shared-C61zPwIz.mjs → _shared-CtXCQFTV.mjs} +6 -9
- package/dist/adapters/build.d.mts +3 -5
- package/dist/adapters/build.mjs +7 -8
- package/dist/adapters/cac.d.mts +1 -3
- package/dist/adapters/cac.mjs +5 -7
- package/dist/adapters/dev.d.mts +6 -8
- package/dist/adapters/dev.mjs +2 -2
- package/dist/adapters/embedded.d.mts +2 -4
- package/dist/adapters/embedded.mjs +1 -2
- package/dist/adapters/initiate.d.mts +10 -10
- package/dist/adapters/initiate.mjs +1 -2
- package/dist/adapters/mcp.d.mts +2 -2
- package/dist/adapters/mcp.mjs +1 -2
- package/dist/{agentic-C6SCkdtj.d.mts → agentic-DVgUzwhV.d.mts} +1 -3
- package/dist/{browser-agent-Pu-FLk6I.mjs → browser-agent-DmAotroz.mjs} +1 -2
- package/dist/{browser-agent-rpc-KH4HHvHf.mjs → browser-agent-rpc-CS80Sphv.mjs} +3 -5
- package/dist/cli/main.d.mts +1 -3
- package/dist/cli/main.mjs +3 -4
- package/dist/client/index.d.mts +6 -30
- package/dist/client/index.mjs +47 -72
- package/dist/{client-agent-iBkMYxqn.mjs → client-agent-qNMgDUev.mjs} +7 -12
- package/dist/constants.d.mts +1 -5
- package/dist/constants.mjs +2 -3
- package/dist/{context-BGJi0ITA.d.mts → context-B-AARy_U.d.mts} +1 -3
- package/dist/{context-D_jSSdME.mjs → context-BTxC4QrJ.mjs} +4 -5
- package/dist/{context-CAJ5V017.mjs → context-C5FcbWQi.mjs} +25 -41
- package/dist/{crypto-token-TVbGGFuj.mjs → crypto-token-CUhPE_ei.mjs} +1 -2
- package/dist/{define-BLWPsH6y.mjs → define-C8h-fyD3.mjs} +1 -2
- package/dist/{dev-BKBjIpX3.mjs → dev-Cu_iwSCy.mjs} +9 -11
- package/dist/{diagnostics-E_PvUPsA.mjs → diagnostics-DC1-WcvN.mjs} +2 -3
- package/dist/{dist-CO98PBnQ.mjs → dist-BWGpvt-z.mjs} +1 -2
- package/dist/{dist-CZXfGEkd.mjs → dist-CZ-TySHD.mjs} +3 -11
- package/dist/{events-0wDwalmL.mjs → events-qWCKwD8-.mjs} +1 -2
- package/dist/{handler-DmaAfpGq.mjs → handler-DkLlj3-B.mjs} +3 -5
- package/dist/{hash-DdPnc4k3.mjs → hash-DHqpWeMO.mjs} +4 -8
- package/dist/{host-h3-BROI6SQ4.mjs → host-h3-D1uj5EM8.mjs} +1 -2
- package/dist/{import-runtime-module-BzlEQ9PI.mjs → import-runtime-module-DsdqJ1gK.mjs} +2 -3
- package/dist/in-page-channel/index.d.mts +3 -12
- package/dist/in-page-channel/index.mjs +10 -16
- package/dist/{index-CeEtxDmK.d.mts → index-BIRF0E5l.d.mts} +0 -2
- package/dist/{index-Bia1vKjL.d.mts → index-BKu9BxcT.d.mts} +0 -2
- package/dist/{context-BNxFOPbX.d.mts → index-BhUqJUHG.d.mts} +1408 -1442
- package/dist/index.d.mts +7 -8
- package/dist/index.mjs +3 -4
- package/dist/{instance-registry-C_4PpB6N.mjs → instance-registry-DwmnWyCK.mjs} +4 -10
- package/dist/{instance-shell-m4sY2oTG.mjs → instance-shell-Coid7CP6.mjs} +38 -17
- package/dist/{instance-shell-GihbmXoF.d.mts → instance-shell-DTk514M9.d.mts} +6 -10
- package/dist/{interactive-auth-DdDxs3WF.mjs → interactive-auth-BURwIAvE.mjs} +6 -8
- package/dist/internal/index.d.mts +9 -29
- package/dist/internal/index.mjs +13 -15
- package/dist/{mcp-content-QImBQO8e.d.mts → mcp-content-0a0mpCL5.d.mts} +1 -3
- package/dist/{mcp-content-DN3O212x.mjs → mcp-content-CqU8yaF7.mjs} +1 -2
- package/dist/{mrmime-40h5OOIp.mjs → mrmime-y_XyiVcd.mjs} +1 -2
- package/dist/node/auth.d.mts +84 -3
- package/dist/node/auth.mjs +2 -2
- package/dist/node/hub-internals.d.mts +11 -2
- package/dist/node/hub-internals.mjs +2 -2
- package/dist/node/index.d.mts +4 -6
- package/dist/node/index.mjs +2 -2
- package/dist/{nostics-D0PvLZsn.mjs → nostics-InlX4tmd.mjs} +2 -4
- package/dist/{origin-DZit9g29.mjs → origin-Ck7mLbKU.mjs} +1 -2
- package/dist/recipes/interactive-auth.d.mts +3 -5
- package/dist/recipes/interactive-auth.mjs +1 -2
- package/dist/{remote-assets-eBvSKZMS.d.mts → remote-assets-5AQMHZnV.d.mts} +0 -2
- package/dist/{remote-assets-B-n83kUY.mjs → remote-assets-DhonNeo_.mjs} +5 -8
- package/dist/{revoke-CeQUo6KI.mjs → revoke-D6KA3vwr.mjs} +2 -3
- package/dist/{rolldown-runtime-B4iAMlE-.mjs → rolldown-runtime-BVN1G_yT.mjs} +6 -7
- package/dist/rpc/client.d.mts +2 -4
- package/dist/rpc/client.mjs +2 -3
- package/dist/rpc/dump.d.mts +3 -11
- package/dist/rpc/dump.mjs +1 -2
- package/dist/rpc/index.d.mts +122 -4
- package/dist/rpc/index.mjs +6 -8
- package/dist/rpc/server.d.mts +2 -4
- package/dist/rpc/server.mjs +2 -3
- package/dist/rpc/transports/sse-client.d.mts +34 -2
- package/dist/rpc/transports/sse-client.mjs +2 -3
- package/dist/rpc/transports/sse-server.d.mts +5 -7
- package/dist/rpc/transports/sse-server.mjs +4 -5
- package/dist/rpc/transports/ws-bun.d.mts +3 -5
- package/dist/rpc/transports/ws-bun.mjs +2 -3
- package/dist/rpc/transports/ws-client.d.mts +27 -2
- package/dist/rpc/transports/ws-client.mjs +2 -3
- package/dist/rpc/transports/ws-deno.d.mts +3 -5
- package/dist/rpc/transports/ws-deno.mjs +2 -3
- package/dist/rpc/transports/ws-server.d.mts +151 -4
- package/dist/rpc/transports/ws-server.mjs +5 -6
- package/dist/{rpc-core-BLc5hm9X.mjs → rpc-core-BmDHiDR6.mjs} +4 -5
- package/dist/{rpc-core-CGTCla-R.d.mts → rpc-core-CblgPYJ_.d.mts} +5 -7
- package/dist/{serialization-BhuOoL80.mjs → serialization-iiTQ7n21.mjs} +3 -5
- package/dist/{services-install-D5YUwFXW.mjs → services-install-DCuDzMJ-.mjs} +1 -2
- package/dist/{session-DPfj6zQG.mjs → session-BjvoLH3r.mjs} +1 -2
- package/dist/{session-r6PDixP6.d.mts → session-Y9R6tqg4.d.mts} +0 -2
- package/dist/{shared-state-Cc-Jrhma.mjs → shared-state-COV7NCbd.mjs} +4 -6
- package/dist/{state-W4wI6X5X.mjs → state-B_yjfeqo.mjs} +3 -5
- package/dist/{storage-CWI9PZ-5.mjs → storage-DpJ52UB_.mjs} +3 -5
- package/dist/{structured-clone-CbAV5rFI.mjs → structured-clone-B1N_XQvA.mjs} +2 -4
- package/dist/{structured-clone-CgtQ61SA.mjs → structured-clone-D1dOCZvc.mjs} +2 -4
- package/dist/{tool-input-CES3Pc4y.mjs → tool-input-CcCgJ8jq.mjs} +6 -12
- package/dist/types/index.d.mts +5 -5
- package/dist/{types-BmDbfHCx.d.mts → types-KZOyhez5.d.mts} +2 -5
- package/dist/utils/agent-tool-name.d.mts +1 -3
- package/dist/utils/agent-tool-name.mjs +1 -2
- package/dist/utils/colors.d.mts +1 -3
- package/dist/utils/colors.mjs +1 -2
- package/dist/utils/crypto-token.d.mts +1 -3
- package/dist/utils/crypto-token.mjs +1 -2
- package/dist/utils/debounce.d.mts +6 -2
- package/dist/utils/debounce.mjs +1 -2
- package/dist/utils/events.d.mts +2 -4
- package/dist/utils/events.mjs +1 -2
- package/dist/utils/get-port.d.mts +0 -2
- package/dist/utils/get-port.mjs +1 -2
- package/dist/utils/hash.d.mts +1 -3
- package/dist/utils/hash.mjs +1 -2
- package/dist/utils/launch-editor.d.mts +1 -3
- package/dist/utils/launch-editor.mjs +25 -37
- package/dist/utils/nanoid.d.mts +1 -3
- package/dist/utils/nanoid.mjs +1 -2
- package/dist/utils/nostics.d.mts +40 -2
- package/dist/utils/nostics.mjs +1 -2
- package/dist/utils/open.d.mts +1 -3
- package/dist/utils/open.mjs +1 -2
- package/dist/utils/origin.d.mts +55 -2
- package/dist/utils/origin.mjs +1 -2
- package/dist/utils/remote-assets.d.mts +2 -4
- package/dist/utils/remote-assets.mjs +1 -2
- package/dist/utils/serve-static.d.mts +3 -5
- package/dist/utils/serve-static.mjs +3 -4
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -2
- package/dist/utils/simple-schema.d.mts +1 -3
- package/dist/utils/simple-schema.mjs +1 -2
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/streaming-channel.mjs +1 -2
- package/dist/utils/structured-clone.d.mts +1 -3
- package/dist/utils/structured-clone.mjs +1 -2
- package/dist/utils/url.d.mts +1 -3
- package/dist/utils/url.mjs +1 -2
- package/dist/utils/when.d.mts +1 -3
- package/dist/utils/when.mjs +2 -4
- package/dist/{validation-CMfDAti3.mjs → validation-Cjy1P58H.mjs} +7 -13
- package/dist/{wire-codec-B1W3zH3L.mjs → wire-codec-BdngvzfH.mjs} +3 -4
- package/dist/{write-DK7rBUN3.mjs → write-3miSvPaD.mjs} +10 -16
- package/package.json +8 -8
- package/dist/index-CxJatyA1.d.mts +0 -88
- package/dist/index-DuEm0sDH.d.mts +0 -135
- package/dist/nostics-DWvukRwa.d.mts +0 -42
- package/dist/origin-CY6BBHOy.d.mts +0 -58
- package/dist/sse-client-DNdscfu_.d.mts +0 -37
- package/dist/ws-client-6Mrz6eC4.d.mts +0 -30
- package/dist/ws-server-y2R76aSW.d.mts +0 -152
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as DevframeRpcConnection, t as DevframeNodeRpcSessionMeta } from "./session-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { t as StandardSchemaV1 } from "./index-BIRF0E5l.mjs";
|
|
2
|
+
import { g as RpcFunctionDefinitionAny, h as RpcFunctionDefinition } from "./types-KZOyhez5.mjs";
|
|
3
|
+
import { i as BirpcReturn } from "./index-BKu9BxcT.mjs";
|
|
4
|
+
import { RpcFunctionsCollectorBase } from "./rpc/index.mjs";
|
|
5
|
+
import { n as DevframeRpcConnection, t as DevframeNodeRpcSessionMeta } from "./session-Y9R6tqg4.mjs";
|
|
6
|
+
import { defineDiagnostics } from "./utils/nostics.mjs";
|
|
7
|
+
import { a as RemoteAssetsStore, o as StaticAssetsSource } from "./remote-assets-5AQMHZnV.mjs";
|
|
8
8
|
import { CAC } from "cac";
|
|
9
|
-
//#region src/types/events.d.ts
|
|
10
9
|
interface EventsMap {
|
|
11
10
|
[event: string]: any;
|
|
12
11
|
}
|
|
@@ -75,8 +74,6 @@ interface EventEmitter<Events extends EventsMap> {
|
|
|
75
74
|
*/
|
|
76
75
|
once: <K extends keyof Events>(event: K, cb: Events[K]) => EventUnsubscribe;
|
|
77
76
|
}
|
|
78
|
-
//#endregion
|
|
79
|
-
//#region src/types/agent.d.ts
|
|
80
77
|
/**
|
|
81
78
|
* Serializable description of an agent-exposed tool. This is the shape
|
|
82
79
|
* returned by the agent host manifest and surfaced over the wire by
|
|
@@ -280,322 +277,197 @@ interface DevframeAgentHost {
|
|
|
280
277
|
/** Look up a resource by id. */
|
|
281
278
|
getResource: (id: string) => AgentResource | undefined;
|
|
282
279
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
* (valibot, zod, arktype, devframe's built-in `s`, …) used to both (a)
|
|
290
|
-
* derive the CAC option type when the flag is registered and (b) validate
|
|
291
|
-
* the parsed value before it's forwarded to `setup(ctx, { flags })`.
|
|
292
|
-
*/
|
|
293
|
-
type CliFlagsSchema = Record<string, StandardSchemaV1>;
|
|
280
|
+
type ImmutablePrimitive = undefined | null | boolean | string | number | Function;
|
|
281
|
+
type Immutable<T> = T extends ImmutablePrimitive ? T : T extends Array<infer U> ? ImmutableArray<U> : T extends Map<infer K, infer V> ? ImmutableMap<K, V> : T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>;
|
|
282
|
+
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
|
|
283
|
+
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
|
|
284
|
+
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
|
|
285
|
+
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]>; };
|
|
294
286
|
/**
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* ```ts
|
|
299
|
-
* const appFlags = defineCliFlags({
|
|
300
|
-
* depth: v.pipe(v.number(), v.integer()),
|
|
301
|
-
* config: v.optional(v.string()),
|
|
302
|
-
* })
|
|
303
|
-
*
|
|
304
|
-
* defineDevframe({
|
|
305
|
-
* cli: { flags: appFlags },
|
|
306
|
-
* setup(ctx, info) {
|
|
307
|
-
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
308
|
-
* flags.depth // number
|
|
309
|
-
* flags.config // string | undefined
|
|
310
|
-
* },
|
|
311
|
-
* })
|
|
312
|
-
* ```
|
|
287
|
+
* Serializable patch describing a single mutation to a `SharedState`.
|
|
288
|
+
* Structurally compatible with JSON-Patch and is safe to send over RPC.
|
|
313
289
|
*/
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
flags: Record<string, unknown>;
|
|
320
|
-
issues?: string[];
|
|
321
|
-
};
|
|
322
|
-
//#endregion
|
|
323
|
-
//#region src/node/auth/handler.d.ts
|
|
290
|
+
interface SharedStatePatch {
|
|
291
|
+
op: 'add' | 'remove' | 'replace';
|
|
292
|
+
path: readonly (string | number)[];
|
|
293
|
+
value?: unknown;
|
|
294
|
+
}
|
|
324
295
|
/**
|
|
325
|
-
*
|
|
326
|
-
* `devframe/recipes/interactive-auth`'s `createInteractiveAuth`. Bundles
|
|
327
|
-
* everything a host adapter needs to wire an authenticated server:
|
|
328
|
-
* the handshake RPC functions, the resolver gate, the connect-time trust
|
|
329
|
-
* hook, and the startup banner.
|
|
330
|
-
*
|
|
331
|
-
* `initDevframe` / `initHub` accept one of these directly via their `auth` option
|
|
332
|
-
* (see {@link https://devfra.me | devframe}'s server docs), or a host can
|
|
333
|
-
* wire the four pieces itself against a lower-level transport.
|
|
296
|
+
* State host that is immutable by default with explicit mutate.
|
|
334
297
|
*/
|
|
335
|
-
interface
|
|
298
|
+
interface SharedState<T> {
|
|
336
299
|
/**
|
|
337
|
-
*
|
|
338
|
-
* handshake), `anonymous:devframe:auth:request-code` (client-requested
|
|
339
|
-
* banner print), and `devframe:auth:revoke` (self-revoke); register these
|
|
340
|
-
* on the RPC host (e.g. `rpcHost.register(fn)` for each).
|
|
300
|
+
* Get the current state. Immutable.
|
|
341
301
|
*/
|
|
342
|
-
|
|
302
|
+
value: () => Immutable<T>;
|
|
343
303
|
/**
|
|
344
|
-
*
|
|
345
|
-
* current trust state. Defaults to allowing any `anonymous:`-prefixed
|
|
346
|
-
* method (see `isAnonymousRpcMethod`) plus anything once the session is
|
|
347
|
-
* trusted.
|
|
304
|
+
* Subscribe to state changes.
|
|
348
305
|
*/
|
|
349
|
-
|
|
306
|
+
on: EventEmitter<SharedStateEvents<T>>['on'];
|
|
350
307
|
/**
|
|
351
|
-
*
|
|
352
|
-
* request (a static/pre-shared token from `clientAuthTokens`, or a token
|
|
353
|
-
* minted by the code exchange) and, when valid, marks the session
|
|
354
|
-
* trusted immediately, before the client's own handshake call.
|
|
308
|
+
* Mutate the state.
|
|
355
309
|
*/
|
|
356
|
-
|
|
310
|
+
mutate: (fn: (state: T) => void, syncId?: string) => void;
|
|
357
311
|
/**
|
|
358
|
-
*
|
|
359
|
-
* browser client triggers this itself over
|
|
360
|
-
* `anonymous:devframe:auth:request-code`; call it directly when the host
|
|
361
|
-
* wants the code on screen without waiting for a client. Safe to call
|
|
362
|
-
* repeatedly; it only prints once per code.
|
|
312
|
+
* Apply patches to the state.
|
|
363
313
|
*/
|
|
364
|
-
|
|
314
|
+
patch: (patches: SharedStatePatch[], syncId?: string) => void;
|
|
365
315
|
/**
|
|
366
|
-
*
|
|
367
|
-
* tab lands already authenticated, e.g. appending the current OTP as a
|
|
368
|
-
* query param. Called with the fully-resolved target URL; return it
|
|
369
|
-
* unchanged to opt out. Optional: a handler that doesn't need this (e.g.
|
|
370
|
-
* one gated by a pre-shared bearer token instead of an interactive code)
|
|
371
|
-
* can omit it and the URL opens as-is.
|
|
316
|
+
* Sync IDs that have been applied to the state.
|
|
372
317
|
*/
|
|
373
|
-
|
|
318
|
+
syncIds: Set<string>;
|
|
319
|
+
}
|
|
320
|
+
interface SharedStateEvents<T> {
|
|
321
|
+
updated: (fullState: T, patches: SharedStatePatch[] | undefined, syncId: string) => void;
|
|
322
|
+
}
|
|
323
|
+
interface SharedStateOptions<T> {
|
|
324
|
+
/**
|
|
325
|
+
* Initial state.
|
|
326
|
+
*/
|
|
327
|
+
initialValue: T;
|
|
328
|
+
/**
|
|
329
|
+
* Enable patches.
|
|
330
|
+
*
|
|
331
|
+
* @default false
|
|
332
|
+
*/
|
|
333
|
+
enablePatches?: boolean;
|
|
374
334
|
}
|
|
375
|
-
|
|
376
|
-
//#region src/types/mcp.d.ts
|
|
335
|
+
declare function createSharedState<T extends object>(options: SharedStateOptions<T>): SharedState<T>;
|
|
377
336
|
/**
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* implements it) share one contract without a type-level dependency cycle.
|
|
381
|
-
* None of these shapes reference the MCP SDK: the SDK is an implementation
|
|
382
|
-
* detail of `@devframes/agentic`, freely swappable behind this surface.
|
|
383
|
-
* The h3-bound `mountMcpHttp` shapes live in `node/agentic.ts` (exported via
|
|
384
|
-
* `devframe/internal`) instead: `devframe/types` must stay lib-neutral, and
|
|
385
|
-
* h3's declarations are not.
|
|
337
|
+
* Serialized error shape sent over the wire when a stream ends with a failure.
|
|
338
|
+
* Stays JSON-safe so the strict-JSON encoder can carry it without coercion.
|
|
386
339
|
*/
|
|
387
|
-
interface
|
|
340
|
+
interface StreamErrorPayload {
|
|
341
|
+
name: string;
|
|
342
|
+
message: string;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Single buffered chunk in the server-side ring buffer.
|
|
346
|
+
*
|
|
347
|
+
* Sequence numbers start at 1 and increment per write. Subscribers track
|
|
348
|
+
* `lastSeenSeq` and ask for `afterSeq` on resubscribe so the server can
|
|
349
|
+
* replay any chunks the client missed during a brief disconnect.
|
|
350
|
+
*/
|
|
351
|
+
interface BufferedChunk<T> {
|
|
352
|
+
seq: number;
|
|
353
|
+
chunk: T;
|
|
354
|
+
}
|
|
355
|
+
interface StreamSinkEvents<T> {
|
|
356
|
+
/** Fired for each `write()`. The RPC layer subscribes and broadcasts. */
|
|
357
|
+
chunk: (seq: number, chunk: T) => void;
|
|
358
|
+
/** Terminal; fired exactly once per sink lifetime. */
|
|
359
|
+
end: (error?: StreamErrorPayload) => void;
|
|
360
|
+
}
|
|
361
|
+
interface CreateStreamSinkOptions {
|
|
362
|
+
id?: string;
|
|
388
363
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* served route-based by the dev server instead; see `mountMcpHttp` and
|
|
392
|
-
* the `mcp` option on `createDevServer` / `createCac`'s `--mcp` flag.
|
|
364
|
+
* Size of the per-stream ring buffer kept for replay-on-resubscribe.
|
|
365
|
+
* `0` (default) disables replay.
|
|
393
366
|
*/
|
|
394
|
-
|
|
367
|
+
replayWindow?: number;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Server-side producer handle. Two equivalent surfaces share one piece of
|
|
371
|
+
* state: the imperative `write/error/close` triple, and a `WritableStream<T>`
|
|
372
|
+
* for `pipeTo`-style consumption.
|
|
373
|
+
*/
|
|
374
|
+
interface StreamSink<T> {
|
|
375
|
+
/** Stable id used by clients to subscribe. */
|
|
376
|
+
readonly id: string;
|
|
395
377
|
/**
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
* - `(key) => boolean`: filter
|
|
378
|
+
* Aborts when the consumer cancels (server-side) or when the transport
|
|
379
|
+
* loses every subscriber. Producers should poll `signal.aborted` and exit
|
|
380
|
+
* cleanly.
|
|
400
381
|
*/
|
|
401
|
-
|
|
382
|
+
readonly signal: AbortSignal;
|
|
383
|
+
/** `true` after `close()` / `error()`. Further writes throw. */
|
|
384
|
+
readonly closed: boolean;
|
|
385
|
+
/** Last allocated sequence number. `0` until the first write. */
|
|
386
|
+
readonly lastSeq: number;
|
|
387
|
+
write: (chunk: T) => void;
|
|
388
|
+
error: (reason: unknown) => void;
|
|
389
|
+
close: () => void;
|
|
390
|
+
/** External-cancel path. Aborts the signal so handlers can short-circuit. */
|
|
391
|
+
abort: (reason?: unknown) => void;
|
|
392
|
+
/** `WritableStream<T>` adapter; same in-memory state as the imperative API. */
|
|
393
|
+
readonly writable: WritableStream<T>;
|
|
402
394
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
395
|
+
* Internal: RPC layer subscribes to receive chunk/end notifications.
|
|
396
|
+
* Not part of the public contract; do not call directly.
|
|
397
|
+
*
|
|
398
|
+
* @internal
|
|
405
399
|
*/
|
|
406
|
-
|
|
400
|
+
readonly events: EventEmitter<StreamSinkEvents<T>>;
|
|
407
401
|
/**
|
|
408
|
-
*
|
|
409
|
-
*
|
|
402
|
+
* Internal replay buffer. RPC layer reads on (re)subscribe to feed
|
|
403
|
+
* missed chunks before going live.
|
|
404
|
+
*
|
|
405
|
+
* @internal
|
|
410
406
|
*/
|
|
411
|
-
|
|
407
|
+
readonly buffer: ReadonlyArray<BufferedChunk<T>>;
|
|
408
|
+
}
|
|
409
|
+
interface CreateStreamReaderOptions {
|
|
410
|
+
id?: string;
|
|
412
411
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
412
|
+
* Maximum number of buffered chunks held client-side while the consumer
|
|
413
|
+
* isn't draining. On overflow, the oldest chunk is dropped.
|
|
415
414
|
*/
|
|
416
|
-
|
|
415
|
+
highWaterMark?: number;
|
|
417
416
|
/**
|
|
418
|
-
*
|
|
419
|
-
*
|
|
417
|
+
* Called when the chunk queue overflows the high-water mark. The RPC
|
|
418
|
+
* layer wires this to a coded warning; the primitive itself is
|
|
419
|
+
* RPC-agnostic.
|
|
420
420
|
*/
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
|
|
424
|
-
/** Override the version reported in the MCP handshake. Defaults to `definition.version ?? '0.0.0'`. */
|
|
425
|
-
serverVersion?: string;
|
|
426
|
-
/** Called once the transport is connected. */
|
|
427
|
-
onReady?: (info: {
|
|
428
|
-
transport: 'stdio';
|
|
429
|
-
}) => void;
|
|
421
|
+
onOverflow?: (dropped: number) => void;
|
|
422
|
+
/** Called when the consumer cancels; the RPC layer sends `:cancel` upstream. */
|
|
423
|
+
onCancel?: () => void;
|
|
430
424
|
}
|
|
431
425
|
/**
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
426
|
+
* Client-side consumer handle. Both an `AsyncIterable<T>` (for `for await`)
|
|
427
|
+
* and exposes `readable: ReadableStream<T>` (for `pipeTo`). Pick one; they
|
|
428
|
+
* share a single internal queue, so concurrent draining will race.
|
|
435
429
|
*/
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
stop: () => Promise<void>;
|
|
450
|
-
}
|
|
451
|
-
interface CreateMcpFetchHandlerOptions {
|
|
452
|
-
/** Name reported in the MCP handshake. */
|
|
453
|
-
serverName: string;
|
|
454
|
-
/** Version reported in the MCP handshake. */
|
|
455
|
-
serverVersion: string;
|
|
456
|
-
/** Expose shared-state keys as MCP resources; see {@link CreateMcpServerOptions.exposeSharedState}. */
|
|
457
|
-
exposeSharedState: boolean | ((key: string) => boolean);
|
|
458
|
-
/** Usage guidance for the handshake; see {@link CreateMcpServerOptions.instructions}. */
|
|
459
|
-
instructions?: string;
|
|
460
|
-
/** Resource templates; see {@link CreateMcpServerOptions.resourceTemplates}. */
|
|
461
|
-
resourceTemplates?: McpResourceTemplate[];
|
|
462
|
-
/** Host subscription for resource-list changes; see {@link CreateMcpServerOptions.onResourcesChanged}. */
|
|
463
|
-
onResourcesChanged?: McpResourcesChangedHook;
|
|
464
|
-
/** Prompt templates; see {@link CreateMcpServerOptions.prompts}. */
|
|
465
|
-
prompts?: McpPrompt[];
|
|
466
|
-
/**
|
|
467
|
-
* Optional identity check, layered on top of the origin gate and checked
|
|
468
|
-
* **after** it: a bearer token string (matched in constant time against
|
|
469
|
-
* `Authorization: Bearer <token>`), a `(request) => boolean` callback, or
|
|
470
|
-
* `false` (the default) for origin-only, trusting same-machine callers. A
|
|
471
|
-
* callback governs identity only and cannot relax the origin gate. See
|
|
472
|
-
* {@link McpAuthorization}.
|
|
473
|
-
*/
|
|
474
|
-
authorization?: McpAuthorization;
|
|
475
|
-
/**
|
|
476
|
-
* Origin allow-list beyond the loopback default. `false` disables the
|
|
477
|
-
* origin gate entirely. Default: loopback-only.
|
|
478
|
-
*
|
|
479
|
-
* Unlike the WS transport, the MCP route does **not** allow `Origin`-less
|
|
480
|
-
* requests: a route-based endpoint is reachable by any local process, so a
|
|
481
|
-
* request must carry an `Origin` that passes the gate. Native clients
|
|
482
|
-
* (e.g. `devframe connect`) send their loopback origin explicitly.
|
|
483
|
-
*/
|
|
484
|
-
allowedOrigins?: readonly string[] | false;
|
|
485
|
-
}
|
|
486
|
-
/** Connection facts a host knows about a request beyond the `Request` itself. */
|
|
487
|
-
interface McpConnectionInfo {
|
|
488
|
-
/**
|
|
489
|
-
* The connecting peer's remote address (a node socket's `remoteAddress`),
|
|
490
|
-
* used to prove a same-machine caller when the endpoint relies on the
|
|
491
|
-
* loopback origin default with no identity check. A host that can resolve a
|
|
492
|
-
* trustworthy peer address (the h3/node mount) supplies it; when it's
|
|
493
|
-
* omitted the origin gate stays the only locality signal.
|
|
494
|
-
*/
|
|
495
|
-
remoteAddress?: string;
|
|
496
|
-
}
|
|
497
|
-
interface McpFetchHandler {
|
|
498
|
-
/**
|
|
499
|
-
* WHATWG-`fetch` handler for the MCP endpoint. Hand every method
|
|
500
|
-
* (POST/GET/DELETE) on the endpoint's path to it; routing by path is the
|
|
501
|
-
* host's job. Pass {@link McpConnectionInfo} when the host can resolve the
|
|
502
|
-
* peer address so the default trust boundary can enforce same-machine
|
|
503
|
-
* locality.
|
|
504
|
-
*/
|
|
505
|
-
fetch: (request: Request, connection?: McpConnectionInfo) => Promise<Response>;
|
|
506
|
-
/** Tear down the handler (aborts in-flight exchanges, drops the change bridge). */
|
|
507
|
-
dispose: () => Promise<void>;
|
|
508
|
-
}
|
|
509
|
-
/** One concrete resource that an {@link McpResourceTemplate} lists in `resources/list`. */
|
|
510
|
-
interface McpResourceTemplateEntry {
|
|
511
|
-
/** The resource URI. It SHOULD match the `uriTemplate` of its template, so `resources/read` finds it. */
|
|
512
|
-
uri: string;
|
|
513
|
-
name: string;
|
|
514
|
-
/** Human-readable name for display. */
|
|
515
|
-
title?: string;
|
|
516
|
-
description?: string;
|
|
517
|
-
/** Defaults to the `mimeType` of the template. */
|
|
518
|
-
mimeType?: string;
|
|
430
|
+
interface StreamReader<T> extends AsyncIterable<T> {
|
|
431
|
+
readonly id: string;
|
|
432
|
+
readonly cancelled: boolean;
|
|
433
|
+
readonly done: boolean;
|
|
434
|
+
/** Highest `seq` observed. Used for replay on reconnect. */
|
|
435
|
+
readonly lastSeenSeq: number;
|
|
436
|
+
/** `ReadableStream<T>` adapter for `pipeTo`-style consumption. */
|
|
437
|
+
readonly readable: ReadableStream<T>;
|
|
438
|
+
cancel: () => void;
|
|
439
|
+
/** @internal */
|
|
440
|
+
_push: (seq: number, chunk: T) => void;
|
|
441
|
+
/** @internal */
|
|
442
|
+
_end: (error?: StreamErrorPayload) => void;
|
|
519
443
|
}
|
|
520
444
|
/**
|
|
521
|
-
*
|
|
522
|
-
* `
|
|
445
|
+
* Build a server-side stream sink. RPC-agnostic; the RPC host wires
|
|
446
|
+
* `events.on('chunk' | 'end')` to broadcast, and reads `buffer` to replay
|
|
447
|
+
* for late or reconnecting subscribers.
|
|
523
448
|
*/
|
|
524
|
-
|
|
525
|
-
text?: string;
|
|
526
|
-
json?: unknown;
|
|
527
|
-
/** Defaults to the `mimeType` of the template, then `application/json`. */
|
|
528
|
-
mimeType?: string;
|
|
529
|
-
}
|
|
449
|
+
declare function createStreamSink<T>(options?: CreateStreamSinkOptions): StreamSink<T>;
|
|
530
450
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
* expression matches a non-empty value with no `/`, and its value is
|
|
535
|
-
* percent-decoded.
|
|
536
|
-
*
|
|
537
|
-
* `list` and `read` get the node context of the devframe (or of the hub), so
|
|
538
|
-
* they can read live state such as `ctx.rpc.sharedState` or `ctx.agent`. The
|
|
539
|
-
* route options are resolved before `setup()` runs, so a template cannot
|
|
540
|
-
* capture that context in a closure.
|
|
451
|
+
* Build a client-side stream reader. RPC-agnostic; the RPC host calls
|
|
452
|
+
* `_push(seq, chunk)` on each incoming chunk and `_end(error?)` on the
|
|
453
|
+
* terminal frame. Consumers iterate with `for await` or pipe `readable`.
|
|
541
454
|
*/
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
name: string;
|
|
546
|
-
/** Human-readable name for display. */
|
|
455
|
+
declare function createStreamReader<T>(options?: CreateStreamReaderOptions): StreamReader<T>;
|
|
456
|
+
interface BrowserAgentToolManifest {
|
|
457
|
+
id: string;
|
|
547
458
|
title?: string;
|
|
548
|
-
description
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
list?: (ctx: DevframeNodeContext) => McpResourceTemplateEntry[] | Promise<McpResourceTemplateEntry[]>;
|
|
553
|
-
/** Read one resource: `params` holds the decoded value of each `{name}`, `uri` the requested URI. */
|
|
554
|
-
read: (params: Record<string, string>, uri: string, ctx: DevframeNodeContext) => McpResourceTemplateContent | Promise<McpResourceTemplateContent>;
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* A host subscription for resource-list changes. Call `notify()` each time
|
|
558
|
-
* the resources change; the MCP server then sends
|
|
559
|
-
* `notifications/resources/list_changed`. Return a function that removes the
|
|
560
|
-
* subscription; the MCP server calls it on teardown.
|
|
561
|
-
*/
|
|
562
|
-
type McpResourcesChangedHook = (notify: () => void, ctx: DevframeNodeContext) => () => void;
|
|
563
|
-
/** One argument of an {@link McpPrompt}. */
|
|
564
|
-
interface McpPromptArgument {
|
|
565
|
-
name: string;
|
|
566
|
-
description?: string;
|
|
567
|
-
/** `prompts/get` answers invalid params when a required argument is missing or empty. */
|
|
568
|
-
required?: boolean;
|
|
569
|
-
}
|
|
570
|
-
/** One message of the answer to `prompts/get`. */
|
|
571
|
-
interface McpPromptMessage {
|
|
572
|
-
role: 'user' | 'assistant';
|
|
573
|
-
content: {
|
|
574
|
-
type: 'text';
|
|
575
|
-
text: string;
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
/** What an {@link McpPrompt} returns from `get`, sent as the `prompts/get` result. */
|
|
579
|
-
interface McpPromptResult {
|
|
580
|
-
description?: string;
|
|
581
|
-
messages: McpPromptMessage[];
|
|
459
|
+
description: string;
|
|
460
|
+
safety: 'read' | 'action' | 'destructive';
|
|
461
|
+
tags?: readonly string[];
|
|
462
|
+
inputSchema?: unknown;
|
|
582
463
|
}
|
|
583
|
-
/**
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
name: string;
|
|
590
|
-
/** Human-readable name for display. */
|
|
591
|
-
title?: string;
|
|
592
|
-
description?: string;
|
|
593
|
-
arguments?: McpPromptArgument[];
|
|
594
|
-
/** Build the messages from the arguments the coding agent sent. */
|
|
595
|
-
get: (args: Record<string, string>) => McpPromptResult | Promise<McpPromptResult>;
|
|
464
|
+
/** What a connected document reports about itself alongside its tool manifest. */
|
|
465
|
+
interface BrowserAgentClientInfo {
|
|
466
|
+
url: string;
|
|
467
|
+
title: string;
|
|
468
|
+
visible: boolean;
|
|
469
|
+
focused: boolean;
|
|
596
470
|
}
|
|
597
|
-
//#endregion
|
|
598
|
-
//#region src/types/diagnostics.d.ts
|
|
599
471
|
/**
|
|
600
472
|
* The shared diagnostics lookup exposed by the host. A `Proxy` that resolves
|
|
601
473
|
* any registered code name to its `nostics` handle (a callable that builds
|
|
@@ -652,8 +524,6 @@ interface DevframeDiagnosticsHost {
|
|
|
652
524
|
*/
|
|
653
525
|
defineDiagnostics: typeof defineDiagnostics;
|
|
654
526
|
}
|
|
655
|
-
//#endregion
|
|
656
|
-
//#region src/types/host.d.ts
|
|
657
527
|
interface DevframeHost {
|
|
658
528
|
/**
|
|
659
529
|
* Serve static assets at the given URL base: a local directory, or a
|
|
@@ -721,274 +591,44 @@ interface DevframeHost {
|
|
|
721
591
|
* private, `global` is per-user.
|
|
722
592
|
*/
|
|
723
593
|
type DevframeStorageScope = 'workspace' | 'project' | 'global';
|
|
724
|
-
|
|
725
|
-
//#region src/client/browser-agent.d.ts
|
|
726
|
-
interface BrowserAgentToolManifest {
|
|
727
|
-
id: string;
|
|
728
|
-
title?: string;
|
|
729
|
-
description: string;
|
|
730
|
-
safety: 'read' | 'action' | 'destructive';
|
|
731
|
-
tags?: readonly string[];
|
|
732
|
-
inputSchema?: unknown;
|
|
733
|
-
}
|
|
734
|
-
/** What a connected document reports about itself alongside its tool manifest. */
|
|
735
|
-
interface BrowserAgentClientInfo {
|
|
736
|
-
url: string;
|
|
737
|
-
title: string;
|
|
738
|
-
visible: boolean;
|
|
739
|
-
focused: boolean;
|
|
740
|
-
}
|
|
741
|
-
//#endregion
|
|
742
|
-
//#region src/types/rpc-augments.d.ts
|
|
743
|
-
/**
|
|
744
|
-
* To be extended
|
|
745
|
-
*/
|
|
746
|
-
interface DevframeRpcClientFunctions {
|
|
747
|
-
/** Clear cached RPC results and refresh cache eligibility. */
|
|
748
|
-
'devframe:rpc:cache:invalidate': () => Promise<void>;
|
|
749
|
-
/** Invoke a tool registered in this browser document. @internal */
|
|
750
|
-
'devframe:agent:invoke-client-tool': (id: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
751
|
-
/**
|
|
752
|
-
* Server→client notification that this connection's auth token has been
|
|
753
|
-
* revoked. The client drops to untrusted on receipt. Broadcast by
|
|
754
|
-
* `revokeActiveConnectionsForToken`.
|
|
755
|
-
*
|
|
756
|
-
* @internal
|
|
757
|
-
*/
|
|
758
|
-
'devframe:auth:revoked': () => Promise<void>;
|
|
759
|
-
/**
|
|
760
|
-
* Streaming chunk pushed from server to subscribed clients. Wired by
|
|
761
|
-
* `RpcStreamingHost`; do not register manually.
|
|
762
|
-
*
|
|
763
|
-
* @internal
|
|
764
|
-
*/
|
|
765
|
-
'devframe:streaming:chunk': (channel: string, id: string, seq: number, chunk: any) => Promise<void>;
|
|
766
|
-
/**
|
|
767
|
-
* Streaming terminator pushed from server to subscribed clients. Wired by
|
|
768
|
-
* `RpcStreamingHost`; do not register manually.
|
|
769
|
-
*
|
|
770
|
-
* @internal
|
|
771
|
-
*/
|
|
772
|
-
'devframe:streaming:end': (channel: string, id: string, error?: {
|
|
773
|
-
name: string;
|
|
774
|
-
message: string;
|
|
775
|
-
}) => Promise<void>;
|
|
594
|
+
interface DevframeViewHost {
|
|
776
595
|
/**
|
|
777
|
-
*
|
|
778
|
-
* `
|
|
596
|
+
* Static mounts registered through {@link DevframeViewHost.hostStatic}, each
|
|
597
|
+
* carrying the `resolveFrom` base it was mounted with so a build step that
|
|
598
|
+
* copies these itself (rather than serving them live) re-resolves a remote
|
|
599
|
+
* source to the same locally-installed copy it would serve live.
|
|
779
600
|
*
|
|
780
601
|
* @internal
|
|
781
602
|
*/
|
|
782
|
-
|
|
603
|
+
buildStaticDirs: {
|
|
604
|
+
baseUrl: string;
|
|
605
|
+
source: StaticAssetsSource;
|
|
606
|
+
resolveFrom?: string | null;
|
|
607
|
+
}[];
|
|
783
608
|
/**
|
|
784
|
-
*
|
|
785
|
-
*
|
|
609
|
+
* Helper to host static files
|
|
610
|
+
* - In `dev` mode, it will register middleware to `viteServer.middlewares` to host the static files
|
|
611
|
+
* - In `build` mode, it will copy the static files to the dist directory
|
|
786
612
|
*
|
|
787
|
-
* @
|
|
788
|
-
|
|
789
|
-
'devframe:rpc:client-state:updated': (key: string, fullState: any, syncId: string) => Promise<void>;
|
|
790
|
-
/**
|
|
791
|
-
* Incremental shared-state patch pushed from server to subscribed clients.
|
|
792
|
-
* Wired by `RpcSharedStateHost`; do not register manually.
|
|
613
|
+
* Accepts a local dist directory, or a {@link StaticAssetsSource} remote
|
|
614
|
+
* declaration served through devframe's caching CDN back-proxy.
|
|
793
615
|
*
|
|
794
|
-
*
|
|
616
|
+
* `defaultResolveFrom` overrides, for this call only, the context's own
|
|
617
|
+
* `importMetaUrl` as the default `resolveFrom` for a remote source that
|
|
618
|
+
* doesn't set one. A shared host that mounts assets on behalf of another
|
|
619
|
+
* devframe (a hub installing a plugin) passes that plugin's `importMetaUrl`
|
|
620
|
+
* so the assets resolve against the plugin's dependency graph rather than
|
|
621
|
+
* the host's.
|
|
795
622
|
*/
|
|
796
|
-
|
|
623
|
+
hostStatic: (baseUrl: string, source: StaticAssetsSource, defaultResolveFrom?: string | null) => void;
|
|
797
624
|
}
|
|
625
|
+
type AnyRpcFn = (...args: any[]) => any;
|
|
798
626
|
/**
|
|
799
|
-
*
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
/** Replace this connection's browser-agent tool manifest, tagged with the calling tab's stable client id. @internal */
|
|
805
|
-
'devframe:agent:sync-client-tools': (clientId: string, tools: BrowserAgentToolManifest[], info: BrowserAgentClientInfo) => Promise<void>;
|
|
806
|
-
/**
|
|
807
|
-
* Authenticate a connection with a previously-issued bearer token; resolves
|
|
808
|
-
* whether the connection is now trusted. The interactive handler is provided
|
|
809
|
-
* by the host adapter (e.g. Vite DevTools); the standalone server registers
|
|
810
|
-
* an auto-trust noop when `auth: false`.
|
|
811
|
-
*
|
|
812
|
-
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
813
|
-
* reachable before the connection is trusted; this is the *only* rule the
|
|
814
|
-
* pre-trust gate applies, no per-method allowlist.
|
|
815
|
-
*
|
|
816
|
-
* @internal
|
|
817
|
-
*/
|
|
818
|
-
'anonymous:devframe:auth': (params: {
|
|
819
|
-
authToken: string;
|
|
820
|
-
ua: string;
|
|
821
|
-
origin: string;
|
|
822
|
-
}) => Promise<{
|
|
823
|
-
isTrusted: boolean;
|
|
824
|
-
}>;
|
|
825
|
-
/**
|
|
826
|
-
* Exchange a one-time authentication code (shown by the dev server) for a fresh,
|
|
827
|
-
* node-issued bearer token, returning the token on success or `null`. The
|
|
828
|
-
* handler is provided by the host adapter on top of `exchangeTempAuthCode`.
|
|
829
|
-
*
|
|
830
|
-
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
831
|
-
* reachable before the connection is trusted.
|
|
832
|
-
*
|
|
833
|
-
* @internal
|
|
834
|
-
*/
|
|
835
|
-
'anonymous:devframe:auth:exchange': (params: {
|
|
836
|
-
code: string;
|
|
837
|
-
ua: string;
|
|
838
|
-
origin: string;
|
|
839
|
-
}) => Promise<{
|
|
840
|
-
authToken: string | null;
|
|
841
|
-
}>;
|
|
842
|
-
/**
|
|
843
|
-
* Ask the server to print its auth banner (code + magic link) for this
|
|
844
|
-
* client, e.g. when an auth UI first shows; `reissue: true` rotates the code
|
|
845
|
-
* first (the manual "re-issue" action). Registered by
|
|
846
|
-
* `recipes/interactive-auth`; a repeat request for an already-printed code
|
|
847
|
-
* is a no-op.
|
|
848
|
-
*
|
|
849
|
-
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
850
|
-
* reachable before the connection is trusted.
|
|
851
|
-
*
|
|
852
|
-
* @internal
|
|
853
|
-
*/
|
|
854
|
-
'anonymous:devframe:auth:request-code': (params: {
|
|
855
|
-
ua: string;
|
|
856
|
-
origin: string;
|
|
857
|
-
reissue?: boolean;
|
|
858
|
-
}) => Promise<void>;
|
|
859
|
-
/**
|
|
860
|
-
* Self-revoke: the caller asks the server to revoke its own bearer token
|
|
861
|
-
* (if any) and drop to untrusted. Requires an already-trusted caller, so
|
|
862
|
-
* unlike the two handshake methods above it does **not** carry the
|
|
863
|
-
* `anonymous:` prefix. Registered by `recipes/interactive-auth`.
|
|
864
|
-
*
|
|
865
|
-
* @internal
|
|
866
|
-
*/
|
|
867
|
-
'devframe:auth:revoke': () => Promise<void>;
|
|
868
|
-
/**
|
|
869
|
-
* Subscribe a client to a shared-state key. Wired by
|
|
870
|
-
* `RpcSharedStateHost`; do not register manually.
|
|
871
|
-
*
|
|
872
|
-
* @internal
|
|
873
|
-
*/
|
|
874
|
-
'devframe:rpc:server-state:subscribe': (key: string) => Promise<void>;
|
|
875
|
-
/**
|
|
876
|
-
* Read the current value for a shared-state key. Wired by
|
|
877
|
-
* `RpcSharedStateHost`; do not register manually.
|
|
878
|
-
*
|
|
879
|
-
* @internal
|
|
880
|
-
*/
|
|
881
|
-
'devframe:rpc:server-state:get': (key: string) => Promise<any>;
|
|
882
|
-
/**
|
|
883
|
-
* Replace a shared-state value (from the client). Wired by
|
|
884
|
-
* `RpcSharedStateHost`; do not register manually.
|
|
885
|
-
*
|
|
886
|
-
* @internal
|
|
887
|
-
*/
|
|
888
|
-
'devframe:rpc:server-state:set': (key: string, value: any, syncId: string) => Promise<void>;
|
|
889
|
-
/**
|
|
890
|
-
* Apply a patch to a shared-state value (from the client). Wired by
|
|
891
|
-
* `RpcSharedStateHost`; do not register manually.
|
|
892
|
-
*
|
|
893
|
-
* @internal
|
|
894
|
-
*/
|
|
895
|
-
'devframe:rpc:server-state:patch': (key: string, patches: any[], syncId: string) => Promise<void>;
|
|
896
|
-
/**
|
|
897
|
-
* Client→server streaming subscription with optional replay cursor.
|
|
898
|
-
* Wired by `RpcStreamingHost`; do not register manually.
|
|
899
|
-
*
|
|
900
|
-
* @internal
|
|
901
|
-
*/
|
|
902
|
-
'devframe:streaming:subscribe': (channel: string, id: string, opts?: {
|
|
903
|
-
afterSeq?: number;
|
|
904
|
-
}) => Promise<void>;
|
|
905
|
-
/**
|
|
906
|
-
* Client→server streaming unsubscribe. Wired by `RpcStreamingHost`;
|
|
907
|
-
* do not register manually.
|
|
908
|
-
*
|
|
909
|
-
* @internal
|
|
910
|
-
*/
|
|
911
|
-
'devframe:streaming:unsubscribe': (channel: string, id: string) => Promise<void>;
|
|
912
|
-
/**
|
|
913
|
-
* Client→server streaming cancellation request. Wired by
|
|
914
|
-
* `RpcStreamingHost`; do not register manually.
|
|
915
|
-
*
|
|
916
|
-
* @internal
|
|
917
|
-
*/
|
|
918
|
-
'devframe:streaming:cancel': (channel: string, id: string) => Promise<void>;
|
|
919
|
-
/**
|
|
920
|
-
* Client→server upload chunk. Wired by `RpcStreamingHost`; do not
|
|
921
|
-
* register manually.
|
|
922
|
-
*
|
|
923
|
-
* @internal
|
|
924
|
-
*/
|
|
925
|
-
'devframe:streaming:upload-chunk': (channel: string, id: string, seq: number, chunk: any) => Promise<void>;
|
|
926
|
-
/**
|
|
927
|
-
* Client→server upload terminator. Wired by `RpcStreamingHost`; do not
|
|
928
|
-
* register manually.
|
|
929
|
-
*
|
|
930
|
-
* @internal
|
|
931
|
-
*/
|
|
932
|
-
'devframe:streaming:upload-end': (channel: string, id: string, error?: {
|
|
933
|
-
name: string;
|
|
934
|
-
message: string;
|
|
935
|
-
}) => Promise<void>;
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* To be extended
|
|
939
|
-
*/
|
|
940
|
-
interface DevframeRpcSharedStates {
|
|
941
|
-
/**
|
|
942
|
-
* Wire-service advertisements: package name → `{ package, version,
|
|
943
|
-
* scope, meta }` for every installed {@link import('./services').DevframeServiceDefinition}.
|
|
944
|
-
* Written by the node services host at the `ready()` barrier; clients read
|
|
945
|
-
* it through `client.services` (or subscribe to it directly for
|
|
946
|
-
* reactivity). Read-only from the browser.
|
|
947
|
-
*/
|
|
948
|
-
'devframe:services': DevframeServicesState;
|
|
949
|
-
}
|
|
950
|
-
//#endregion
|
|
951
|
-
//#region src/types/views.d.ts
|
|
952
|
-
interface DevframeViewHost {
|
|
953
|
-
/**
|
|
954
|
-
* Static mounts registered through {@link DevframeViewHost.hostStatic}, each
|
|
955
|
-
* carrying the `resolveFrom` base it was mounted with so a build step that
|
|
956
|
-
* copies these itself (rather than serving them live) re-resolves a remote
|
|
957
|
-
* source to the same locally-installed copy it would serve live.
|
|
958
|
-
*
|
|
959
|
-
* @internal
|
|
960
|
-
*/
|
|
961
|
-
buildStaticDirs: {
|
|
962
|
-
baseUrl: string;
|
|
963
|
-
source: StaticAssetsSource;
|
|
964
|
-
resolveFrom?: string | null;
|
|
965
|
-
}[];
|
|
966
|
-
/**
|
|
967
|
-
* Helper to host static files
|
|
968
|
-
* - In `dev` mode, it will register middleware to `viteServer.middlewares` to host the static files
|
|
969
|
-
* - In `build` mode, it will copy the static files to the dist directory
|
|
970
|
-
*
|
|
971
|
-
* Accepts a local dist directory, or a {@link StaticAssetsSource} remote
|
|
972
|
-
* declaration served through devframe's caching CDN back-proxy.
|
|
973
|
-
*
|
|
974
|
-
* `defaultResolveFrom` overrides, for this call only, the context's own
|
|
975
|
-
* `importMetaUrl` as the default `resolveFrom` for a remote source that
|
|
976
|
-
* doesn't set one. A shared host that mounts assets on behalf of another
|
|
977
|
-
* devframe (a hub installing a plugin) passes that plugin's `importMetaUrl`
|
|
978
|
-
* so the assets resolve against the plugin's dependency graph rather than
|
|
979
|
-
* the host's.
|
|
980
|
-
*/
|
|
981
|
-
hostStatic: (baseUrl: string, source: StaticAssetsSource, defaultResolveFrom?: string | null) => void;
|
|
982
|
-
}
|
|
983
|
-
//#endregion
|
|
984
|
-
//#region src/types/scope.d.ts
|
|
985
|
-
type AnyRpcFn = (...args: any[]) => any;
|
|
986
|
-
/**
|
|
987
|
-
* Resolve a scoped bare name `T` back to its fully-qualified entry in
|
|
988
|
-
* `Registry` (`<NS>:<T>`). Indexing the plain registry behind a `keyof`
|
|
989
|
-
* guard keeps TypeScript from rejecting a generic index into the
|
|
990
|
-
* key-remapped `Scoped*Functions<NS>` maps (TS2536) once a plugin augments
|
|
991
|
-
* the registry, while preserving each name's argument/return typing.
|
|
627
|
+
* Resolve a scoped bare name `T` back to its fully-qualified entry in
|
|
628
|
+
* `Registry` (`<NS>:<T>`). Indexing the plain registry behind a `keyof`
|
|
629
|
+
* guard keeps TypeScript from rejecting a generic index into the
|
|
630
|
+
* key-remapped `Scoped*Functions<NS>` maps (TS2536) once a plugin augments
|
|
631
|
+
* the registry, while preserving each name's argument/return typing.
|
|
992
632
|
*/
|
|
993
633
|
type ScopedRpcFn<Registry, NS extends string, T extends string> = `${NS}:${T}` extends keyof Registry ? Extract<Registry[`${NS}:${T}`], AnyRpcFn> : AnyRpcFn;
|
|
994
634
|
/**
|
|
@@ -1161,8 +801,6 @@ interface DevframeScopedNodeContext<NS extends string = string, Settings extends
|
|
|
1161
801
|
*/
|
|
1162
802
|
scope: DevframeNodeContext['scope'];
|
|
1163
803
|
}
|
|
1164
|
-
//#endregion
|
|
1165
|
-
//#region src/types/services.d.ts
|
|
1166
804
|
/**
|
|
1167
805
|
* Augmentation point mapping service ids to their implementation types.
|
|
1168
806
|
* Providers extend this via `declare module 'devframe'`.
|
|
@@ -1356,1097 +994,1425 @@ interface DevframeServicesHost {
|
|
|
1356
994
|
*/
|
|
1357
995
|
ready: () => Promise<void>;
|
|
1358
996
|
}
|
|
1359
|
-
//#endregion
|
|
1360
|
-
//#region src/types/devframe.d.ts
|
|
1361
|
-
/**
|
|
1362
|
-
* Classification of how a devframe is being deployed. Hosted adapters
|
|
1363
|
-
* (`vite`, `embedded`) share their origin with a host app and must
|
|
1364
|
-
* namespace their mount path under `/__<id>/`. Standalone adapters
|
|
1365
|
-
* (`cli`, `build`) own the origin and default to `/`.
|
|
1366
|
-
*/
|
|
1367
|
-
type DevframeDeploymentKind = 'standalone' | 'hosted';
|
|
1368
997
|
/**
|
|
1369
|
-
*
|
|
1370
|
-
* is mounted onto the same hub. See {@link DevframeDefinition.duplicationStrategy}.
|
|
1371
|
-
*
|
|
1372
|
-
* - `'warn'` (default): keep the first registration, drop later
|
|
1373
|
-
* duplicates, and emit a warning diagnostic (`DF8105`).
|
|
1374
|
-
* - `'silent'`: drop later duplicates without warning.
|
|
1375
|
-
* - `'throw'`: throw when a duplicate is mounted.
|
|
1376
|
-
* - `'duplicate'`: let every instance coexist under a disambiguated
|
|
1377
|
-
* dock id.
|
|
1378
|
-
*/
|
|
1379
|
-
type DevframeDuplicationStrategy = 'warn' | 'silent' | 'throw' | 'duplicate';
|
|
1380
|
-
/**
|
|
1381
|
-
* Controls where the browser opens the RPC WebSocket, advertised in
|
|
1382
|
-
* `__connection.json` and used to bind the dev server. The three shapes map
|
|
1383
|
-
* to the three connection scenarios; precedence is `url` > `port` > `route`:
|
|
1384
|
-
*
|
|
1385
|
-
* 1. **Same server, different route** (default): leave `port`/`url` unset.
|
|
1386
|
-
* The socket shares the HTTP server's port and binds to `route`
|
|
1387
|
-
* (`__ws`). The client connects to its own origin, so the link
|
|
1388
|
-
* survives a reverse proxy that rewrites the host/port/subpath.
|
|
1389
|
-
*
|
|
1390
|
-
* 2. **Different port**: set `port`. The socket binds on its own port on the
|
|
1391
|
-
* same host; the client targets `ws(s)://<page-host>:<port>/<route>`.
|
|
1392
|
-
*
|
|
1393
|
-
* 3. **Remote, different origin**: set `url` to a full `ws://`/`wss://`
|
|
1394
|
-
* endpoint (e.g. a public tunnel or relay). The client uses it verbatim.
|
|
998
|
+
* To be extended
|
|
1395
999
|
*/
|
|
1396
|
-
interface
|
|
1000
|
+
interface DevframeRpcClientFunctions {
|
|
1001
|
+
/** Clear cached RPC results and refresh cache eligibility. */
|
|
1002
|
+
'devframe:rpc:cache:invalidate': () => Promise<void>;
|
|
1003
|
+
/** Invoke a tool registered in this browser document. @internal */
|
|
1004
|
+
'devframe:agent:invoke-client-tool': (id: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
1397
1005
|
/**
|
|
1398
|
-
*
|
|
1399
|
-
* to
|
|
1006
|
+
* Server→client notification that this connection's auth token has been
|
|
1007
|
+
* revoked. The client drops to untrusted on receipt. Broadcast by
|
|
1008
|
+
* `revokeActiveConnectionsForToken`.
|
|
1009
|
+
*
|
|
1010
|
+
* @internal
|
|
1400
1011
|
*/
|
|
1401
|
-
|
|
1012
|
+
'devframe:auth:revoked': () => Promise<void>;
|
|
1402
1013
|
/**
|
|
1403
|
-
*
|
|
1404
|
-
*
|
|
1405
|
-
*
|
|
1014
|
+
* Streaming chunk pushed from server to subscribed clients. Wired by
|
|
1015
|
+
* `RpcStreamingHost`; do not register manually.
|
|
1016
|
+
*
|
|
1017
|
+
* @internal
|
|
1406
1018
|
*/
|
|
1407
|
-
|
|
1019
|
+
'devframe:streaming:chunk': (channel: string, id: string, seq: number, chunk: any) => Promise<void>;
|
|
1408
1020
|
/**
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
1021
|
+
* Streaming terminator pushed from server to subscribed clients. Wired by
|
|
1022
|
+
* `RpcStreamingHost`; do not register manually.
|
|
1023
|
+
*
|
|
1024
|
+
* @internal
|
|
1413
1025
|
*/
|
|
1414
|
-
|
|
1026
|
+
'devframe:streaming:end': (channel: string, id: string, error?: {
|
|
1027
|
+
name: string;
|
|
1028
|
+
message: string;
|
|
1029
|
+
}) => Promise<void>;
|
|
1415
1030
|
/**
|
|
1416
|
-
*
|
|
1417
|
-
* `
|
|
1031
|
+
* Server→client cancel for an in-flight upload. Wired by
|
|
1032
|
+
* `RpcStreamingHost`; do not register manually.
|
|
1033
|
+
*
|
|
1034
|
+
* @internal
|
|
1418
1035
|
*/
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
/**
|
|
1422
|
-
* Controls the SSE RPC endpoint, the WebSocket-free transport for hosts
|
|
1423
|
-
* and proxies where the upgrade isn't available. It rides whatever HTTP
|
|
1424
|
-
* surface serves the instance (the same one serving `__connection.json`),
|
|
1425
|
-
* so a relative `route` always resolves; there is no port plumbing of its
|
|
1426
|
-
* own. Enabled by default alongside the WebSocket; pass `sse: false` to
|
|
1427
|
-
* disable, or `ws: false` to run SSE-only (`backend: 'sse'`).
|
|
1428
|
-
*/
|
|
1429
|
-
interface DevframeSseOptions {
|
|
1036
|
+
'devframe:streaming:upload-cancel': (channel: string, id: string) => Promise<void>;
|
|
1430
1037
|
/**
|
|
1431
|
-
*
|
|
1432
|
-
*
|
|
1038
|
+
* Full shared-state snapshot pushed from server to subscribed clients.
|
|
1039
|
+
* Wired by `RpcSharedStateHost`; do not register manually.
|
|
1040
|
+
*
|
|
1041
|
+
* @internal
|
|
1433
1042
|
*/
|
|
1434
|
-
|
|
1043
|
+
'devframe:rpc:client-state:updated': (key: string, fullState: any, syncId: string) => Promise<void>;
|
|
1044
|
+
/**
|
|
1045
|
+
* Incremental shared-state patch pushed from server to subscribed clients.
|
|
1046
|
+
* Wired by `RpcSharedStateHost`; do not register manually.
|
|
1047
|
+
*
|
|
1048
|
+
* @internal
|
|
1049
|
+
*/
|
|
1050
|
+
'devframe:rpc:client-state:patch': (key: string, patches: any[], syncId: string) => Promise<void>;
|
|
1435
1051
|
}
|
|
1436
1052
|
/**
|
|
1437
|
-
*
|
|
1438
|
-
* route-based MCP endpoint trusts same-machine callers by default (the
|
|
1439
|
-
* loopback origin gate is enough), so this is opt-in hardening for the cases
|
|
1440
|
-
* where a same-machine process is not a trust boundary, like a LAN/tunnel
|
|
1441
|
-
* origin, a shared/CI box, or a destructive tool surface:
|
|
1442
|
-
*
|
|
1443
|
-
* - a non-empty **bearer token string**: the request must carry
|
|
1444
|
-
* `Authorization: Bearer <token>`, compared in constant time. Back it with
|
|
1445
|
-
* an environment variable rather than a literal;
|
|
1446
|
-
* - a **callback** `(request) => boolean | Promise<boolean>`: a custom
|
|
1447
|
-
* identity check (validate a signed header, an mTLS-derived claim, …). It
|
|
1448
|
-
* only governs identity and cannot relax the origin gate;
|
|
1449
|
-
* - `false`, the default: **origin-only**, trusting same-machine callers.
|
|
1450
|
-
*/
|
|
1451
|
-
type McpAuthorization = string | ((request: Request) => boolean | Promise<boolean>) | false;
|
|
1452
|
-
/**
|
|
1453
|
-
* The route-based MCP setting accepted everywhere a host mounts a devframe
|
|
1454
|
-
* (`initDevframe` / `initHub` / `createDevServer` options, `createCac` /
|
|
1455
|
-
* `--mcp`, the framework kits):
|
|
1456
|
-
*
|
|
1457
|
-
* - `'auto'`, the default: mount the route when the devframe exposes an
|
|
1458
|
-
* agent surface (an `agent`-flagged RPC function, or a tool / resource /
|
|
1459
|
-
* provider registered on `ctx.agent`) AND the optional `@devframes/agentic`
|
|
1460
|
-
* peer (the MCP adapter and SDK) is installed. An empty agent surface
|
|
1461
|
-
* mounts nothing and loads no MCP code; a non-empty one without the peer
|
|
1462
|
-
* warns once (DF0078) and mounts nothing.
|
|
1463
|
-
* - `true`: always mount at the default `__mcp` route; a missing
|
|
1464
|
-
* `@devframes/agentic` throws DF0079.
|
|
1465
|
-
* - `false`: never mount, and never probe or warn.
|
|
1466
|
-
* - {@link McpRouteOptions}: always mount (like `true`), with a custom route
|
|
1467
|
-
* path, origin allow-list, or {@link McpAuthorization} identity check.
|
|
1468
|
-
*
|
|
1469
|
-
* A mounted route trusts same-machine callers by default (the loopback
|
|
1470
|
-
* origin gate), exactly like `mcp: true`.
|
|
1471
|
-
*/
|
|
1472
|
-
type McpSetting = boolean | 'auto' | McpRouteOptions;
|
|
1473
|
-
/**
|
|
1474
|
-
* Configuration for the route-based MCP server mounted alongside the dev
|
|
1475
|
-
* server (via {@link DevframeCliOptions.mcp}). The endpoint speaks
|
|
1476
|
-
* the MCP Streamable-HTTP transport over the same origin as the SPA,
|
|
1477
|
-
* exposing the definition's `ctx.agent` tools + shared-state resources to
|
|
1478
|
-
* external MCP clients connected to the *running* server.
|
|
1053
|
+
* To be extended
|
|
1479
1054
|
*/
|
|
1480
|
-
interface
|
|
1055
|
+
interface DevframeRpcServerFunctions {
|
|
1056
|
+
/** Methods eligible for automatic client caching. @internal */
|
|
1057
|
+
'devframe:rpc:cacheable-functions': () => Promise<string[]>;
|
|
1058
|
+
/** Replace this connection's browser-agent tool manifest, tagged with the calling tab's stable client id. @internal */
|
|
1059
|
+
'devframe:agent:sync-client-tools': (clientId: string, tools: BrowserAgentToolManifest[], info: BrowserAgentClientInfo) => Promise<void>;
|
|
1481
1060
|
/**
|
|
1482
|
-
*
|
|
1483
|
-
*
|
|
1061
|
+
* Authenticate a connection with a previously-issued bearer token; resolves
|
|
1062
|
+
* whether the connection is now trusted. The interactive handler is provided
|
|
1063
|
+
* by the host adapter (e.g. Vite DevTools); the standalone server registers
|
|
1064
|
+
* an auto-trust noop when `auth: false`.
|
|
1065
|
+
*
|
|
1066
|
+
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
1067
|
+
* reachable before the connection is trusted; this is the *only* rule the
|
|
1068
|
+
* pre-trust gate applies, no per-method allowlist.
|
|
1069
|
+
*
|
|
1070
|
+
* @internal
|
|
1484
1071
|
*/
|
|
1485
|
-
|
|
1072
|
+
'anonymous:devframe:auth': (params: {
|
|
1073
|
+
authToken: string;
|
|
1074
|
+
ua: string;
|
|
1075
|
+
origin: string;
|
|
1076
|
+
}) => Promise<{
|
|
1077
|
+
isTrusted: boolean;
|
|
1078
|
+
}>;
|
|
1486
1079
|
/**
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1080
|
+
* Exchange a one-time authentication code (shown by the dev server) for a fresh,
|
|
1081
|
+
* node-issued bearer token, returning the token on success or `null`. The
|
|
1082
|
+
* handler is provided by the host adapter on top of `exchangeTempAuthCode`.
|
|
1083
|
+
*
|
|
1084
|
+
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
1085
|
+
* reachable before the connection is trusted.
|
|
1086
|
+
*
|
|
1087
|
+
* @internal
|
|
1494
1088
|
*/
|
|
1495
|
-
|
|
1089
|
+
'anonymous:devframe:auth:exchange': (params: {
|
|
1090
|
+
code: string;
|
|
1091
|
+
ua: string;
|
|
1092
|
+
origin: string;
|
|
1093
|
+
}) => Promise<{
|
|
1094
|
+
authToken: string | null;
|
|
1095
|
+
}>;
|
|
1496
1096
|
/**
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
1097
|
+
* Ask the server to print its auth banner (code + magic link) for this
|
|
1098
|
+
* client, e.g. when an auth UI first shows; `reissue: true` rotates the code
|
|
1099
|
+
* first (the manual "re-issue" action). Registered by
|
|
1100
|
+
* `recipes/interactive-auth`; a repeat request for an already-printed code
|
|
1101
|
+
* is a no-op.
|
|
1502
1102
|
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
* widen it past loopback, layer on {@link McpRouteOptions.authorization} to
|
|
1508
|
-
* prove identity too.
|
|
1103
|
+
* Named with the `anonymous:` prefix (see `isAnonymousRpcMethod`) so it is
|
|
1104
|
+
* reachable before the connection is trusted.
|
|
1105
|
+
*
|
|
1106
|
+
* @internal
|
|
1509
1107
|
*/
|
|
1510
|
-
|
|
1108
|
+
'anonymous:devframe:auth:request-code': (params: {
|
|
1109
|
+
ua: string;
|
|
1110
|
+
origin: string;
|
|
1111
|
+
reissue?: boolean;
|
|
1112
|
+
}) => Promise<void>;
|
|
1511
1113
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1514
|
-
*
|
|
1515
|
-
*
|
|
1516
|
-
* - `(key) => boolean`: only the keys the filter accepts
|
|
1114
|
+
* Self-revoke: the caller asks the server to revoke its own bearer token
|
|
1115
|
+
* (if any) and drop to untrusted. Requires an already-trusted caller, so
|
|
1116
|
+
* unlike the two handshake methods above it does **not** carry the
|
|
1117
|
+
* `anonymous:` prefix. Registered by `recipes/interactive-auth`.
|
|
1517
1118
|
*
|
|
1518
|
-
*
|
|
1119
|
+
* @internal
|
|
1519
1120
|
*/
|
|
1520
|
-
|
|
1121
|
+
'devframe:auth:revoke': () => Promise<void>;
|
|
1521
1122
|
/**
|
|
1522
|
-
*
|
|
1523
|
-
* `
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1123
|
+
* Subscribe a client to a shared-state key. Wired by
|
|
1124
|
+
* `RpcSharedStateHost`; do not register manually.
|
|
1125
|
+
*
|
|
1126
|
+
* @internal
|
|
1526
1127
|
*/
|
|
1527
|
-
|
|
1128
|
+
'devframe:rpc:server-state:subscribe': (key: string) => Promise<void>;
|
|
1528
1129
|
/**
|
|
1529
|
-
*
|
|
1530
|
-
* `
|
|
1531
|
-
*
|
|
1532
|
-
*
|
|
1533
|
-
* the first template whose `uriTemplate` matches the URI reads it. `resources/list` adds the
|
|
1534
|
-
* entries each template's `list` returns. Omitted or empty keeps the
|
|
1535
|
-
* resources unchanged.
|
|
1130
|
+
* Read the current value for a shared-state key. Wired by
|
|
1131
|
+
* `RpcSharedStateHost`; do not register manually.
|
|
1132
|
+
*
|
|
1133
|
+
* @internal
|
|
1536
1134
|
*/
|
|
1537
|
-
|
|
1135
|
+
'devframe:rpc:server-state:get': (key: string) => Promise<any>;
|
|
1538
1136
|
/**
|
|
1539
|
-
*
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1137
|
+
* Replace a shared-state value (from the client). Wired by
|
|
1138
|
+
* `RpcSharedStateHost`; do not register manually.
|
|
1139
|
+
*
|
|
1140
|
+
* @internal
|
|
1543
1141
|
*/
|
|
1544
|
-
|
|
1142
|
+
'devframe:rpc:server-state:set': (key: string, value: any, syncId: string) => Promise<void>;
|
|
1545
1143
|
/**
|
|
1546
|
-
*
|
|
1547
|
-
* `
|
|
1144
|
+
* Apply a patch to a shared-state value (from the client). Wired by
|
|
1145
|
+
* `RpcSharedStateHost`; do not register manually.
|
|
1146
|
+
*
|
|
1147
|
+
* @internal
|
|
1548
1148
|
*/
|
|
1549
|
-
|
|
1550
|
-
}
|
|
1551
|
-
interface DevframeCliOptions {
|
|
1552
|
-
/** Binary name; default: the devframe's `id`. */
|
|
1553
|
-
command?: string;
|
|
1554
|
-
/** Preferred port for the dev server (default 9999). */
|
|
1555
|
-
port?: number;
|
|
1556
|
-
/** Port scan range, forwarded to `get-port-please`. */
|
|
1557
|
-
portRange?: [number, number];
|
|
1558
|
-
/** Prefer a random open port. */
|
|
1559
|
-
random?: boolean;
|
|
1560
|
-
/** Default host to bind to; `--host` overrides. */
|
|
1561
|
-
host?: string;
|
|
1149
|
+
'devframe:rpc:server-state:patch': (key: string, patches: any[], syncId: string) => Promise<void>;
|
|
1562
1150
|
/**
|
|
1563
|
-
*
|
|
1564
|
-
*
|
|
1565
|
-
*
|
|
1151
|
+
* Client→server streaming subscription with optional replay cursor.
|
|
1152
|
+
* Wired by `RpcStreamingHost`; do not register manually.
|
|
1153
|
+
*
|
|
1154
|
+
* @internal
|
|
1566
1155
|
*/
|
|
1567
|
-
|
|
1156
|
+
'devframe:streaming:subscribe': (channel: string, id: string, opts?: {
|
|
1157
|
+
afterSeq?: number;
|
|
1158
|
+
}) => Promise<void>;
|
|
1568
1159
|
/**
|
|
1569
|
-
*
|
|
1570
|
-
*
|
|
1571
|
-
* - `undefined` / `true`: the standalone adapters (`cli` /
|
|
1572
|
-
* served `build`) auto-wire devframe's interactive OTP auth
|
|
1573
|
-
* (`createInteractiveAuth`): an untrusted client can only reach
|
|
1574
|
-
* `anonymous:` methods until it exchanges the printed one-time code.
|
|
1575
|
-
* The adapter prints the code + magic-link banner once the server is
|
|
1576
|
-
* listening.
|
|
1577
|
-
* - `false`: no gate, for trusted single-user localhost tools where an
|
|
1578
|
-
* auth round-trip only gets in the way (the built-in plugins set this).
|
|
1579
|
-
* The `--no-auth` CLI flag maps here for one-off runs.
|
|
1580
|
-
* - A {@link DevframeAuthHandler}: a custom handler (e.g. a tuned
|
|
1581
|
-
* `createInteractiveAuth`, or an entirely different scheme) passed
|
|
1582
|
-
* straight through to the RPC transport binding.
|
|
1160
|
+
* Client→server streaming unsubscribe. Wired by `RpcStreamingHost`;
|
|
1161
|
+
* do not register manually.
|
|
1583
1162
|
*
|
|
1584
|
-
*
|
|
1585
|
-
|
|
1163
|
+
* @internal
|
|
1164
|
+
*/
|
|
1165
|
+
'devframe:streaming:unsubscribe': (channel: string, id: string) => Promise<void>;
|
|
1166
|
+
/**
|
|
1167
|
+
* Client→server streaming cancellation request. Wired by
|
|
1168
|
+
* `RpcStreamingHost`; do not register manually.
|
|
1586
1169
|
*
|
|
1587
|
-
* @
|
|
1170
|
+
* @internal
|
|
1588
1171
|
*/
|
|
1589
|
-
|
|
1172
|
+
'devframe:streaming:cancel': (channel: string, id: string) => Promise<void>;
|
|
1590
1173
|
/**
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1595
|
-
*/
|
|
1596
|
-
ws?: DevframeWsOptions | false;
|
|
1597
|
-
/**
|
|
1598
|
-
* How the browser reaches the SSE RPC endpoint, enabled by default
|
|
1599
|
-
* alongside the WebSocket as the more portable transport. Pass `false`
|
|
1600
|
-
* to disable, or a {@link DevframeSseOptions} to change its route.
|
|
1601
|
-
*/
|
|
1602
|
-
sse?: boolean | DevframeSseOptions;
|
|
1603
|
-
/**
|
|
1604
|
-
* Capability-side CAC hook. Called with the CAC instance after the
|
|
1605
|
-
* adapter registers its built-in commands (`build` / `mcp`)
|
|
1606
|
-
* but before `createCac`'s own `configureCli` caller. Use this to
|
|
1607
|
-
* contribute tool-specific flags and subcommands from the definition
|
|
1608
|
-
* itself.
|
|
1174
|
+
* Client→server upload chunk. Wired by `RpcStreamingHost`; do not
|
|
1175
|
+
* register manually.
|
|
1176
|
+
*
|
|
1177
|
+
* @internal
|
|
1609
1178
|
*/
|
|
1610
|
-
|
|
1179
|
+
'devframe:streaming:upload-chunk': (channel: string, id: string, seq: number, chunk: any) => Promise<void>;
|
|
1611
1180
|
/**
|
|
1612
|
-
*
|
|
1613
|
-
*
|
|
1614
|
-
* zod, arktype, or devframe's built-in `s`). The adapter registers
|
|
1615
|
-
* matching `--kebab-key` options on CAC, validates the parsed values,
|
|
1616
|
-
* and forwards the typed bag to `setup(ctx, { flags })`.
|
|
1617
|
-
*
|
|
1618
|
-
* Use {@link defineCliFlags} to preserve the literal schema-map
|
|
1619
|
-
* shape, and {@link InferCliFlags} to recover the typed output at the
|
|
1620
|
-
* call site:
|
|
1621
|
-
*
|
|
1622
|
-
* ```ts
|
|
1623
|
-
* const appFlags = defineCliFlags({
|
|
1624
|
-
* depth: v.pipe(v.number(), v.integer()),
|
|
1625
|
-
* config: v.optional(v.string()),
|
|
1626
|
-
* })
|
|
1181
|
+
* Client→server upload terminator. Wired by `RpcStreamingHost`; do not
|
|
1182
|
+
* register manually.
|
|
1627
1183
|
*
|
|
1628
|
-
*
|
|
1629
|
-
* cli: { flags: appFlags },
|
|
1630
|
-
* setup(ctx, info) {
|
|
1631
|
-
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
1632
|
-
* },
|
|
1633
|
-
* })
|
|
1634
|
-
* ```
|
|
1184
|
+
* @internal
|
|
1635
1185
|
*/
|
|
1636
|
-
|
|
1186
|
+
'devframe:streaming:upload-end': (channel: string, id: string, error?: {
|
|
1187
|
+
name: string;
|
|
1188
|
+
message: string;
|
|
1189
|
+
}) => Promise<void>;
|
|
1637
1190
|
}
|
|
1638
1191
|
/**
|
|
1639
|
-
*
|
|
1640
|
-
* mounts this devframe. Framework-neutral metadata only; the hub layer
|
|
1641
|
-
* (`ctx.install`) merges these beneath its per-mount `dock` overrides,
|
|
1642
|
-
* which in turn sit beneath the locked, derived `id` / `type` / `url`.
|
|
1643
|
-
*
|
|
1644
|
-
* Every field is optional. `title` / `icon` default to the definition's
|
|
1645
|
-
* `name` / `icon` when omitted here; the rest are unset by default.
|
|
1646
|
-
* Standalone adapters (`cli` / `build`) ignore this entirely.
|
|
1192
|
+
* To be extended
|
|
1647
1193
|
*/
|
|
1648
|
-
interface
|
|
1649
|
-
/** Dock entry title. Defaults to the definition's `name`. */
|
|
1650
|
-
title?: string;
|
|
1651
|
-
/** Translations of `title` by BCP 47 tag; see `@devframes/hub`'s `resolveTitle()`. */
|
|
1652
|
-
titleLocales?: Record<string, string>;
|
|
1653
|
-
/** Dock entry icon. Defaults to the definition's `icon`. */
|
|
1654
|
-
icon?: string | {
|
|
1655
|
-
light: string;
|
|
1656
|
-
dark: string;
|
|
1657
|
-
};
|
|
1194
|
+
interface DevframeRpcSharedStates {
|
|
1658
1195
|
/**
|
|
1659
|
-
*
|
|
1660
|
-
* @
|
|
1196
|
+
* Wire-service advertisements: package name → `{ package, version,
|
|
1197
|
+
* scope, meta }` for every installed {@link import('./services').DevframeServiceDefinition}.
|
|
1198
|
+
* Written by the node services host at the `ready()` barrier; clients read
|
|
1199
|
+
* it through `client.services` (or subscribe to it directly for
|
|
1200
|
+
* reactivity). Read-only from the browser.
|
|
1661
1201
|
*/
|
|
1662
|
-
|
|
1202
|
+
'devframe:services': DevframeServicesState;
|
|
1203
|
+
}
|
|
1204
|
+
interface DevframeNodeRpcSession {
|
|
1205
|
+
meta: DevframeNodeRpcSessionMeta;
|
|
1206
|
+
rpc: BirpcReturn<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>;
|
|
1207
|
+
}
|
|
1208
|
+
interface RpcBroadcastOptions<METHOD, Args extends any[]> {
|
|
1209
|
+
method: METHOD;
|
|
1210
|
+
args: Args;
|
|
1211
|
+
optional?: boolean;
|
|
1212
|
+
event?: boolean;
|
|
1213
|
+
filter?: (client: BirpcReturn<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>) => boolean | void;
|
|
1214
|
+
}
|
|
1215
|
+
type RpcFunctionsHost = RpcFunctionsCollectorBase<DevframeRpcServerFunctions, DevframeNodeContext> & {
|
|
1663
1216
|
/**
|
|
1664
|
-
*
|
|
1665
|
-
*
|
|
1217
|
+
* Invoke a locally registered server RPC function directly.
|
|
1218
|
+
*
|
|
1219
|
+
* This bypasses transport and is useful for server-side cross-function calls.
|
|
1666
1220
|
*/
|
|
1667
|
-
|
|
1221
|
+
invokeLocal: <T extends keyof DevframeRpcServerFunctions, Args extends Parameters<DevframeRpcServerFunctions[T]>>(method: T, ...args: Args) => Promise<Awaited<ReturnType<DevframeRpcServerFunctions[T]>>>;
|
|
1668
1222
|
/**
|
|
1669
|
-
*
|
|
1670
|
-
* clauses). Set to `'false'` to hide the entry unconditionally.
|
|
1223
|
+
* Broadcast a message to all connected clients
|
|
1671
1224
|
*/
|
|
1672
|
-
|
|
1225
|
+
broadcast: <T extends keyof DevframeRpcClientFunctions, Args extends Parameters<DevframeRpcClientFunctions[T]>>(options: RpcBroadcastOptions<T, Args>) => Promise<void>;
|
|
1673
1226
|
/**
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1676
|
-
*
|
|
1677
|
-
* which is the general relevance switch for the entry as a whole.
|
|
1227
|
+
* Get the current RPC client
|
|
1228
|
+
*
|
|
1229
|
+
* Available in RPC functions to get the current RPC client
|
|
1678
1230
|
*/
|
|
1679
|
-
|
|
1680
|
-
/** Badge text rendered on the dock icon (e.g. an unread count). */
|
|
1681
|
-
badge?: string;
|
|
1682
|
-
/** Id of the dock group this entry collapses under, if any. */
|
|
1683
|
-
groupId?: string;
|
|
1231
|
+
getCurrentRpcSession: () => DevframeNodeRpcSession | undefined;
|
|
1684
1232
|
/**
|
|
1685
|
-
*
|
|
1686
|
-
* script**). An absolute-path `importFrom` is served by the hub under the
|
|
1687
|
-
* mount base and rewritten to that URL, so mounting by package name needs no
|
|
1688
|
-
* host wiring; a URL or bare specifier passes through untouched.
|
|
1233
|
+
* The shared state host
|
|
1689
1234
|
*/
|
|
1690
|
-
|
|
1691
|
-
/**
|
|
1692
|
-
* Initialize after RPC trust without waiting for dock activation.
|
|
1693
|
-
* @default false
|
|
1694
|
-
*/
|
|
1695
|
-
eager?: boolean;
|
|
1696
|
-
/** An absolute filesystem path, a served URL, or a bare npm specifier. */
|
|
1697
|
-
importFrom: string;
|
|
1698
|
-
/**
|
|
1699
|
-
* The name to import the module as.
|
|
1700
|
-
* @default 'default'
|
|
1701
|
-
*/
|
|
1702
|
-
importName?: string;
|
|
1703
|
-
};
|
|
1704
|
-
}
|
|
1705
|
-
/**
|
|
1706
|
-
* Runtime information threaded into `setup(ctx, info)`. Adapters
|
|
1707
|
-
* populate the fields that make sense for their deployment. In
|
|
1708
|
-
* particular, `createCac` fills `flags` with the parsed CAC bag.
|
|
1709
|
-
*/
|
|
1710
|
-
interface DevframeSetupInfo {
|
|
1711
|
-
/** Parsed CLI flags, populated by the CLI adapter. */
|
|
1712
|
-
flags?: Record<string, unknown>;
|
|
1713
|
-
}
|
|
1714
|
-
interface DevframeDefinition {
|
|
1715
|
-
id: string;
|
|
1716
|
-
name: string;
|
|
1717
|
-
/** Semver of the tool, surfaced in hub UIs and diagnostics. */
|
|
1718
|
-
version: string;
|
|
1719
|
-
/** npm package name the devframe ships in (e.g. `@scope/my-tool`). */
|
|
1720
|
-
packageName: string;
|
|
1235
|
+
sharedState: RpcSharedStateHost;
|
|
1721
1236
|
/**
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
* for the tool's own dependency graph, which lets the host resolve
|
|
1725
|
-
* everything against the plugin's own installed packages rather than the
|
|
1726
|
-
* consuming app's.
|
|
1727
|
-
*
|
|
1728
|
-
* - **Remote assets**: becomes the default `resolveFrom` for any remote
|
|
1729
|
-
* {@link StaticAssetsSource} the devframe hosts (its `clientAssets`, and
|
|
1730
|
-
* every `ctx.views.hostStatic` call) that doesn't set one explicitly, so a
|
|
1731
|
-
* locally installed copy of the assets package is served with zero
|
|
1732
|
-
* network. A per-asset `resolveFrom` still wins, and an explicit
|
|
1733
|
-
* `resolveFrom: null` still opts out.
|
|
1734
|
-
* - **Service dependencies**: becomes the base the host resolves declared
|
|
1735
|
-
* {@link DevframeServiceInput | services} from, so a plugin can ship a
|
|
1736
|
-
* service package as its own dependency instead of asking users to install
|
|
1737
|
-
* it.
|
|
1237
|
+
* The streaming channel host. Provides per-channel `start()` /
|
|
1238
|
+
* `pipeFrom()` producers; clients consume via `rpc.streaming.subscribe()`.
|
|
1738
1239
|
*
|
|
1739
|
-
*
|
|
1740
|
-
* runtime-directory resolution and disables the zero-network installed-copy
|
|
1741
|
-
* fast paths above.
|
|
1240
|
+
* @see RpcStreamingHost
|
|
1742
1241
|
*/
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1242
|
+
streaming: RpcStreamingHost;
|
|
1243
|
+
};
|
|
1244
|
+
interface RpcSharedStateGetOptions<T> {
|
|
1245
|
+
sharedState?: SharedState<T>;
|
|
1246
|
+
initialValue?: T;
|
|
1247
|
+
}
|
|
1248
|
+
interface RpcSharedStateHost {
|
|
1249
|
+
get: <T extends object = any>(key: string, options?: RpcSharedStateGetOptions<T>) => Promise<SharedState<T>>;
|
|
1250
|
+
keys: () => string[];
|
|
1752
1251
|
/**
|
|
1753
|
-
*
|
|
1754
|
-
*
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1758
|
-
* @see {@link DevframeDockDefaults}
|
|
1252
|
+
* Subscribe to new shared-state keys becoming available. Fires when
|
|
1253
|
+
* `get(key, ...)` creates a fresh entry (not on subsequent gets).
|
|
1254
|
+
* Useful for protocol adapters (e.g. MCP) that surface shared state
|
|
1255
|
+
* as dynamic resources.
|
|
1759
1256
|
*/
|
|
1760
|
-
|
|
1257
|
+
onKeyAdded: (fn: (key: string) => void) => () => void;
|
|
1761
1258
|
/**
|
|
1762
|
-
*
|
|
1763
|
-
*
|
|
1764
|
-
* (
|
|
1259
|
+
* Unregister a shared state and drop its broadcast listeners. Returns
|
|
1260
|
+
* `true` when a state was removed, `false` when the key was unknown.
|
|
1261
|
+
* Used by short-lived states (e.g. a disposed JSON-render view) to avoid
|
|
1262
|
+
* leaking listeners and lingering entries for the context lifetime.
|
|
1765
1263
|
*/
|
|
1766
|
-
|
|
1264
|
+
delete: (key: string) => boolean;
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Options for `RpcStreamingHost.create()`.
|
|
1268
|
+
*/
|
|
1269
|
+
interface RpcStreamingChannelOptions {
|
|
1767
1270
|
/**
|
|
1768
|
-
*
|
|
1769
|
-
*
|
|
1770
|
-
*
|
|
1771
|
-
* ignore it.
|
|
1271
|
+
* Size of the per-stream ring buffer kept on the server for
|
|
1272
|
+
* replay-on-resubscribe. `0` (default) disables replay; on reconnect
|
|
1273
|
+
* the consumer only sees chunks that arrive after subscribing.
|
|
1772
1274
|
*
|
|
1773
|
-
*
|
|
1275
|
+
* The buffer is per stream id, not per channel; each `channel.start()`
|
|
1276
|
+
* gets its own.
|
|
1774
1277
|
*/
|
|
1775
|
-
|
|
1278
|
+
replayWindow?: number;
|
|
1776
1279
|
/**
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1280
|
+
* Milliseconds a closed stream is retained on the server after its
|
|
1281
|
+
* last subscriber leaves (or if no subscriber ever arrived). During
|
|
1282
|
+
* this window, late subscribers can still join and replay the buffer
|
|
1283
|
+
* + receive the `end` frame.
|
|
1779
1284
|
*
|
|
1780
|
-
*
|
|
1781
|
-
*
|
|
1782
|
-
*
|
|
1783
|
-
* no SPA copy, no RPCs in the dump. Useful for a devframe whose value is
|
|
1784
|
-
* inherently live (e.g. it manages real files on disk), so a static
|
|
1785
|
-
* export would only ever produce a broken, write-less shell of the tool.
|
|
1786
|
-
* - `dev: false`: `createDevServer` refuses (throws `DF0058`) unless
|
|
1787
|
-
* `{ force: true }`. Useful for a devframe that only makes sense as a
|
|
1788
|
-
* static export (e.g. a report generator with nothing to serve live).
|
|
1285
|
+
* Defaults to `30_000` (30 s) when `replayWindow > 0`, else `0`
|
|
1286
|
+
* (immediate free). Set to `0` to opt out, or higher for longer
|
|
1287
|
+
* post-mortem replay.
|
|
1789
1288
|
*/
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1289
|
+
closedStreamRetention?: number;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Channel handle returned by `ctx.rpc.streaming.create(name, opts)`. A
|
|
1293
|
+
* channel owns a wire namespace; calling `start()` produces individual
|
|
1294
|
+
* streams keyed by id.
|
|
1295
|
+
*
|
|
1296
|
+
* @see {@link https://devfra.me/guide/streaming Streaming guide}
|
|
1297
|
+
*/
|
|
1298
|
+
interface RpcStreamingChannel<T = unknown> {
|
|
1299
|
+
/** Channel name as registered with `ctx.rpc.streaming.create()`. */
|
|
1300
|
+
readonly name: string;
|
|
1794
1301
|
/**
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
* own dependencies**) or a ready `DevframeServiceDefinition` (the factory
|
|
1800
|
-
* was already called). The adapter queues these before `setup(ctx)` runs
|
|
1801
|
-
* and constructs each service once at the `ctx.services.ready()` barrier,
|
|
1802
|
-
* merging option sets across every declarer. Missing services are skipped
|
|
1803
|
-
* unless marked `required`; clients feature-detect via
|
|
1804
|
-
* `client.services.has(pkg)` and degrade.
|
|
1302
|
+
* Start a new stream. Returns a server-side sink with both an imperative
|
|
1303
|
+
* (`write` / `close` / `error`) surface and a `WritableStream<T>` for
|
|
1304
|
+
* `pipeTo` consumption. The sink's `signal` aborts when every subscriber
|
|
1305
|
+
* disconnects or cancels.
|
|
1805
1306
|
*/
|
|
1806
|
-
|
|
1307
|
+
start: (opts?: {
|
|
1308
|
+
id?: string;
|
|
1309
|
+
}) => StreamSink<T>;
|
|
1807
1310
|
/**
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
1810
|
-
* served through devframe's caching CDN back-proxy so the assets need not
|
|
1811
|
-
* ship inside the node package.
|
|
1311
|
+
* Convenience: start a stream and pipe a `ReadableStream<T>` into it.
|
|
1312
|
+
* The pipe uses `sink.signal` so cancellation propagates upstream.
|
|
1812
1313
|
*
|
|
1813
|
-
*
|
|
1814
|
-
*
|
|
1314
|
+
* Node-stream interop: convert a `Readable` with `Readable.toWeb(node)`
|
|
1315
|
+
* before passing it here.
|
|
1815
1316
|
*/
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
/**
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
interface DevframeRpcOptions {
|
|
1317
|
+
pipeFrom: (readable: ReadableStream<T>, opts?: {
|
|
1318
|
+
id?: string;
|
|
1319
|
+
}) => Promise<StreamSink<T>>;
|
|
1320
|
+
/** Look up an active stream by id. Returns `undefined` if none. */
|
|
1321
|
+
get: (id: string) => StreamSink<T> | undefined;
|
|
1322
|
+
/** All active outbound stream ids on this channel. */
|
|
1323
|
+
ids: () => string[];
|
|
1824
1324
|
/**
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1325
|
+
* Open an inbound stream: the server side of a client-to-server
|
|
1326
|
+
* upload. Allocates an id, returns a `StreamReader<T>` that fills as
|
|
1327
|
+
* the client writes chunks. Typical pattern is to call this from an
|
|
1328
|
+
* action handler, kick off background processing, and return the id
|
|
1329
|
+
* so the caller can start uploading:
|
|
1829
1330
|
*
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
1832
|
-
*
|
|
1833
|
-
* (
|
|
1834
|
-
*
|
|
1835
|
-
*
|
|
1836
|
-
*
|
|
1331
|
+
* ```ts
|
|
1332
|
+
* handler: async () => {
|
|
1333
|
+
* const reader = channel.openInbound()
|
|
1334
|
+
* ;(async () => {
|
|
1335
|
+
* for await (const chunk of reader) processChunk(chunk)
|
|
1336
|
+
* })()
|
|
1337
|
+
* return { uploadId: reader.id }
|
|
1338
|
+
* }
|
|
1339
|
+
* ```
|
|
1340
|
+
*
|
|
1341
|
+
* Calling `reader.cancel()` on the server sends an `upload-cancel` to
|
|
1342
|
+
* the uploading client, which aborts its sink.
|
|
1837
1343
|
*/
|
|
1838
|
-
|
|
1344
|
+
openInbound: (opts?: {
|
|
1345
|
+
id?: string;
|
|
1346
|
+
}) => StreamReader<T>;
|
|
1839
1347
|
}
|
|
1840
|
-
/** Argument-tuples to bake for a {@link DevframeSnapshotRpcEntry}, or a provider that computes them at build time. */
|
|
1841
|
-
type DevframeSnapshotRpcInputs = readonly (readonly unknown[])[] | ((ctx: DevframeNodeContext) => readonly (readonly unknown[])[] | Promise<readonly (readonly unknown[])[]>);
|
|
1842
|
-
/**
|
|
1843
|
-
* One {@link DevframeRpcOptions.snapshot} entry: a bare method id (bakes
|
|
1844
|
-
* the no-argument call) or a method plus the argument-tuples to bake.
|
|
1845
|
-
*/
|
|
1846
|
-
type DevframeSnapshotRpcEntry = string | {
|
|
1847
|
-
method: string;
|
|
1848
|
-
inputs: DevframeSnapshotRpcInputs;
|
|
1849
|
-
};
|
|
1850
|
-
//#endregion
|
|
1851
|
-
//#region src/utils/shared-state.d.ts
|
|
1852
|
-
type ImmutablePrimitive = undefined | null | boolean | string | number | Function;
|
|
1853
|
-
type Immutable<T> = T extends ImmutablePrimitive ? T : T extends Array<infer U> ? ImmutableArray<U> : T extends Map<infer K, infer V> ? ImmutableMap<K, V> : T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>;
|
|
1854
|
-
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
|
|
1855
|
-
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
|
|
1856
|
-
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
|
|
1857
|
-
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]>; };
|
|
1858
1348
|
/**
|
|
1859
|
-
*
|
|
1860
|
-
*
|
|
1349
|
+
* Server-side streaming host. Lives on `ctx.rpc.streaming` alongside
|
|
1350
|
+
* `ctx.rpc.sharedState`. Each named channel owns its own stream registry
|
|
1351
|
+
* and wire namespace.
|
|
1861
1352
|
*/
|
|
1862
|
-
interface
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1353
|
+
interface RpcStreamingHost {
|
|
1354
|
+
/**
|
|
1355
|
+
* Register a streaming channel. Names follow the `<plugin-id>:<channel>`
|
|
1356
|
+
* convention (e.g. `'my-devtool:chat-stream'`). Throws `DF0032` if the
|
|
1357
|
+
* name is already taken.
|
|
1358
|
+
*/
|
|
1359
|
+
create: <T = unknown>(name: string, opts?: RpcStreamingChannelOptions) => RpcStreamingChannel<T>;
|
|
1360
|
+
/**
|
|
1361
|
+
* Adapters call this when a session disconnects so the host can drop
|
|
1362
|
+
* subscribers and abort orphaned streams. Most users do not need this;
|
|
1363
|
+
* it's wired by the RPC server binding automatically.
|
|
1364
|
+
*
|
|
1365
|
+
* @internal
|
|
1366
|
+
*/
|
|
1367
|
+
_onSessionDisconnected: (meta: DevframeNodeRpcSessionMeta) => void;
|
|
1368
|
+
}
|
|
1369
|
+
interface DevframeCapabilities {
|
|
1370
|
+
rpc?: boolean;
|
|
1371
|
+
views?: boolean;
|
|
1866
1372
|
}
|
|
1867
1373
|
/**
|
|
1868
|
-
*
|
|
1374
|
+
* Framework- and build-tool-agnostic node context: RPC + diagnostics +
|
|
1375
|
+
* agent + the view-host (HTTP file-serving). Host adapters can wrap this
|
|
1376
|
+
* to add their own surfaces; for example, `@vitejs/devtools-kit`'s
|
|
1377
|
+
* `createKitContext` adds `docks`, `terminals`, `messages`, and
|
|
1378
|
+
* `commands` when mounted into Vite DevTools. JSON rendering is an opt-in
|
|
1379
|
+
* integration (`@devframes/json-render`) layered on top, not part of this
|
|
1380
|
+
* core surface.
|
|
1869
1381
|
*/
|
|
1870
|
-
interface
|
|
1382
|
+
interface DevframeNodeContext {
|
|
1383
|
+
readonly workspaceRoot: string;
|
|
1384
|
+
readonly cwd: string;
|
|
1871
1385
|
/**
|
|
1872
|
-
*
|
|
1386
|
+
* Lifecycle distinction surfaced to plugin authors:
|
|
1387
|
+
*
|
|
1388
|
+
* - `'dev'`: long-running, interactive session. Connections come and
|
|
1389
|
+
* go; broadcasts and shared-state mutations are debounced
|
|
1390
|
+
* to keep the UI responsive.
|
|
1391
|
+
* - `'build'`: one-shot batch run. The context is set up, the devtool
|
|
1392
|
+
* collects what it needs, and a snapshot is written. No
|
|
1393
|
+
* live UI, no WS server.
|
|
1394
|
+
*
|
|
1395
|
+
* Names are inherited from Vite's serve/build dichotomy but the meaning
|
|
1396
|
+
* is general: the same distinction applies to any tool that runs in
|
|
1397
|
+
* either an interactive or a static-output mode.
|
|
1873
1398
|
*/
|
|
1874
|
-
|
|
1399
|
+
readonly mode: 'dev' | 'build';
|
|
1875
1400
|
/**
|
|
1876
|
-
*
|
|
1401
|
+
* Host runtime abstraction, exposing `mountStatic` / `resolveOrigin` /
|
|
1402
|
+
* `getStorageDir`.
|
|
1877
1403
|
*/
|
|
1878
|
-
|
|
1404
|
+
host: DevframeHost;
|
|
1405
|
+
rpc: RpcFunctionsHost;
|
|
1406
|
+
views: DevframeViewHost;
|
|
1879
1407
|
/**
|
|
1880
|
-
*
|
|
1408
|
+
* Structured diagnostics host; wraps `nostics` and lets integrations
|
|
1409
|
+
* register their own coded errors/warnings into the shared lookup.
|
|
1881
1410
|
*/
|
|
1882
|
-
|
|
1411
|
+
diagnostics: DevframeDiagnosticsHost;
|
|
1883
1412
|
/**
|
|
1884
|
-
*
|
|
1413
|
+
* Agent host; aggregates the agent-exposed surface of this devtool.
|
|
1885
1414
|
*/
|
|
1886
|
-
|
|
1415
|
+
agent: DevframeAgentHost;
|
|
1887
1416
|
/**
|
|
1888
|
-
*
|
|
1417
|
+
* Cross-plugin services: a typed, namespaced registry through which one
|
|
1418
|
+
* integration exposes a capability (e.g. a data-source registry) and
|
|
1419
|
+
* others consume it without a hard package dependency. Ids follow the RPC
|
|
1420
|
+
* namespacing rule (`<plugin-id>:<service>`); types come from augmenting
|
|
1421
|
+
* the `DevframeServicesRegistry` interface. `whenAvailable` subscriptions
|
|
1422
|
+
* absorb setup-order differences between provider and consumer.
|
|
1889
1423
|
*/
|
|
1890
|
-
|
|
1891
|
-
}
|
|
1892
|
-
interface SharedStateEvents<T> {
|
|
1893
|
-
updated: (fullState: T, patches: SharedStatePatch[] | undefined, syncId: string) => void;
|
|
1894
|
-
}
|
|
1895
|
-
interface SharedStateOptions<T> {
|
|
1424
|
+
services: DevframeServicesHost;
|
|
1896
1425
|
/**
|
|
1897
|
-
*
|
|
1426
|
+
* This context's own {@link ConnectionMeta.configs}: static, boot-time
|
|
1427
|
+
* config a host publishes once through the connection handshake and every
|
|
1428
|
+
* client reads read-only. A plain, **non-reactive** object: mutate it
|
|
1429
|
+
* during `setup(ctx)` (a plugin sets its keys, a hub aggregates across
|
|
1430
|
+
* every installed devframe), never during the session, since it's serialized
|
|
1431
|
+
* once, after setup, and changing it afterwards reaches no client.
|
|
1432
|
+
*
|
|
1433
|
+
* ```ts
|
|
1434
|
+
* ctx.staticConfig.dock = {
|
|
1435
|
+
* ...ctx.staticConfig.dock,
|
|
1436
|
+
* categoryOrder: { ...ctx.staticConfig.dock?.categoryOrder, ...myOrder },
|
|
1437
|
+
* }
|
|
1438
|
+
* ```
|
|
1898
1439
|
*/
|
|
1899
|
-
|
|
1440
|
+
staticConfig: Partial<DevframeConnectionConfigsRegistry>;
|
|
1900
1441
|
/**
|
|
1901
|
-
*
|
|
1442
|
+
* Create a namespace-scoped view of this context. The returned
|
|
1443
|
+
* `ctx.scope('my-plugin')` auto-namespaces every RPC id, shared-state
|
|
1444
|
+
* key, and streaming channel with `my-plugin:`, and exposes a typed
|
|
1445
|
+
* top-level `settings` store. This is the preferred way to consume the
|
|
1446
|
+
* context from a single tool's setup code.
|
|
1902
1447
|
*
|
|
1903
|
-
*
|
|
1448
|
+
* Pass `null` or `''` to un-scope and get the base context.
|
|
1904
1449
|
*/
|
|
1905
|
-
|
|
1450
|
+
scope: {
|
|
1451
|
+
<NS extends string>(namespace: NS): DevframeScopedNodeContext<NS, SettingsForNamespace<NS>>;
|
|
1452
|
+
(namespace?: null | ''): DevframeNodeContext;
|
|
1453
|
+
};
|
|
1906
1454
|
}
|
|
1907
|
-
declare function createSharedState<T extends object>(options: SharedStateOptions<T>): SharedState<T>;
|
|
1908
|
-
//#endregion
|
|
1909
|
-
//#region src/utils/streaming-channel.d.ts
|
|
1910
1455
|
/**
|
|
1911
|
-
*
|
|
1912
|
-
*
|
|
1456
|
+
* Describes where the browser client should open its RPC WebSocket. The
|
|
1457
|
+
* object form is the proxy-flexible default: `path` is resolved relative to
|
|
1458
|
+
* where `__connection.json` was loaded, and the connection is made to the
|
|
1459
|
+
* page's own origin (only the `http`→`ws` / `https`→`wss` protocol swap is
|
|
1460
|
+
* applied). This survives reverse proxies that change the host/port, because
|
|
1461
|
+
* the client never trusts a server-baked hostname; it reuses its own.
|
|
1462
|
+
*
|
|
1463
|
+
* Set `port` (and/or `host`) only when the WS endpoint genuinely lives on a
|
|
1464
|
+
* different origin than the page, e.g. a side-car server on its own port.
|
|
1913
1465
|
*/
|
|
1914
|
-
interface
|
|
1915
|
-
|
|
1916
|
-
|
|
1466
|
+
interface ConnectionMetaWebsocket {
|
|
1467
|
+
/**
|
|
1468
|
+
* Path to the WS endpoint. Relative paths (the default, e.g. `__ws`) are
|
|
1469
|
+
* resolved against `__connection.json`'s location; absolute paths (`/__ws`)
|
|
1470
|
+
* resolve against the page origin.
|
|
1471
|
+
*/
|
|
1472
|
+
path?: string;
|
|
1473
|
+
/** Override the port. Combined with the page hostname unless `host` is set. */
|
|
1474
|
+
port?: number;
|
|
1475
|
+
/** Override the host (`hostname[:port]`). Use for a fully cross-origin endpoint. */
|
|
1476
|
+
host?: string;
|
|
1917
1477
|
}
|
|
1918
1478
|
/**
|
|
1919
|
-
*
|
|
1920
|
-
*
|
|
1921
|
-
*
|
|
1922
|
-
* `
|
|
1923
|
-
*
|
|
1479
|
+
* Object form of {@link ConnectionMeta.sse}: the same proxy-safe shape and
|
|
1480
|
+
* resolution rules as {@link ConnectionMetaWebsocket}, producing an
|
|
1481
|
+
* `http(s)://` endpoint instead of a `ws(s)://` one. Set `port` (and/or
|
|
1482
|
+
* `host`) only when the SSE endpoint genuinely lives on a different origin
|
|
1483
|
+
* than the page, e.g. a side-car server on its own port.
|
|
1924
1484
|
*/
|
|
1925
|
-
interface
|
|
1926
|
-
seq: number;
|
|
1927
|
-
chunk: T;
|
|
1928
|
-
}
|
|
1929
|
-
interface StreamSinkEvents<T> {
|
|
1930
|
-
/** Fired for each `write()`. The RPC layer subscribes and broadcasts. */
|
|
1931
|
-
chunk: (seq: number, chunk: T) => void;
|
|
1932
|
-
/** Terminal; fired exactly once per sink lifetime. */
|
|
1933
|
-
end: (error?: StreamErrorPayload) => void;
|
|
1934
|
-
}
|
|
1935
|
-
interface CreateStreamSinkOptions {
|
|
1936
|
-
id?: string;
|
|
1485
|
+
interface ConnectionMetaSse {
|
|
1937
1486
|
/**
|
|
1938
|
-
*
|
|
1939
|
-
* `
|
|
1487
|
+
* Path to the SSE endpoint. Relative paths (the default, e.g. `__sse`)
|
|
1488
|
+
* are resolved against `__connection.json`'s location; absolute paths
|
|
1489
|
+
* (`/__sse`) resolve against the page origin.
|
|
1940
1490
|
*/
|
|
1941
|
-
|
|
1491
|
+
path?: string;
|
|
1492
|
+
/** Override the port. Combined with the page hostname unless `host` is set. */
|
|
1493
|
+
port?: number;
|
|
1494
|
+
/** Override the host (`hostname[:port]`). Use for a fully cross-origin endpoint. */
|
|
1495
|
+
host?: string;
|
|
1942
1496
|
}
|
|
1943
|
-
|
|
1944
|
-
* Server-side producer handle. Two equivalent surfaces share one piece of
|
|
1945
|
-
* state: the imperative `write/error/close` triple, and a `WritableStream<T>`
|
|
1946
|
-
* for `pipeTo`-style consumption.
|
|
1947
|
-
*/
|
|
1948
|
-
interface StreamSink<T> {
|
|
1949
|
-
/** Stable id used by clients to subscribe. */
|
|
1950
|
-
readonly id: string;
|
|
1497
|
+
interface ConnectionMeta {
|
|
1951
1498
|
/**
|
|
1952
|
-
*
|
|
1953
|
-
*
|
|
1954
|
-
*
|
|
1499
|
+
* The server's primary live-RPC transport (`websocket` / `sse`), `static`
|
|
1500
|
+
* for a pre-computed RPC dump with no live server, or `none` for a server
|
|
1501
|
+
* exposing no RPC transport at all (e.g. an MCP-only deployment).
|
|
1955
1502
|
*/
|
|
1956
|
-
|
|
1957
|
-
/** `true` after `close()` / `error()`. Further writes throw. */
|
|
1958
|
-
readonly closed: boolean;
|
|
1959
|
-
/** Last allocated sequence number. `0` until the first write. */
|
|
1960
|
-
readonly lastSeq: number;
|
|
1961
|
-
write: (chunk: T) => void;
|
|
1962
|
-
error: (reason: unknown) => void;
|
|
1963
|
-
close: () => void;
|
|
1964
|
-
/** External-cancel path. Aborts the signal so handlers can short-circuit. */
|
|
1965
|
-
abort: (reason?: unknown) => void;
|
|
1966
|
-
/** `WritableStream<T>` adapter; same in-memory state as the imperative API. */
|
|
1967
|
-
readonly writable: WritableStream<T>;
|
|
1503
|
+
backend: 'websocket' | 'sse' | 'static' | 'none';
|
|
1968
1504
|
/**
|
|
1969
|
-
*
|
|
1970
|
-
* Not part of the public contract; do not call directly.
|
|
1505
|
+
* WebSocket endpoint, resolved by the client into a `ws(s)://` URL:
|
|
1971
1506
|
*
|
|
1972
|
-
* @
|
|
1507
|
+
* - {@link ConnectionMetaWebsocket}: the proxy-flexible default; a
|
|
1508
|
+
* same-origin path relative to `__connection.json`.
|
|
1509
|
+
* - `number`: a port on the page's hostname (`ws(s)://<host>:<port>`).
|
|
1510
|
+
* - `string`: a full `ws://`/`wss://` URL used verbatim, an `http(s)://`
|
|
1511
|
+
* URL with its protocol swapped, or a path resolved same-origin.
|
|
1973
1512
|
*/
|
|
1974
|
-
|
|
1513
|
+
websocket?: number | string | ConnectionMetaWebsocket;
|
|
1975
1514
|
/**
|
|
1976
|
-
*
|
|
1977
|
-
*
|
|
1515
|
+
* SSE endpoint (`GET` opens the event stream, `POST` carries RPC calls),
|
|
1516
|
+
* resolved by the client into an `http(s)://` URL with the same
|
|
1517
|
+
* proxy-safe rules as {@link ConnectionMeta.websocket}:
|
|
1978
1518
|
*
|
|
1979
|
-
* @
|
|
1519
|
+
* - {@link ConnectionMetaSse}: the proxy-flexible default; a
|
|
1520
|
+
* same-origin path relative to `__connection.json`.
|
|
1521
|
+
* - `string`: a full `http(s)://` URL used verbatim, or a path
|
|
1522
|
+
* resolved same-origin.
|
|
1980
1523
|
*/
|
|
1981
|
-
|
|
1982
|
-
}
|
|
1983
|
-
interface CreateStreamReaderOptions {
|
|
1984
|
-
id?: string;
|
|
1524
|
+
sse?: string | ConnectionMetaSse;
|
|
1985
1525
|
/**
|
|
1986
|
-
*
|
|
1987
|
-
*
|
|
1526
|
+
* Present when the dev server exposes a route-based MCP endpoint
|
|
1527
|
+
* (the host's `mcp` setting). Advertises the MCP Streamable-HTTP route so in-browser
|
|
1528
|
+
* tooling (e.g. an MCP inspector) can discover it without guessing the
|
|
1529
|
+
* path. `path` is relative to `__connection.json`'s location, like the
|
|
1530
|
+
* WebSocket `path`. `port` is set when the endpoint lives on a side-car
|
|
1531
|
+
* server on its own port (bridge mode: `devframeViteBridge`,
|
|
1532
|
+
* `@devframes/next`): the client combines the page hostname with `port`
|
|
1533
|
+
* and resolves `path` against that origin, mirroring
|
|
1534
|
+
* {@link ConnectionMetaWebsocket.port}.
|
|
1988
1535
|
*/
|
|
1989
|
-
|
|
1536
|
+
mcp?: {
|
|
1537
|
+
path: string;
|
|
1538
|
+
port?: number;
|
|
1539
|
+
};
|
|
1990
1540
|
/**
|
|
1991
|
-
*
|
|
1992
|
-
*
|
|
1993
|
-
*
|
|
1541
|
+
* Names of RPC functions that have declared `jsonSerializable: true`.
|
|
1542
|
+
* Used by the WS / static client to dispatch the per-call wire
|
|
1543
|
+
* serializer (strict JSON for these methods, structured-clone for
|
|
1544
|
+
* the rest). Populated by the server / build adapter; absent on
|
|
1545
|
+
* legacy clients, in which case all outgoing messages fall back to
|
|
1546
|
+
* structured-clone.
|
|
1994
1547
|
*/
|
|
1995
|
-
|
|
1996
|
-
/** Called when the consumer cancels; the RPC layer sends `:cancel` upstream. */
|
|
1997
|
-
onCancel?: () => void;
|
|
1998
|
-
}
|
|
1999
|
-
/**
|
|
2000
|
-
* Client-side consumer handle. Both an `AsyncIterable<T>` (for `for await`)
|
|
2001
|
-
* and exposes `readable: ReadableStream<T>` (for `pipeTo`). Pick one; they
|
|
2002
|
-
* share a single internal queue, so concurrent draining will race.
|
|
2003
|
-
*/
|
|
2004
|
-
interface StreamReader<T> extends AsyncIterable<T> {
|
|
2005
|
-
readonly id: string;
|
|
2006
|
-
readonly cancelled: boolean;
|
|
2007
|
-
readonly done: boolean;
|
|
2008
|
-
/** Highest `seq` observed. Used for replay on reconnect. */
|
|
2009
|
-
readonly lastSeenSeq: number;
|
|
2010
|
-
/** `ReadableStream<T>` adapter for `pipeTo`-style consumption. */
|
|
2011
|
-
readonly readable: ReadableStream<T>;
|
|
2012
|
-
cancel: () => void;
|
|
2013
|
-
/** @internal */
|
|
2014
|
-
_push: (seq: number, chunk: T) => void;
|
|
2015
|
-
/** @internal */
|
|
2016
|
-
_end: (error?: StreamErrorPayload) => void;
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Build a server-side stream sink. RPC-agnostic; the RPC host wires
|
|
2020
|
-
* `events.on('chunk' | 'end')` to broadcast, and reads `buffer` to replay
|
|
2021
|
-
* for late or reconnecting subscribers.
|
|
2022
|
-
*/
|
|
2023
|
-
declare function createStreamSink<T>(options?: CreateStreamSinkOptions): StreamSink<T>;
|
|
2024
|
-
/**
|
|
2025
|
-
* Build a client-side stream reader. RPC-agnostic; the RPC host calls
|
|
2026
|
-
* `_push(seq, chunk)` on each incoming chunk and `_end(error?)` on the
|
|
2027
|
-
* terminal frame. Consumers iterate with `for await` or pipe `readable`.
|
|
2028
|
-
*/
|
|
2029
|
-
declare function createStreamReader<T>(options?: CreateStreamReaderOptions): StreamReader<T>;
|
|
2030
|
-
//#endregion
|
|
2031
|
-
//#region src/types/rpc.d.ts
|
|
2032
|
-
interface DevframeNodeRpcSession {
|
|
2033
|
-
meta: DevframeNodeRpcSessionMeta;
|
|
2034
|
-
rpc: BirpcReturn<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>;
|
|
2035
|
-
}
|
|
2036
|
-
interface RpcBroadcastOptions<METHOD, Args extends any[]> {
|
|
2037
|
-
method: METHOD;
|
|
2038
|
-
args: Args;
|
|
2039
|
-
optional?: boolean;
|
|
2040
|
-
event?: boolean;
|
|
2041
|
-
filter?: (client: BirpcReturn<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>) => boolean | void;
|
|
2042
|
-
}
|
|
2043
|
-
type RpcFunctionsHost = RpcFunctionsCollectorBase<DevframeRpcServerFunctions, DevframeNodeContext> & {
|
|
1548
|
+
jsonSerializableMethods?: string[];
|
|
2044
1549
|
/**
|
|
2045
|
-
*
|
|
1550
|
+
* URL of the `__connection.json` that owns this meta's relative paths.
|
|
1551
|
+
* Two producers write it:
|
|
2046
1552
|
*
|
|
2047
|
-
*
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
*
|
|
1553
|
+
* - The client annotates it (absolute) when it publishes the meta on a
|
|
1554
|
+
* shared window for same-origin inheritance: a relative
|
|
1555
|
+
* `websocket.path` resolves against this, so a child SPA mounted at
|
|
1556
|
+
* another base (e.g. a hub mounting several devframes at `/__foo/`,
|
|
1557
|
+
* `/__bar/`, …) inherits a dialable endpoint rather than resolving the
|
|
1558
|
+
* path against its own mount.
|
|
1559
|
+
* - A static hub build serves it (base-absolute, e.g.
|
|
1560
|
+
* `/__devframes/__connection.json`) in each **per-frame** meta, so a
|
|
1561
|
+
* frame SPA that fetched its own copy still resolves the shared RPC
|
|
1562
|
+
* dump from the hub base. Resolved against the fetched URL.
|
|
2052
1563
|
*/
|
|
2053
|
-
|
|
1564
|
+
baseUrl?: string;
|
|
2054
1565
|
/**
|
|
2055
|
-
*
|
|
1566
|
+
* A pre-issued bearer token embedded in the meta so a client trusts the
|
|
1567
|
+
* server on connect without any prompt or `localStorage` lookup. Only a
|
|
1568
|
+
* **hub** serving a **per-frame** connection meta populates this; it
|
|
1569
|
+
* authenticates once at the top level and bakes the resulting token into
|
|
1570
|
+
* the meta each plugin iframe fetches, so a cross-origin frame (which
|
|
1571
|
+
* cannot read the hub's `localStorage`) is still pre-authorized. The
|
|
1572
|
+
* standalone `__connection.json` never carries a token.
|
|
2056
1573
|
*
|
|
2057
|
-
*
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
* The shared state host
|
|
1574
|
+
* > [!WARNING]
|
|
1575
|
+
* > A token in a fetchable JSON is only as protected as the URL serving
|
|
1576
|
+
* > it. Emit it exclusively from hub-controlled, per-frame meta, never
|
|
1577
|
+
* > from a publicly reachable static `__connection.json`.
|
|
2062
1578
|
*/
|
|
2063
|
-
|
|
1579
|
+
authToken?: string;
|
|
2064
1580
|
/**
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
1581
|
+
* Session-scoped token that lets a trusted external viewer register its
|
|
1582
|
+
* browser origin before opening the WebSocket. The host includes it in the
|
|
1583
|
+
* connection metadata, which the viewer obtains through the host page.
|
|
2067
1584
|
*
|
|
2068
|
-
*
|
|
2069
|
-
|
|
2070
|
-
streaming: RpcStreamingHost;
|
|
2071
|
-
};
|
|
2072
|
-
interface RpcSharedStateGetOptions<T> {
|
|
2073
|
-
sharedState?: SharedState<T>;
|
|
2074
|
-
initialValue?: T;
|
|
2075
|
-
}
|
|
2076
|
-
interface RpcSharedStateHost {
|
|
2077
|
-
get: <T extends object = any>(key: string, options?: RpcSharedStateGetOptions<T>) => Promise<SharedState<T>>;
|
|
2078
|
-
keys: () => string[];
|
|
2079
|
-
/**
|
|
2080
|
-
* Subscribe to new shared-state keys becoming available. Fires when
|
|
2081
|
-
* `get(key, ...)` creates a fresh entry (not on subsequent gets).
|
|
2082
|
-
* Useful for protocol adapters (e.g. MCP) that surface shared state
|
|
2083
|
-
* as dynamic resources.
|
|
1585
|
+
* Treat this as a bearer credential. Keep connection metadata containing the
|
|
1586
|
+
* token same-origin until the requesting origin has been verified.
|
|
2084
1587
|
*/
|
|
2085
|
-
|
|
1588
|
+
viewerOriginToken?: string;
|
|
2086
1589
|
/**
|
|
2087
|
-
*
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
1590
|
+
* Static, host-declared configuration, baked in once at connect time and
|
|
1591
|
+
* fixed for the life of the server (e.g. a hub's UI rebrand, or its
|
|
1592
|
+
* aggregated dock-bar layout preferences). Read-only from the browser: a
|
|
1593
|
+
* client only ever reads `rpc.connectionMeta.configs`, never writes to it.
|
|
1594
|
+
*
|
|
1595
|
+
* Contrast this with {@link DevframeSettingsRegistry} (`ctx.scope(ns).settings`)
|
|
1596
|
+
* and a hub's `devframe:user-settings` shared-state key; both are
|
|
1597
|
+
* mutable, user-editable, and synced bidirectionally over RPC for the
|
|
1598
|
+
* life of the session. `configs` is the opposite: one-way, immutable,
|
|
1599
|
+
* decided by whoever assembled the server.
|
|
1600
|
+
*
|
|
1601
|
+
* Each key is owned by one package, contributed via declaration merging:
|
|
1602
|
+
*
|
|
1603
|
+
* ```ts
|
|
1604
|
+
* declare module 'devframe/types' {
|
|
1605
|
+
* interface DevframeConnectionConfigsRegistry {
|
|
1606
|
+
* 'my-key': { some: 'shape' }
|
|
1607
|
+
* }
|
|
1608
|
+
* }
|
|
1609
|
+
* ```
|
|
2091
1610
|
*/
|
|
2092
|
-
|
|
1611
|
+
configs?: Partial<DevframeConnectionConfigsRegistry>;
|
|
2093
1612
|
}
|
|
2094
1613
|
/**
|
|
2095
|
-
*
|
|
1614
|
+
* Augmentation point for {@link ConnectionMeta.configs}. Empty by default;
|
|
1615
|
+
* a package that wants to publish static, boot-time config through the
|
|
1616
|
+
* connection handshake augments this interface with its own key (see
|
|
1617
|
+
* {@link ConnectionMeta.configs} for the pattern). `@devframes/hub`
|
|
1618
|
+
* augments it with `dock`; `@devframes/hub-ui` augments it with `ui`.
|
|
2096
1619
|
*/
|
|
2097
|
-
interface
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
1620
|
+
interface DevframeConnectionConfigsRegistry {}
|
|
1621
|
+
/**
|
|
1622
|
+
* Schema map for typed CLI flags. Keys are flag names in camelCase, so
|
|
1623
|
+
* this matches CAC's parsed-flag output ( `--no-open` → `noOpen` ). Each
|
|
1624
|
+
* value is any [Standard Schema](https://standardschema.dev/) validator
|
|
1625
|
+
* (valibot, zod, arktype, devframe's built-in `s`, …) used to both (a)
|
|
1626
|
+
* derive the CAC option type when the flag is registered and (b) validate
|
|
1627
|
+
* the parsed value before it's forwarded to `setup(ctx, { flags })`.
|
|
1628
|
+
*/
|
|
1629
|
+
type CliFlagsSchema = Record<string, StandardSchemaV1>;
|
|
1630
|
+
/**
|
|
1631
|
+
* Identity helper that preserves the literal schema-map type; use this
|
|
1632
|
+
* so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
|
|
1633
|
+
*
|
|
1634
|
+
* ```ts
|
|
1635
|
+
* const appFlags = defineCliFlags({
|
|
1636
|
+
* depth: v.pipe(v.number(), v.integer()),
|
|
1637
|
+
* config: v.optional(v.string()),
|
|
1638
|
+
* })
|
|
1639
|
+
*
|
|
1640
|
+
* defineDevframe({
|
|
1641
|
+
* cli: { flags: appFlags },
|
|
1642
|
+
* setup(ctx, info) {
|
|
1643
|
+
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
1644
|
+
* flags.depth // number
|
|
1645
|
+
* flags.config // string | undefined
|
|
1646
|
+
* },
|
|
1647
|
+
* })
|
|
1648
|
+
* ```
|
|
1649
|
+
*/
|
|
1650
|
+
declare function defineCliFlags<T extends CliFlagsSchema>(flags: T): T;
|
|
1651
|
+
/** Extract the parsed-output type from a {@link CliFlagsSchema}. */
|
|
1652
|
+
type InferCliFlags<T extends CliFlagsSchema> = { [K in keyof T]: StandardSchemaV1.InferOutput<T[K]>; };
|
|
1653
|
+
/** Validate the raw cac-parsed bag against a {@link CliFlagsSchema}. */
|
|
1654
|
+
declare function parseCliFlags(schema: CliFlagsSchema, raw: Record<string, unknown>): {
|
|
1655
|
+
flags: Record<string, unknown>;
|
|
1656
|
+
issues?: string[];
|
|
1657
|
+
};
|
|
1658
|
+
/**
|
|
1659
|
+
* A ready-made pre-auth RPC handler, as produced by
|
|
1660
|
+
* `devframe/recipes/interactive-auth`'s `createInteractiveAuth`. Bundles
|
|
1661
|
+
* everything a host adapter needs to wire an authenticated server:
|
|
1662
|
+
* the handshake RPC functions, the resolver gate, the connect-time trust
|
|
1663
|
+
* hook, and the startup banner.
|
|
1664
|
+
*
|
|
1665
|
+
* `initDevframe` / `initHub` accept one of these directly via their `auth` option
|
|
1666
|
+
* (see {@link https://devfra.me | devframe}'s server docs), or a host can
|
|
1667
|
+
* wire the four pieces itself against a lower-level transport.
|
|
1668
|
+
*/
|
|
1669
|
+
interface DevframeAuthHandler {
|
|
2107
1670
|
/**
|
|
2108
|
-
*
|
|
2109
|
-
*
|
|
2110
|
-
*
|
|
2111
|
-
*
|
|
1671
|
+
* `anonymous:devframe:auth` + `anonymous:devframe:auth:exchange` (the
|
|
1672
|
+
* handshake), `anonymous:devframe:auth:request-code` (client-requested
|
|
1673
|
+
* banner print), and `devframe:auth:revoke` (self-revoke); register these
|
|
1674
|
+
* on the RPC host (e.g. `rpcHost.register(fn)` for each).
|
|
1675
|
+
*/
|
|
1676
|
+
rpcFunctions: RpcFunctionDefinitionAny[];
|
|
1677
|
+
/**
|
|
1678
|
+
* Resolver gate: whether `methodName` is callable given `session`'s
|
|
1679
|
+
* current trust state. Defaults to allowing any `anonymous:`-prefixed
|
|
1680
|
+
* method (see `isAnonymousRpcMethod`) plus anything once the session is
|
|
1681
|
+
* trusted.
|
|
1682
|
+
*/
|
|
1683
|
+
authorize: (methodName: string, session: DevframeNodeRpcSession) => boolean;
|
|
1684
|
+
/**
|
|
1685
|
+
* Connect-time trust: reads a bearer token off the connection's initial
|
|
1686
|
+
* request (a static/pre-shared token from `clientAuthTokens`, or a token
|
|
1687
|
+
* minted by the code exchange) and, when valid, marks the session
|
|
1688
|
+
* trusted immediately, before the client's own handshake call.
|
|
1689
|
+
*/
|
|
1690
|
+
onConnect: (connection: DevframeRpcConnection, session: DevframeNodeRpcSession) => void;
|
|
1691
|
+
/**
|
|
1692
|
+
* Print the current one-time code and its magic-link URL. An untrusted
|
|
1693
|
+
* browser client triggers this itself over
|
|
1694
|
+
* `anonymous:devframe:auth:request-code`; call it directly when the host
|
|
1695
|
+
* wants the code on screen without waiting for a client. Safe to call
|
|
1696
|
+
* repeatedly; it only prints once per code.
|
|
1697
|
+
*/
|
|
1698
|
+
printBanner: () => void;
|
|
1699
|
+
/**
|
|
1700
|
+
* Rewrite a URL the CLI is about to open in the browser (`--open`) so the
|
|
1701
|
+
* tab lands already authenticated, e.g. appending the current OTP as a
|
|
1702
|
+
* query param. Called with the fully-resolved target URL; return it
|
|
1703
|
+
* unchanged to opt out. Optional: a handler that doesn't need this (e.g.
|
|
1704
|
+
* one gated by a pre-shared bearer token instead of an interactive code)
|
|
1705
|
+
* can omit it and the URL opens as-is.
|
|
1706
|
+
*/
|
|
1707
|
+
buildOpenUrl?: (url: string) => string;
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* The MCP adapter surface, typed here so `devframe` (which probes for and
|
|
1711
|
+
* lazily loads `@devframes/agentic`) and `@devframes/agentic/mcp` (which
|
|
1712
|
+
* implements it) share one contract without a type-level dependency cycle.
|
|
1713
|
+
* None of these shapes reference the MCP SDK: the SDK is an implementation
|
|
1714
|
+
* detail of `@devframes/agentic`, freely swappable behind this surface.
|
|
1715
|
+
* The h3-bound `mountMcpHttp` shapes live in `node/agentic.ts` (exported via
|
|
1716
|
+
* `devframe/internal`) instead: `devframe/types` must stay lib-neutral, and
|
|
1717
|
+
* h3's declarations are not.
|
|
1718
|
+
*/
|
|
1719
|
+
interface CreateMcpServerOptions {
|
|
1720
|
+
/**
|
|
1721
|
+
* Transport to use. `createMcpServer` itself runs `'stdio'` (a standalone
|
|
1722
|
+
* process with its own host context); the Streamable-HTTP transport is
|
|
1723
|
+
* served route-based by the dev server instead; see `mountMcpHttp` and
|
|
1724
|
+
* the `mcp` option on `createDevServer` / `createCac`'s `--mcp` flag.
|
|
1725
|
+
*/
|
|
1726
|
+
transport?: 'stdio';
|
|
1727
|
+
/**
|
|
1728
|
+
* Expose shared-state keys as MCP resources.
|
|
1729
|
+
* - `true` (default): every key the host publishes
|
|
1730
|
+
* - `false`: none
|
|
1731
|
+
* - `(key) => boolean`: filter
|
|
1732
|
+
*/
|
|
1733
|
+
exposeSharedState?: boolean | ((key: string) => boolean);
|
|
1734
|
+
/**
|
|
1735
|
+
* Usage guidance sent as `instructions` in the MCP `initialize` (and
|
|
1736
|
+
* `server/discover`) result. Omitted or empty sends no instructions.
|
|
1737
|
+
*/
|
|
1738
|
+
instructions?: string;
|
|
1739
|
+
/**
|
|
1740
|
+
* Resource templates served through `resources/templates/list`, and read
|
|
1741
|
+
* through `resources/read`. Omitted or empty keeps the resources unchanged.
|
|
1742
|
+
*/
|
|
1743
|
+
resourceTemplates?: McpResourceTemplate[];
|
|
1744
|
+
/**
|
|
1745
|
+
* Host subscription for resource-list changes; each `notify()` sends
|
|
1746
|
+
* `notifications/resources/list_changed`. See {@link McpResourcesChangedHook}.
|
|
1747
|
+
*/
|
|
1748
|
+
onResourcesChanged?: McpResourcesChangedHook;
|
|
1749
|
+
/**
|
|
1750
|
+
* Prompt templates served through `prompts/list` and `prompts/get`.
|
|
1751
|
+
* Omitted or empty declares no `prompts` capability.
|
|
1752
|
+
*/
|
|
1753
|
+
prompts?: McpPrompt[];
|
|
1754
|
+
/** Override the name reported in the MCP handshake. */
|
|
1755
|
+
serverName?: string;
|
|
1756
|
+
/** Override the version reported in the MCP handshake. Defaults to `definition.version ?? '0.0.0'`. */
|
|
1757
|
+
serverVersion?: string;
|
|
1758
|
+
/** Called once the transport is connected. */
|
|
1759
|
+
onReady?: (info: {
|
|
1760
|
+
transport: 'stdio';
|
|
1761
|
+
}) => void;
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* One MCP content block in a tool result. Attach blocks to a tool's return
|
|
1765
|
+
* value with `withMcpContent` (from `devframe`) to send them in place of the
|
|
1766
|
+
* default JSON text block. `data` is base64.
|
|
1767
|
+
*/
|
|
1768
|
+
type McpContentBlock = {
|
|
1769
|
+
type: 'text';
|
|
1770
|
+
text: string;
|
|
1771
|
+
} | {
|
|
1772
|
+
type: 'image';
|
|
1773
|
+
data: string;
|
|
1774
|
+
mimeType: string;
|
|
1775
|
+
} | {
|
|
1776
|
+
type: 'audio';
|
|
1777
|
+
data: string;
|
|
1778
|
+
mimeType: string;
|
|
1779
|
+
};
|
|
1780
|
+
interface McpServerHandle {
|
|
1781
|
+
stop: () => Promise<void>;
|
|
1782
|
+
}
|
|
1783
|
+
interface CreateMcpFetchHandlerOptions {
|
|
1784
|
+
/** Name reported in the MCP handshake. */
|
|
1785
|
+
serverName: string;
|
|
1786
|
+
/** Version reported in the MCP handshake. */
|
|
1787
|
+
serverVersion: string;
|
|
1788
|
+
/** Expose shared-state keys as MCP resources; see {@link CreateMcpServerOptions.exposeSharedState}. */
|
|
1789
|
+
exposeSharedState: boolean | ((key: string) => boolean);
|
|
1790
|
+
/** Usage guidance for the handshake; see {@link CreateMcpServerOptions.instructions}. */
|
|
1791
|
+
instructions?: string;
|
|
1792
|
+
/** Resource templates; see {@link CreateMcpServerOptions.resourceTemplates}. */
|
|
1793
|
+
resourceTemplates?: McpResourceTemplate[];
|
|
1794
|
+
/** Host subscription for resource-list changes; see {@link CreateMcpServerOptions.onResourcesChanged}. */
|
|
1795
|
+
onResourcesChanged?: McpResourcesChangedHook;
|
|
1796
|
+
/** Prompt templates; see {@link CreateMcpServerOptions.prompts}. */
|
|
1797
|
+
prompts?: McpPrompt[];
|
|
1798
|
+
/**
|
|
1799
|
+
* Optional identity check, layered on top of the origin gate and checked
|
|
1800
|
+
* **after** it: a bearer token string (matched in constant time against
|
|
1801
|
+
* `Authorization: Bearer <token>`), a `(request) => boolean` callback, or
|
|
1802
|
+
* `false` (the default) for origin-only, trusting same-machine callers. A
|
|
1803
|
+
* callback governs identity only and cannot relax the origin gate. See
|
|
1804
|
+
* {@link McpAuthorization}.
|
|
1805
|
+
*/
|
|
1806
|
+
authorization?: McpAuthorization;
|
|
1807
|
+
/**
|
|
1808
|
+
* Origin allow-list beyond the loopback default. `false` disables the
|
|
1809
|
+
* origin gate entirely. Default: loopback-only.
|
|
2112
1810
|
*
|
|
2113
|
-
*
|
|
2114
|
-
*
|
|
2115
|
-
*
|
|
1811
|
+
* Unlike the WS transport, the MCP route does **not** allow `Origin`-less
|
|
1812
|
+
* requests: a route-based endpoint is reachable by any local process, so a
|
|
1813
|
+
* request must carry an `Origin` that passes the gate. Native clients
|
|
1814
|
+
* (e.g. `devframe connect`) send their loopback origin explicitly.
|
|
2116
1815
|
*/
|
|
2117
|
-
|
|
1816
|
+
allowedOrigins?: readonly string[] | false;
|
|
1817
|
+
}
|
|
1818
|
+
/** Connection facts a host knows about a request beyond the `Request` itself. */
|
|
1819
|
+
interface McpConnectionInfo {
|
|
1820
|
+
/**
|
|
1821
|
+
* The connecting peer's remote address (a node socket's `remoteAddress`),
|
|
1822
|
+
* used to prove a same-machine caller when the endpoint relies on the
|
|
1823
|
+
* loopback origin default with no identity check. A host that can resolve a
|
|
1824
|
+
* trustworthy peer address (the h3/node mount) supplies it; when it's
|
|
1825
|
+
* omitted the origin gate stays the only locality signal.
|
|
1826
|
+
*/
|
|
1827
|
+
remoteAddress?: string;
|
|
1828
|
+
}
|
|
1829
|
+
interface McpFetchHandler {
|
|
1830
|
+
/**
|
|
1831
|
+
* WHATWG-`fetch` handler for the MCP endpoint. Hand every method
|
|
1832
|
+
* (POST/GET/DELETE) on the endpoint's path to it; routing by path is the
|
|
1833
|
+
* host's job. Pass {@link McpConnectionInfo} when the host can resolve the
|
|
1834
|
+
* peer address so the default trust boundary can enforce same-machine
|
|
1835
|
+
* locality.
|
|
1836
|
+
*/
|
|
1837
|
+
fetch: (request: Request, connection?: McpConnectionInfo) => Promise<Response>;
|
|
1838
|
+
/** Tear down the handler (aborts in-flight exchanges, drops the change bridge). */
|
|
1839
|
+
dispose: () => Promise<void>;
|
|
1840
|
+
}
|
|
1841
|
+
/** One concrete resource that an {@link McpResourceTemplate} lists in `resources/list`. */
|
|
1842
|
+
interface McpResourceTemplateEntry {
|
|
1843
|
+
/** The resource URI. It SHOULD match the `uriTemplate` of its template, so `resources/read` finds it. */
|
|
1844
|
+
uri: string;
|
|
1845
|
+
name: string;
|
|
1846
|
+
/** Human-readable name for display. */
|
|
1847
|
+
title?: string;
|
|
1848
|
+
description?: string;
|
|
1849
|
+
/** Defaults to the `mimeType` of the template. */
|
|
1850
|
+
mimeType?: string;
|
|
2118
1851
|
}
|
|
2119
1852
|
/**
|
|
2120
|
-
*
|
|
2121
|
-
*
|
|
2122
|
-
|
|
1853
|
+
* What an {@link McpResourceTemplate} returns from `read`, sent as the
|
|
1854
|
+
* `resources/read` result: `text` as is, or else `json` as JSON text.
|
|
1855
|
+
*/
|
|
1856
|
+
interface McpResourceTemplateContent {
|
|
1857
|
+
text?: string;
|
|
1858
|
+
json?: unknown;
|
|
1859
|
+
/** Defaults to the `mimeType` of the template, then `application/json`. */
|
|
1860
|
+
mimeType?: string;
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* A resource template the MCP server lists in `resources/templates/list` and
|
|
1864
|
+
* reads in `resources/read`. The `uriTemplate` uses RFC 6570 level 1 only:
|
|
1865
|
+
* plain `{name}` expressions, with text between any two of them. Each
|
|
1866
|
+
* expression matches a non-empty value with no `/`, and its value is
|
|
1867
|
+
* percent-decoded.
|
|
2123
1868
|
*
|
|
2124
|
-
*
|
|
1869
|
+
* `list` and `read` get the node context of the devframe (or of the hub), so
|
|
1870
|
+
* they can read live state such as `ctx.rpc.sharedState` or `ctx.agent`. The
|
|
1871
|
+
* route options are resolved before `setup()` runs, so a template cannot
|
|
1872
|
+
* capture that context in a closure.
|
|
2125
1873
|
*/
|
|
2126
|
-
interface
|
|
2127
|
-
/**
|
|
2128
|
-
|
|
1874
|
+
interface McpResourceTemplate {
|
|
1875
|
+
/** RFC 6570 level 1 URI template, e.g. `my-tool://file/{path}`. Anything else throws `DF0084`. */
|
|
1876
|
+
uriTemplate: string;
|
|
1877
|
+
name: string;
|
|
1878
|
+
/** Human-readable name for display. */
|
|
1879
|
+
title?: string;
|
|
1880
|
+
description?: string;
|
|
1881
|
+
/** MIME type of every resource the template stands for. */
|
|
1882
|
+
mimeType?: string;
|
|
1883
|
+
/** The concrete resources the template stands for right now. They are added to `resources/list`. */
|
|
1884
|
+
list?: (ctx: DevframeNodeContext) => McpResourceTemplateEntry[] | Promise<McpResourceTemplateEntry[]>;
|
|
1885
|
+
/** Read one resource: `params` holds the decoded value of each `{name}`, `uri` the requested URI. */
|
|
1886
|
+
read: (params: Record<string, string>, uri: string, ctx: DevframeNodeContext) => McpResourceTemplateContent | Promise<McpResourceTemplateContent>;
|
|
1887
|
+
}
|
|
1888
|
+
/**
|
|
1889
|
+
* A host subscription for resource-list changes. Call `notify()` each time
|
|
1890
|
+
* the resources change; the MCP server then sends
|
|
1891
|
+
* `notifications/resources/list_changed`. Return a function that removes the
|
|
1892
|
+
* subscription; the MCP server calls it on teardown.
|
|
1893
|
+
*/
|
|
1894
|
+
type McpResourcesChangedHook = (notify: () => void, ctx: DevframeNodeContext) => () => void;
|
|
1895
|
+
/** One argument of an {@link McpPrompt}. */
|
|
1896
|
+
interface McpPromptArgument {
|
|
1897
|
+
name: string;
|
|
1898
|
+
description?: string;
|
|
1899
|
+
/** `prompts/get` answers invalid params when a required argument is missing or empty. */
|
|
1900
|
+
required?: boolean;
|
|
1901
|
+
}
|
|
1902
|
+
/** One message of the answer to `prompts/get`. */
|
|
1903
|
+
interface McpPromptMessage {
|
|
1904
|
+
role: 'user' | 'assistant';
|
|
1905
|
+
content: {
|
|
1906
|
+
type: 'text';
|
|
1907
|
+
text: string;
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
/** What an {@link McpPrompt} returns from `get`, sent as the `prompts/get` result. */
|
|
1911
|
+
interface McpPromptResult {
|
|
1912
|
+
description?: string;
|
|
1913
|
+
messages: McpPromptMessage[];
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* A prompt template the MCP server lists in `prompts/list` and builds in
|
|
1917
|
+
* `prompts/get`. A coding agent usually offers it to the user as a slash
|
|
1918
|
+
* command. Each `name` is used once; a repeated name throws `DF0085`.
|
|
1919
|
+
*/
|
|
1920
|
+
interface McpPrompt {
|
|
1921
|
+
name: string;
|
|
1922
|
+
/** Human-readable name for display. */
|
|
1923
|
+
title?: string;
|
|
1924
|
+
description?: string;
|
|
1925
|
+
arguments?: McpPromptArgument[];
|
|
1926
|
+
/** Build the messages from the arguments the coding agent sent. */
|
|
1927
|
+
get: (args: Record<string, string>) => McpPromptResult | Promise<McpPromptResult>;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Classification of how a devframe is being deployed. Hosted adapters
|
|
1931
|
+
* (`vite`, `embedded`) share their origin with a host app and must
|
|
1932
|
+
* namespace their mount path under `/__<id>/`. Standalone adapters
|
|
1933
|
+
* (`cli`, `build`) own the origin and default to `/`.
|
|
1934
|
+
*/
|
|
1935
|
+
type DevframeDeploymentKind = 'standalone' | 'hosted';
|
|
1936
|
+
/**
|
|
1937
|
+
* How a hub deduplicates devframes that share an `id` when more than one
|
|
1938
|
+
* is mounted onto the same hub. See {@link DevframeDefinition.duplicationStrategy}.
|
|
1939
|
+
*
|
|
1940
|
+
* - `'warn'` (default): keep the first registration, drop later
|
|
1941
|
+
* duplicates, and emit a warning diagnostic (`DF8105`).
|
|
1942
|
+
* - `'silent'`: drop later duplicates without warning.
|
|
1943
|
+
* - `'throw'`: throw when a duplicate is mounted.
|
|
1944
|
+
* - `'duplicate'`: let every instance coexist under a disambiguated
|
|
1945
|
+
* dock id.
|
|
1946
|
+
*/
|
|
1947
|
+
type DevframeDuplicationStrategy = 'warn' | 'silent' | 'throw' | 'duplicate';
|
|
1948
|
+
/**
|
|
1949
|
+
* Controls where the browser opens the RPC WebSocket, advertised in
|
|
1950
|
+
* `__connection.json` and used to bind the dev server. The three shapes map
|
|
1951
|
+
* to the three connection scenarios; precedence is `url` > `port` > `route`:
|
|
1952
|
+
*
|
|
1953
|
+
* 1. **Same server, different route** (default): leave `port`/`url` unset.
|
|
1954
|
+
* The socket shares the HTTP server's port and binds to `route`
|
|
1955
|
+
* (`__ws`). The client connects to its own origin, so the link
|
|
1956
|
+
* survives a reverse proxy that rewrites the host/port/subpath.
|
|
1957
|
+
*
|
|
1958
|
+
* 2. **Different port**: set `port`. The socket binds on its own port on the
|
|
1959
|
+
* same host; the client targets `ws(s)://<page-host>:<port>/<route>`.
|
|
1960
|
+
*
|
|
1961
|
+
* 3. **Remote, different origin**: set `url` to a full `ws://`/`wss://`
|
|
1962
|
+
* endpoint (e.g. a public tunnel or relay). The client uses it verbatim.
|
|
1963
|
+
*/
|
|
1964
|
+
interface DevframeWsOptions {
|
|
2129
1965
|
/**
|
|
2130
|
-
*
|
|
2131
|
-
*
|
|
2132
|
-
* `pipeTo` consumption. The sink's `signal` aborts when every subscriber
|
|
2133
|
-
* disconnects or cancels.
|
|
1966
|
+
* Upgrade route segment the socket binds to and is advertised at, relative
|
|
1967
|
+
* to the SPA base. Default: `__ws`.
|
|
2134
1968
|
*/
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
1969
|
+
route?: string;
|
|
1970
|
+
/**
|
|
1971
|
+
* Bind the socket on its own port instead of sharing the HTTP port. The
|
|
1972
|
+
* browser connects to this port on the page's hostname. Implies
|
|
1973
|
+
* {@link DevframeWsOptions.sidecar}.
|
|
1974
|
+
*/
|
|
1975
|
+
port?: number;
|
|
1976
|
+
/**
|
|
1977
|
+
* Start a side-car WebSocket server on a free port, for hosts whose request
|
|
1978
|
+
* handlers can't accept upgrades (Next.js route handlers, Nitro, Rsbuild).
|
|
1979
|
+
* The resolved port is advertised in `__connection.json`, so the browser
|
|
1980
|
+
* finds it without any further wiring. Set `port` instead to pin it.
|
|
1981
|
+
*/
|
|
1982
|
+
sidecar?: boolean;
|
|
1983
|
+
/**
|
|
1984
|
+
* Advertise a fixed, fully-qualified endpoint on another origin (a full
|
|
1985
|
+
* `ws://`/`wss://` URL). Takes precedence over `port`/`route` in the meta.
|
|
1986
|
+
*/
|
|
1987
|
+
url?: string;
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Controls the SSE RPC endpoint, the WebSocket-free transport for hosts
|
|
1991
|
+
* and proxies where the upgrade isn't available. It rides whatever HTTP
|
|
1992
|
+
* surface serves the instance (the same one serving `__connection.json`),
|
|
1993
|
+
* so a relative `route` always resolves; there is no port plumbing of its
|
|
1994
|
+
* own. Enabled by default alongside the WebSocket; pass `sse: false` to
|
|
1995
|
+
* disable, or `ws: false` to run SSE-only (`backend: 'sse'`).
|
|
1996
|
+
*/
|
|
1997
|
+
interface DevframeSseOptions {
|
|
1998
|
+
/**
|
|
1999
|
+
* Route segment the SSE endpoint binds to and is advertised at, relative
|
|
2000
|
+
* to the SPA base. Default: `__sse`.
|
|
2001
|
+
*/
|
|
2002
|
+
route?: string;
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* An **optional** identity check layered on top of the origin gate. The
|
|
2006
|
+
* route-based MCP endpoint trusts same-machine callers by default (the
|
|
2007
|
+
* loopback origin gate is enough), so this is opt-in hardening for the cases
|
|
2008
|
+
* where a same-machine process is not a trust boundary, like a LAN/tunnel
|
|
2009
|
+
* origin, a shared/CI box, or a destructive tool surface:
|
|
2010
|
+
*
|
|
2011
|
+
* - a non-empty **bearer token string**: the request must carry
|
|
2012
|
+
* `Authorization: Bearer <token>`, compared in constant time. Back it with
|
|
2013
|
+
* an environment variable rather than a literal;
|
|
2014
|
+
* - a **callback** `(request) => boolean | Promise<boolean>`: a custom
|
|
2015
|
+
* identity check (validate a signed header, an mTLS-derived claim, …). It
|
|
2016
|
+
* only governs identity and cannot relax the origin gate;
|
|
2017
|
+
* - `false`, the default: **origin-only**, trusting same-machine callers.
|
|
2018
|
+
*/
|
|
2019
|
+
type McpAuthorization = string | ((request: Request) => boolean | Promise<boolean>) | false;
|
|
2020
|
+
/**
|
|
2021
|
+
* The route-based MCP setting accepted everywhere a host mounts a devframe
|
|
2022
|
+
* (`initDevframe` / `initHub` / `createDevServer` options, `createCac` /
|
|
2023
|
+
* `--mcp`, the framework kits):
|
|
2024
|
+
*
|
|
2025
|
+
* - `'auto'`, the default: mount the route when the devframe exposes an
|
|
2026
|
+
* agent surface (an `agent`-flagged RPC function, or a tool / resource /
|
|
2027
|
+
* provider registered on `ctx.agent`) AND the optional `@devframes/agentic`
|
|
2028
|
+
* peer (the MCP adapter and SDK) is installed. An empty agent surface
|
|
2029
|
+
* mounts nothing and loads no MCP code; a non-empty one without the peer
|
|
2030
|
+
* warns once (DF0078) and mounts nothing.
|
|
2031
|
+
* - `true`: always mount at the default `__mcp` route; a missing
|
|
2032
|
+
* `@devframes/agentic` throws DF0079.
|
|
2033
|
+
* - `false`: never mount, and never probe or warn.
|
|
2034
|
+
* - {@link McpRouteOptions}: always mount (like `true`), with a custom route
|
|
2035
|
+
* path, origin allow-list, or {@link McpAuthorization} identity check.
|
|
2036
|
+
*
|
|
2037
|
+
* A mounted route trusts same-machine callers by default (the loopback
|
|
2038
|
+
* origin gate), exactly like `mcp: true`.
|
|
2039
|
+
*/
|
|
2040
|
+
type McpSetting = boolean | 'auto' | McpRouteOptions;
|
|
2041
|
+
/**
|
|
2042
|
+
* Configuration for the route-based MCP server mounted alongside the dev
|
|
2043
|
+
* server (via {@link DevframeCliOptions.mcp}). The endpoint speaks
|
|
2044
|
+
* the MCP Streamable-HTTP transport over the same origin as the SPA,
|
|
2045
|
+
* exposing the definition's `ctx.agent` tools + shared-state resources to
|
|
2046
|
+
* external MCP clients connected to the *running* server.
|
|
2047
|
+
*/
|
|
2048
|
+
interface McpRouteOptions {
|
|
2049
|
+
/**
|
|
2050
|
+
* Route segment the MCP endpoint binds to, relative to the SPA base.
|
|
2051
|
+
* Default: `__mcp` (i.e. `/__mcp` standalone, `/__<id>/__mcp` hosted).
|
|
2052
|
+
*/
|
|
2053
|
+
path?: string;
|
|
2054
|
+
/**
|
|
2055
|
+
* Optional identity check, layered on top of the origin gate and checked
|
|
2056
|
+
* **after** it. Defaults to origin-only (`false`): the route trusts
|
|
2057
|
+
* same-machine callers, since the loopback origin gate already keeps
|
|
2058
|
+
* arbitrary remote/browser callers out. Set a bearer token or a callback to
|
|
2059
|
+
* harden the route when a same-machine process is not your trust boundary
|
|
2060
|
+
* (LAN/tunnel origin, shared/CI host, destructive tools). See
|
|
2061
|
+
* {@link McpAuthorization}.
|
|
2062
|
+
*/
|
|
2063
|
+
authorization?: McpAuthorization;
|
|
2064
|
+
/**
|
|
2065
|
+
* Extra `Origin` header values to accept beyond the loopback default
|
|
2066
|
+
* (`localhost`/`127.0.0.1`/`::1` and any `Origin`-less native client).
|
|
2067
|
+
* Add your LAN/tunnel origin here when reaching the endpoint from another
|
|
2068
|
+
* host, mirroring the WS transport's origin gate. Pass `false` to disable
|
|
2069
|
+
* origin checking entirely (not recommended). Default: loopback-only.
|
|
2070
|
+
*
|
|
2071
|
+
* This is the endpoint's DNS-rebinding protection: the shared
|
|
2072
|
+
* `isAllowedOrigin` gate the WS upgrade already uses, applied as external
|
|
2073
|
+
* middleware (the approach the MCP SDK now recommends over its own
|
|
2074
|
+
* deprecated `allowedHosts`/`allowedOrigins` transport flags). When you
|
|
2075
|
+
* widen it past loopback, layer on {@link McpRouteOptions.authorization} to
|
|
2076
|
+
* prove identity too.
|
|
2077
|
+
*/
|
|
2078
|
+
allowedOrigins?: readonly string[] | false;
|
|
2079
|
+
/**
|
|
2080
|
+
* Which shared-state keys the route exposes to agents, through the built-in
|
|
2081
|
+
* `devframe_state_read` tool and the `devframe://state/<key>` resources.
|
|
2082
|
+
* - `true` (default): every key the host publishes
|
|
2083
|
+
* - `false`: none
|
|
2084
|
+
* - `(key) => boolean`: only the keys the filter accepts
|
|
2085
|
+
*
|
|
2086
|
+
* The states themselves stay available to the UI over RPC.
|
|
2087
|
+
*/
|
|
2088
|
+
exposeSharedState?: boolean | ((key: string) => boolean);
|
|
2089
|
+
/**
|
|
2090
|
+
* Usage guidance for the route, sent as `instructions` in the MCP
|
|
2091
|
+
* `initialize` (and `server/discover`) result. An MCP client can add it to
|
|
2092
|
+
* the coding agent's context, for example to say which tool to call first.
|
|
2093
|
+
* Omitted or empty sends no instructions.
|
|
2094
|
+
*/
|
|
2095
|
+
instructions?: string;
|
|
2096
|
+
/**
|
|
2097
|
+
* Resource templates the route serves through MCP
|
|
2098
|
+
* `resources/templates/list`. `resources/read` tries them after the
|
|
2099
|
+
* registered resources and the shared-state resources (a
|
|
2100
|
+
* `devframe://resource/` or `devframe://state/` URI never reaches them);
|
|
2101
|
+
* the first template whose `uriTemplate` matches the URI reads it. `resources/list` adds the
|
|
2102
|
+
* entries each template's `list` returns. Omitted or empty keeps the
|
|
2103
|
+
* resources unchanged.
|
|
2104
|
+
*/
|
|
2105
|
+
resourceTemplates?: McpResourceTemplate[];
|
|
2138
2106
|
/**
|
|
2139
|
-
*
|
|
2140
|
-
*
|
|
2141
|
-
*
|
|
2142
|
-
*
|
|
2143
|
-
* before passing it here.
|
|
2107
|
+
* Host subscription for resource-list changes. Call `notify()` each time
|
|
2108
|
+
* the resources change (for example, the entries of a resource template);
|
|
2109
|
+
* the route then sends `notifications/resources/list_changed`. Return a
|
|
2110
|
+
* function that removes the subscription; the route calls it on teardown.
|
|
2144
2111
|
*/
|
|
2145
|
-
|
|
2146
|
-
id?: string;
|
|
2147
|
-
}) => Promise<StreamSink<T>>;
|
|
2148
|
-
/** Look up an active stream by id. Returns `undefined` if none. */
|
|
2149
|
-
get: (id: string) => StreamSink<T> | undefined;
|
|
2150
|
-
/** All active outbound stream ids on this channel. */
|
|
2151
|
-
ids: () => string[];
|
|
2112
|
+
onResourcesChanged?: McpResourcesChangedHook;
|
|
2152
2113
|
/**
|
|
2153
|
-
*
|
|
2154
|
-
*
|
|
2155
|
-
* the client writes chunks. Typical pattern is to call this from an
|
|
2156
|
-
* action handler, kick off background processing, and return the id
|
|
2157
|
-
* so the caller can start uploading:
|
|
2158
|
-
*
|
|
2159
|
-
* ```ts
|
|
2160
|
-
* handler: async () => {
|
|
2161
|
-
* const reader = channel.openInbound()
|
|
2162
|
-
* ;(async () => {
|
|
2163
|
-
* for await (const chunk of reader) processChunk(chunk)
|
|
2164
|
-
* })()
|
|
2165
|
-
* return { uploadId: reader.id }
|
|
2166
|
-
* }
|
|
2167
|
-
* ```
|
|
2168
|
-
*
|
|
2169
|
-
* Calling `reader.cancel()` on the server sends an `upload-cancel` to
|
|
2170
|
-
* the uploading client, which aborts its sink.
|
|
2114
|
+
* Prompt templates the route serves through MCP `prompts/list` and
|
|
2115
|
+
* `prompts/get`. Omitted or empty declares no `prompts` capability.
|
|
2171
2116
|
*/
|
|
2172
|
-
|
|
2173
|
-
id?: string;
|
|
2174
|
-
}) => StreamReader<T>;
|
|
2117
|
+
prompts?: McpPrompt[];
|
|
2175
2118
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2119
|
+
interface DevframeCliOptions {
|
|
2120
|
+
/** Binary name; default: the devframe's `id`. */
|
|
2121
|
+
command?: string;
|
|
2122
|
+
/** Preferred port for the dev server (default 9999). */
|
|
2123
|
+
port?: number;
|
|
2124
|
+
/** Port scan range, forwarded to `get-port-please`. */
|
|
2125
|
+
portRange?: [number, number];
|
|
2126
|
+
/** Prefer a random open port. */
|
|
2127
|
+
random?: boolean;
|
|
2128
|
+
/** Default host to bind to; `--host` overrides. */
|
|
2129
|
+
host?: string;
|
|
2182
2130
|
/**
|
|
2183
|
-
*
|
|
2184
|
-
*
|
|
2185
|
-
*
|
|
2131
|
+
* Auto-open the browser when the dev server starts.
|
|
2132
|
+
* `true` opens the resolved origin; a string opens that relative path.
|
|
2133
|
+
* The `--open` / `--no-open` flags override this.
|
|
2186
2134
|
*/
|
|
2187
|
-
|
|
2135
|
+
open?: boolean | string;
|
|
2188
2136
|
/**
|
|
2189
|
-
*
|
|
2190
|
-
* subscribers and abort orphaned streams. Most users do not need this;
|
|
2191
|
-
* it's wired by the RPC server binding automatically.
|
|
2137
|
+
* Authentication for the standalone dev server.
|
|
2192
2138
|
*
|
|
2193
|
-
*
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
* agent + the view-host (HTTP file-serving). Host adapters can wrap this
|
|
2206
|
-
* to add their own surfaces; for example, `@vitejs/devtools-kit`'s
|
|
2207
|
-
* `createKitContext` adds `docks`, `terminals`, `messages`, and
|
|
2208
|
-
* `commands` when mounted into Vite DevTools. JSON rendering is an opt-in
|
|
2209
|
-
* integration (`@devframes/json-render`) layered on top, not part of this
|
|
2210
|
-
* core surface.
|
|
2211
|
-
*/
|
|
2212
|
-
interface DevframeNodeContext {
|
|
2213
|
-
readonly workspaceRoot: string;
|
|
2214
|
-
readonly cwd: string;
|
|
2215
|
-
/**
|
|
2216
|
-
* Lifecycle distinction surfaced to plugin authors:
|
|
2139
|
+
* - `undefined` / `true`: the standalone adapters (`cli` /
|
|
2140
|
+
* served `build`) auto-wire devframe's interactive OTP auth
|
|
2141
|
+
* (`createInteractiveAuth`): an untrusted client can only reach
|
|
2142
|
+
* `anonymous:` methods until it exchanges the printed one-time code.
|
|
2143
|
+
* The adapter prints the code + magic-link banner once the server is
|
|
2144
|
+
* listening.
|
|
2145
|
+
* - `false`: no gate, for trusted single-user localhost tools where an
|
|
2146
|
+
* auth round-trip only gets in the way (the built-in plugins set this).
|
|
2147
|
+
* The `--no-auth` CLI flag maps here for one-off runs.
|
|
2148
|
+
* - A {@link DevframeAuthHandler}: a custom handler (e.g. a tuned
|
|
2149
|
+
* `createInteractiveAuth`, or an entirely different scheme) passed
|
|
2150
|
+
* straight through to the RPC transport binding.
|
|
2217
2151
|
*
|
|
2218
|
-
*
|
|
2219
|
-
*
|
|
2220
|
-
* to keep the UI responsive.
|
|
2221
|
-
* - `'build'`: one-shot batch run. The context is set up, the devtool
|
|
2222
|
-
* collects what it needs, and a snapshot is written. No
|
|
2223
|
-
* live UI, no WS server.
|
|
2152
|
+
* Hosted adapters (`vite`, `embedded`) ignore this and defer to the host's
|
|
2153
|
+
* auth; `@vitejs/devtools` honors the equivalent `devtools.clientAuth`.
|
|
2224
2154
|
*
|
|
2225
|
-
*
|
|
2226
|
-
* is general: the same distinction applies to any tool that runs in
|
|
2227
|
-
* either an interactive or a static-output mode.
|
|
2228
|
-
*/
|
|
2229
|
-
readonly mode: 'dev' | 'build';
|
|
2230
|
-
/**
|
|
2231
|
-
* Host runtime abstraction, exposing `mountStatic` / `resolveOrigin` /
|
|
2232
|
-
* `getStorageDir`.
|
|
2155
|
+
* @default true
|
|
2233
2156
|
*/
|
|
2234
|
-
|
|
2235
|
-
rpc: RpcFunctionsHost;
|
|
2236
|
-
views: DevframeViewHost;
|
|
2157
|
+
auth?: boolean | DevframeAuthHandler;
|
|
2237
2158
|
/**
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2159
|
+
* How the browser reaches the RPC WebSocket. Defaults to sharing the HTTP
|
|
2160
|
+
* port on the `__ws` route. See {@link DevframeWsOptions} for the
|
|
2161
|
+
* different-port and remote-origin variants. Pass `false` to serve no
|
|
2162
|
+
* WebSocket at all; clients connect over SSE instead (`backend: 'sse'`).
|
|
2240
2163
|
*/
|
|
2241
|
-
|
|
2164
|
+
ws?: DevframeWsOptions | false;
|
|
2242
2165
|
/**
|
|
2243
|
-
*
|
|
2166
|
+
* How the browser reaches the SSE RPC endpoint, enabled by default
|
|
2167
|
+
* alongside the WebSocket as the more portable transport. Pass `false`
|
|
2168
|
+
* to disable, or a {@link DevframeSseOptions} to change its route.
|
|
2244
2169
|
*/
|
|
2245
|
-
|
|
2170
|
+
sse?: boolean | DevframeSseOptions;
|
|
2246
2171
|
/**
|
|
2247
|
-
*
|
|
2248
|
-
*
|
|
2249
|
-
*
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2252
|
-
* absorb setup-order differences between provider and consumer.
|
|
2172
|
+
* Capability-side CAC hook. Called with the CAC instance after the
|
|
2173
|
+
* adapter registers its built-in commands (`build` / `mcp`)
|
|
2174
|
+
* but before `createCac`'s own `configureCli` caller. Use this to
|
|
2175
|
+
* contribute tool-specific flags and subcommands from the definition
|
|
2176
|
+
* itself.
|
|
2253
2177
|
*/
|
|
2254
|
-
|
|
2178
|
+
configure?: (cli: CAC) => void;
|
|
2255
2179
|
/**
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2261
|
-
*
|
|
2180
|
+
* Typed CLI flags for the default `dev` command, backed by any
|
|
2181
|
+
* [Standard Schema](https://standardschema.dev/) validator (valibot,
|
|
2182
|
+
* zod, arktype, or devframe's built-in `s`). The adapter registers
|
|
2183
|
+
* matching `--kebab-key` options on CAC, validates the parsed values,
|
|
2184
|
+
* and forwards the typed bag to `setup(ctx, { flags })`.
|
|
2185
|
+
*
|
|
2186
|
+
* Use {@link defineCliFlags} to preserve the literal schema-map
|
|
2187
|
+
* shape, and {@link InferCliFlags} to recover the typed output at the
|
|
2188
|
+
* call site:
|
|
2262
2189
|
*
|
|
2263
2190
|
* ```ts
|
|
2264
|
-
*
|
|
2265
|
-
*
|
|
2266
|
-
*
|
|
2267
|
-
* }
|
|
2268
|
-
* ```
|
|
2269
|
-
*/
|
|
2270
|
-
staticConfig: Partial<DevframeConnectionConfigsRegistry>;
|
|
2271
|
-
/**
|
|
2272
|
-
* Create a namespace-scoped view of this context. The returned
|
|
2273
|
-
* `ctx.scope('my-plugin')` auto-namespaces every RPC id, shared-state
|
|
2274
|
-
* key, and streaming channel with `my-plugin:`, and exposes a typed
|
|
2275
|
-
* top-level `settings` store. This is the preferred way to consume the
|
|
2276
|
-
* context from a single tool's setup code.
|
|
2191
|
+
* const appFlags = defineCliFlags({
|
|
2192
|
+
* depth: v.pipe(v.number(), v.integer()),
|
|
2193
|
+
* config: v.optional(v.string()),
|
|
2194
|
+
* })
|
|
2277
2195
|
*
|
|
2278
|
-
*
|
|
2196
|
+
* defineDevframe({
|
|
2197
|
+
* cli: { flags: appFlags },
|
|
2198
|
+
* setup(ctx, info) {
|
|
2199
|
+
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
2200
|
+
* },
|
|
2201
|
+
* })
|
|
2202
|
+
* ```
|
|
2279
2203
|
*/
|
|
2280
|
-
|
|
2281
|
-
<NS extends string>(namespace: NS): DevframeScopedNodeContext<NS, SettingsForNamespace<NS>>;
|
|
2282
|
-
(namespace?: null | ''): DevframeNodeContext;
|
|
2283
|
-
};
|
|
2204
|
+
flags?: CliFlagsSchema;
|
|
2284
2205
|
}
|
|
2285
2206
|
/**
|
|
2286
|
-
*
|
|
2287
|
-
*
|
|
2288
|
-
*
|
|
2289
|
-
*
|
|
2290
|
-
* applied). This survives reverse proxies that change the host/port, because
|
|
2291
|
-
* the client never trusts a server-baked hostname; it reuses its own.
|
|
2207
|
+
* Default dock attributes for the iframe entry a hub synthesizes when it
|
|
2208
|
+
* mounts this devframe. Framework-neutral metadata only; the hub layer
|
|
2209
|
+
* (`ctx.install`) merges these beneath its per-mount `dock` overrides,
|
|
2210
|
+
* which in turn sit beneath the locked, derived `id` / `type` / `url`.
|
|
2292
2211
|
*
|
|
2293
|
-
*
|
|
2294
|
-
*
|
|
2212
|
+
* Every field is optional. `title` / `icon` default to the definition's
|
|
2213
|
+
* `name` / `icon` when omitted here; the rest are unset by default.
|
|
2214
|
+
* Standalone adapters (`cli` / `build`) ignore this entirely.
|
|
2295
2215
|
*/
|
|
2296
|
-
interface
|
|
2216
|
+
interface DevframeDockDefaults {
|
|
2217
|
+
/** Dock entry title. Defaults to the definition's `name`. */
|
|
2218
|
+
title?: string;
|
|
2219
|
+
/** Translations of `title` by BCP 47 tag; see `@devframes/hub`'s `resolveTitle()`. */
|
|
2220
|
+
titleLocales?: Record<string, string>;
|
|
2221
|
+
/** Dock entry icon. Defaults to the definition's `icon`. */
|
|
2222
|
+
icon?: string | {
|
|
2223
|
+
light: string;
|
|
2224
|
+
dark: string;
|
|
2225
|
+
};
|
|
2297
2226
|
/**
|
|
2298
|
-
*
|
|
2299
|
-
*
|
|
2300
|
-
|
|
2227
|
+
* Sort weight within the dock; higher sorts earlier.
|
|
2228
|
+
* @default 0
|
|
2229
|
+
*/
|
|
2230
|
+
defaultOrder?: number;
|
|
2231
|
+
/**
|
|
2232
|
+
* Category the entry groups under in the dock.
|
|
2233
|
+
* @default 'default'
|
|
2234
|
+
*/
|
|
2235
|
+
category?: string;
|
|
2236
|
+
/**
|
|
2237
|
+
* Conditional-visibility expression (same syntax as command `when`
|
|
2238
|
+
* clauses). Set to `'false'` to hide the entry unconditionally.
|
|
2239
|
+
*/
|
|
2240
|
+
when?: string;
|
|
2241
|
+
/**
|
|
2242
|
+
* Render-only visibility expression, same syntax as {@link when}. Hides the
|
|
2243
|
+
* entry's own dock-bar button when it evaluates to `false` while leaving it
|
|
2244
|
+
* registered and reachable (activation, RPC lookups, etc.), unlike `when`,
|
|
2245
|
+
* which is the general relevance switch for the entry as a whole.
|
|
2246
|
+
*/
|
|
2247
|
+
visibility?: string;
|
|
2248
|
+
/** Badge text rendered on the dock icon (e.g. an unread count). */
|
|
2249
|
+
badge?: string;
|
|
2250
|
+
/** Id of the dock group this entry collapses under, if any. */
|
|
2251
|
+
groupId?: string;
|
|
2252
|
+
/**
|
|
2253
|
+
* A client script the hub imports into the host page (this devframe's **page
|
|
2254
|
+
* script**). An absolute-path `importFrom` is served by the hub under the
|
|
2255
|
+
* mount base and rewritten to that URL, so mounting by package name needs no
|
|
2256
|
+
* host wiring; a URL or bare specifier passes through untouched.
|
|
2301
2257
|
*/
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2258
|
+
clientScript?: {
|
|
2259
|
+
/**
|
|
2260
|
+
* Initialize after RPC trust without waiting for dock activation.
|
|
2261
|
+
* @default false
|
|
2262
|
+
*/
|
|
2263
|
+
eager?: boolean;
|
|
2264
|
+
/** An absolute filesystem path, a served URL, or a bare npm specifier. */
|
|
2265
|
+
importFrom: string;
|
|
2266
|
+
/**
|
|
2267
|
+
* The name to import the module as.
|
|
2268
|
+
* @default 'default'
|
|
2269
|
+
*/
|
|
2270
|
+
importName?: string;
|
|
2271
|
+
};
|
|
2307
2272
|
}
|
|
2308
2273
|
/**
|
|
2309
|
-
*
|
|
2310
|
-
*
|
|
2311
|
-
* `
|
|
2312
|
-
* `host`) only when the SSE endpoint genuinely lives on a different origin
|
|
2313
|
-
* than the page, e.g. a side-car server on its own port.
|
|
2274
|
+
* Runtime information threaded into `setup(ctx, info)`. Adapters
|
|
2275
|
+
* populate the fields that make sense for their deployment. In
|
|
2276
|
+
* particular, `createCac` fills `flags` with the parsed CAC bag.
|
|
2314
2277
|
*/
|
|
2315
|
-
interface
|
|
2316
|
-
/**
|
|
2317
|
-
|
|
2318
|
-
* are resolved against `__connection.json`'s location; absolute paths
|
|
2319
|
-
* (`/__sse`) resolve against the page origin.
|
|
2320
|
-
*/
|
|
2321
|
-
path?: string;
|
|
2322
|
-
/** Override the port. Combined with the page hostname unless `host` is set. */
|
|
2323
|
-
port?: number;
|
|
2324
|
-
/** Override the host (`hostname[:port]`). Use for a fully cross-origin endpoint. */
|
|
2325
|
-
host?: string;
|
|
2278
|
+
interface DevframeSetupInfo {
|
|
2279
|
+
/** Parsed CLI flags, populated by the CLI adapter. */
|
|
2280
|
+
flags?: Record<string, unknown>;
|
|
2326
2281
|
}
|
|
2327
|
-
interface
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2282
|
+
interface DevframeDefinition {
|
|
2283
|
+
id: string;
|
|
2284
|
+
name: string;
|
|
2285
|
+
/** Semver of the tool, surfaced in hub UIs and diagnostics. */
|
|
2286
|
+
version: string;
|
|
2287
|
+
/** npm package name the devframe ships in (e.g. `@scope/my-tool`). */
|
|
2288
|
+
packageName: string;
|
|
2334
2289
|
/**
|
|
2335
|
-
*
|
|
2290
|
+
* `import.meta.url` of the module that defines this devframe. **Always
|
|
2291
|
+
* provide it** (`importMetaUrl: import.meta.url`): it is the resolution base
|
|
2292
|
+
* for the tool's own dependency graph, which lets the host resolve
|
|
2293
|
+
* everything against the plugin's own installed packages rather than the
|
|
2294
|
+
* consuming app's.
|
|
2336
2295
|
*
|
|
2337
|
-
*
|
|
2338
|
-
*
|
|
2339
|
-
*
|
|
2340
|
-
*
|
|
2341
|
-
*
|
|
2296
|
+
* - **Remote assets**: becomes the default `resolveFrom` for any remote
|
|
2297
|
+
* {@link StaticAssetsSource} the devframe hosts (its `clientAssets`, and
|
|
2298
|
+
* every `ctx.views.hostStatic` call) that doesn't set one explicitly, so a
|
|
2299
|
+
* locally installed copy of the assets package is served with zero
|
|
2300
|
+
* network. A per-asset `resolveFrom` still wins, and an explicit
|
|
2301
|
+
* `resolveFrom: null` still opts out.
|
|
2302
|
+
* - **Service dependencies**: becomes the base the host resolves declared
|
|
2303
|
+
* {@link DevframeServiceInput | services} from, so a plugin can ship a
|
|
2304
|
+
* service package as its own dependency instead of asking users to install
|
|
2305
|
+
* it.
|
|
2306
|
+
*
|
|
2307
|
+
* Optional for backward compatibility; omitting it falls back to
|
|
2308
|
+
* runtime-directory resolution and disables the zero-network installed-copy
|
|
2309
|
+
* fast paths above.
|
|
2342
2310
|
*/
|
|
2343
|
-
|
|
2311
|
+
importMetaUrl?: string;
|
|
2312
|
+
/** Project homepage or documentation URL. */
|
|
2313
|
+
homepage: string;
|
|
2314
|
+
/** One-line summary of what the tool does. */
|
|
2315
|
+
description: string;
|
|
2316
|
+
icon?: string | {
|
|
2317
|
+
light: string;
|
|
2318
|
+
dark: string;
|
|
2319
|
+
};
|
|
2344
2320
|
/**
|
|
2345
|
-
*
|
|
2346
|
-
*
|
|
2347
|
-
*
|
|
2321
|
+
* Default dock attributes applied when a hub mounts this devframe as an
|
|
2322
|
+
* iframe dock entry. Consulted only by the hub install path (`ctx.install`),
|
|
2323
|
+
* which merge these beneath the per-mount `dock` overrides; standalone
|
|
2324
|
+
* adapters (`cli` / `build`) ignore it.
|
|
2348
2325
|
*
|
|
2349
|
-
*
|
|
2350
|
-
* same-origin path relative to `__connection.json`.
|
|
2351
|
-
* - `string`: a full `http(s)://` URL used verbatim, or a path
|
|
2352
|
-
* resolved same-origin.
|
|
2326
|
+
* @see {@link DevframeDockDefaults}
|
|
2353
2327
|
*/
|
|
2354
|
-
|
|
2328
|
+
dock?: DevframeDockDefaults;
|
|
2355
2329
|
/**
|
|
2356
|
-
*
|
|
2357
|
-
* (
|
|
2358
|
-
*
|
|
2359
|
-
* path. `path` is relative to `__connection.json`'s location, like the
|
|
2360
|
-
* WebSocket `path`. `port` is set when the endpoint lives on a side-car
|
|
2361
|
-
* server on its own port (bridge mode: `devframeViteBridge`,
|
|
2362
|
-
* `@devframes/next`): the client combines the page hostname with `port`
|
|
2363
|
-
* and resolves `path` against that origin, mirroring
|
|
2364
|
-
* {@link ConnectionMetaWebsocket.port}.
|
|
2330
|
+
* Mount path override. Defaults depend on the adapter:
|
|
2331
|
+
* `/` for standalone (`cli` / `build`), `/__<id>/` for hosted
|
|
2332
|
+
* (`vite` / `embedded`).
|
|
2365
2333
|
*/
|
|
2366
|
-
|
|
2367
|
-
path: string;
|
|
2368
|
-
port?: number;
|
|
2369
|
-
};
|
|
2334
|
+
basePath?: string;
|
|
2370
2335
|
/**
|
|
2371
|
-
*
|
|
2372
|
-
*
|
|
2373
|
-
*
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2376
|
-
*
|
|
2336
|
+
* How a hub reacts when another devframe sharing this one's `id` is
|
|
2337
|
+
* mounted onto the same hub. Consulted only by hub adapters
|
|
2338
|
+
* (`ctx.install`); standalone adapters (`cli` / `build`)
|
|
2339
|
+
* ignore it.
|
|
2340
|
+
*
|
|
2341
|
+
* @default 'warn'
|
|
2377
2342
|
*/
|
|
2378
|
-
|
|
2343
|
+
duplicationStrategy?: DevframeDuplicationStrategy;
|
|
2379
2344
|
/**
|
|
2380
|
-
*
|
|
2381
|
-
*
|
|
2345
|
+
* Declares which runtimes meaningfully support this devframe. Adapters
|
|
2346
|
+
* act on a `false` before doing any work:
|
|
2382
2347
|
*
|
|
2383
|
-
*
|
|
2384
|
-
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2389
|
-
*
|
|
2390
|
-
*
|
|
2391
|
-
*
|
|
2392
|
-
* dump from the hub base. Resolved against the fetched URL.
|
|
2348
|
+
* - `build: false`: `createCac` skips registering the `build` subcommand,
|
|
2349
|
+
* `createBuild` refuses (throws `DF0042`) unless `{ force: true }`, and
|
|
2350
|
+
* a hub static build (`buildHub`) silently skips the devframe - no dock,
|
|
2351
|
+
* no SPA copy, no RPCs in the dump. Useful for a devframe whose value is
|
|
2352
|
+
* inherently live (e.g. it manages real files on disk), so a static
|
|
2353
|
+
* export would only ever produce a broken, write-less shell of the tool.
|
|
2354
|
+
* - `dev: false`: `createDevServer` refuses (throws `DF0058`) unless
|
|
2355
|
+
* `{ force: true }`. Useful for a devframe that only makes sense as a
|
|
2356
|
+
* static export (e.g. a report generator with nothing to serve live).
|
|
2393
2357
|
*/
|
|
2394
|
-
|
|
2358
|
+
capabilities?: {
|
|
2359
|
+
dev?: boolean;
|
|
2360
|
+
build?: boolean;
|
|
2361
|
+
};
|
|
2395
2362
|
/**
|
|
2396
|
-
*
|
|
2397
|
-
*
|
|
2398
|
-
*
|
|
2399
|
-
*
|
|
2400
|
-
*
|
|
2401
|
-
*
|
|
2402
|
-
*
|
|
2403
|
-
*
|
|
2404
|
-
*
|
|
2405
|
-
*
|
|
2406
|
-
* > it. Emit it exclusively from hub-controlled, per-frame meta, never
|
|
2407
|
-
* > from a publicly reachable static `__connection.json`.
|
|
2363
|
+
* Wire services this devframe consumes (see `DevframeServiceDefinition`).
|
|
2364
|
+
* Each entry is either a declarative descriptor
|
|
2365
|
+
* (`{ package, version?, required?, options? }`, where the host imports the
|
|
2366
|
+
* package's default-export factory, resolving it against **this plugin's
|
|
2367
|
+
* own dependencies**) or a ready `DevframeServiceDefinition` (the factory
|
|
2368
|
+
* was already called). The adapter queues these before `setup(ctx)` runs
|
|
2369
|
+
* and constructs each service once at the `ctx.services.ready()` barrier,
|
|
2370
|
+
* merging option sets across every declarer. Missing services are skipped
|
|
2371
|
+
* unless marked `required`; clients feature-detect via
|
|
2372
|
+
* `client.services.has(pkg)` and degrade.
|
|
2408
2373
|
*/
|
|
2409
|
-
|
|
2374
|
+
services?: DevframeServiceInput[];
|
|
2410
2375
|
/**
|
|
2411
|
-
*
|
|
2412
|
-
*
|
|
2413
|
-
*
|
|
2376
|
+
* Author's SPA dist, served as the devframe's UI. A local directory, or
|
|
2377
|
+
* a {@link StaticAssetsSource} remote declaration (`{ package, version }`)
|
|
2378
|
+
* served through devframe's caching CDN back-proxy so the assets need not
|
|
2379
|
+
* ship inside the node package.
|
|
2414
2380
|
*
|
|
2415
|
-
*
|
|
2416
|
-
*
|
|
2381
|
+
* Consumed by every adapter that serves the UI (`dev`, `build`, `vite`,
|
|
2382
|
+
* `next`, and the hub install path).
|
|
2417
2383
|
*/
|
|
2418
|
-
|
|
2384
|
+
clientAssets?: StaticAssetsSource;
|
|
2385
|
+
/** RPC-level configuration for this devframe (see {@link DevframeRpcOptions}). */
|
|
2386
|
+
rpc?: DevframeRpcOptions;
|
|
2387
|
+
/** Server-side setup: the primary entrypoint. Runs in every runtime. */
|
|
2388
|
+
setup: (ctx: DevframeNodeContext, info?: DevframeSetupInfo) => void | Promise<void>;
|
|
2389
|
+
cli?: DevframeCliOptions;
|
|
2390
|
+
}
|
|
2391
|
+
interface DevframeRpcOptions {
|
|
2419
2392
|
/**
|
|
2420
|
-
*
|
|
2421
|
-
*
|
|
2422
|
-
*
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
2425
|
-
* Contrast this with {@link DevframeSettingsRegistry} (`ctx.scope(ns).settings`)
|
|
2426
|
-
* and a hub's `devframe:user-settings` shared-state key; both are
|
|
2427
|
-
* mutable, user-editable, and synced bidirectionally over RPC for the
|
|
2428
|
-
* life of the session. `configs` is the opposite: one-way, immutable,
|
|
2429
|
-
* decided by whoever assembled the server.
|
|
2430
|
-
*
|
|
2431
|
-
* Each key is owned by one package, contributed via declaration merging:
|
|
2393
|
+
* Opt an RPC function into the static-build snapshot **without owning its
|
|
2394
|
+
* definition**, the mechanism a devframe uses to bake a wire service's
|
|
2395
|
+
* RPC (e.g. `@devframes/service-git`'s `status`/`log`/`show`) into its
|
|
2396
|
+
* `build` export, since the service itself defines no `dump`/`snapshot`.
|
|
2432
2397
|
*
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
2437
|
-
*
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
2398
|
+
* Each entry is either a bare method id (bakes the no-argument call, like
|
|
2399
|
+
* `snapshot: true`) or `{ method, inputs }` where `inputs` is the list of
|
|
2400
|
+
* argument-tuples to bake, or an async provider given the node context
|
|
2401
|
+
* (so it can enumerate at build time, e.g. read commit hashes via the
|
|
2402
|
+
* service's node API). `createBuild` resolves these after setup and
|
|
2403
|
+
* executes the target's own handler per tuple; the first tuple's result
|
|
2404
|
+
* becomes the fallback so any call variant resolves to a baked value.
|
|
2440
2405
|
*/
|
|
2441
|
-
|
|
2406
|
+
snapshot?: DevframeSnapshotRpcEntry[];
|
|
2442
2407
|
}
|
|
2408
|
+
/** Argument-tuples to bake for a {@link DevframeSnapshotRpcEntry}, or a provider that computes them at build time. */
|
|
2409
|
+
type DevframeSnapshotRpcInputs = readonly (readonly unknown[])[] | ((ctx: DevframeNodeContext) => readonly (readonly unknown[])[] | Promise<readonly (readonly unknown[])[]>);
|
|
2443
2410
|
/**
|
|
2444
|
-
*
|
|
2445
|
-
*
|
|
2446
|
-
* connection handshake augments this interface with its own key (see
|
|
2447
|
-
* {@link ConnectionMeta.configs} for the pattern). `@devframes/hub`
|
|
2448
|
-
* augments it with `dock`; `@devframes/hub-ui` augments it with `ui`.
|
|
2411
|
+
* One {@link DevframeRpcOptions.snapshot} entry: a bare method id (bakes
|
|
2412
|
+
* the no-argument call) or a method plus the argument-tuples to bake.
|
|
2449
2413
|
*/
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2414
|
+
type DevframeSnapshotRpcEntry = string | {
|
|
2415
|
+
method: string;
|
|
2416
|
+
inputs: DevframeSnapshotRpcInputs;
|
|
2417
|
+
};
|
|
2418
|
+
export { DevframeServiceId as $, AgentToolProviderHandle as $t, CliFlagsSchema as A, StreamReader as At, DevframeNodeRpcSession as B, SharedState as Bt, McpPromptResult as C, DevframeDiagnosticsHost as Ct, McpResourcesChangedHook as D, CreateStreamReaderOptions as Dt, McpResourceTemplateEntry as E, BufferedChunk as Et, ConnectionMetaSse as F, Immutable as Ft, RpcStreamingChannel as G, AgentHandle as Gt, RpcFunctionsHost as H, SharedStateOptions as Ht, ConnectionMetaWebsocket as I, ImmutableArray as It, DevframeRpcClientFunctions as J, AgentResourceContent as Jt, RpcStreamingChannelOptions as K, AgentManifest as Kt, DevframeCapabilities as L, ImmutableMap as Lt, defineCliFlags as M, StreamSinkEvents as Mt, parseCliFlags as N, createStreamReader as Nt, McpServerHandle as O, CreateStreamSinkOptions as Ot, ConnectionMeta as P, createStreamSink as Pt, DevframeServiceDescriptor as Q, AgentToolProvider as Qt, DevframeConnectionConfigsRegistry as R, ImmutableObject as Rt, McpPromptMessage as S, DevframeStorageScope as St, McpResourceTemplateContent as T, BrowserAgentClientInfo as Tt, RpcSharedStateGetOptions as U, SharedStatePatch as Ut, RpcBroadcastOptions as V, SharedStateEvents as Vt, RpcSharedStateHost as W, createSharedState as Wt, DevframeRpcSharedStates as X, AgentTool as Xt, DevframeRpcServerFunctions as Y, AgentResourceInput as Yt, DevframeServiceDefinition as Z, AgentToolInput as Zt, McpConnectionInfo as _, ScopedServerFunctions as _t, DevframeDuplicationStrategy as a, DevframeServicesRegistry as at, McpPrompt as b, DevframeViewHost as bt, DevframeSnapshotRpcEntry as c, DevframeScopedNodeContext as ct, DevframeWsOptions as d, DevframeSettings as dt, DevframeAgentHost as en, DevframeServiceInput as et, McpAuthorization as f, DevframeSettingsRegistry as ft, CreateMcpServerOptions as g, ScopedRpcFn as gt, CreateMcpFetchHandlerOptions as h, ScopedClientFunctions as ht, DevframeDockDefaults as i, EventsMap as in, DevframeServicesHost as it, InferCliFlags as j, StreamSink as jt, DevframeAuthHandler as k, StreamErrorPayload as kt, DevframeSnapshotRpcInputs as l, DevframeScopedNodeRpc as lt, McpSetting as m, ScopedBroadcastOptions as mt, DevframeDefinition as n, EventEmitter as nn, DevframeServiceOf as nt, DevframeRpcOptions as o, DevframeServicesScopeRegistry as ot, McpRouteOptions as p, DevframeSettingsStore as pt, RpcStreamingHost as q, AgentResource as qt, DevframeDeploymentKind as r, EventUnsubscribe as rn, DevframeServiceScopeOf as rt, DevframeSetupInfo as s, DevframeServicesState as st, DevframeCliOptions as t, DevframeAgentHostEvents as tn, DevframeServiceMeta as tt, DevframeSseOptions as u, DevframeScopedStreamingHost as ut, McpContentBlock as v, ScopedSharedStates as vt, McpResourceTemplate as w, DevframeDiagnosticsLogger as wt, McpPromptArgument as x, DevframeHost as xt, McpFetchHandler as y, SettingsForNamespace as yt, DevframeNodeContext as z, ImmutableSet as zt };
|