devframe 0.9.8 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/{_shared-BM3PdYli.mjs → _shared-C08SdQRl.mjs} +15 -4
  2. package/dist/{_shared-mtXpcJIv.d.mts → _shared-CK3czkH4.d.mts} +25 -2
  3. package/dist/adapters/build.d.mts +6 -6
  4. package/dist/adapters/build.mjs +32 -22
  5. package/dist/adapters/cac.d.mts +16 -1
  6. package/dist/adapters/cac.mjs +8 -7
  7. package/dist/adapters/dev.d.mts +13 -13
  8. package/dist/adapters/dev.mjs +2 -2
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +28 -26
  11. package/dist/adapters/initiate.mjs +1 -1
  12. package/dist/adapters/mcp.d.mts +28 -14
  13. package/dist/adapters/mcp.mjs +75 -39
  14. package/dist/{agent-tool-name-EgfoFO8C.mjs → agent-tool-name-DGzeuWcO.mjs} +2 -2
  15. package/dist/cli/main.d.mts +1 -1
  16. package/dist/cli/main.mjs +41 -17
  17. package/dist/client/index.d.mts +36 -36
  18. package/dist/client/index.mjs +83 -51
  19. package/dist/{client-assets-C7SXgTWY.mjs → client-assets-DNdhagGm.mjs} +2 -2
  20. package/dist/constants.d.mts +8 -7
  21. package/dist/constants.mjs +7 -6
  22. package/dist/{context-CLF4-8Pp.d.mts → context-4AIVRLYF.d.mts} +158 -122
  23. package/dist/{context-omlma_1n.mjs → context-CwPUinjn.mjs} +126 -88
  24. package/dist/{context-KUqAfawQ.mjs → context-DIUvJW4D.mjs} +3 -3
  25. package/dist/{context-DftYyXaR.d.mts → context-rgBSPFHS.d.mts} +5 -5
  26. package/dist/{crypto-token-XCqTSMg9.mjs → crypto-token-TVbGGFuj.mjs} +1 -1
  27. package/dist/{dev-CzkPCJwi.mjs → dev-Eqq5PX0k.mjs} +37 -18
  28. package/dist/{diagnostics-BXWW3VK-.mjs → diagnostics-BMfN8mb1.mjs} +30 -17
  29. package/dist/{diagnostics-CD8nlgll.mjs → diagnostics-D0EVm5M6.mjs} +2 -2
  30. package/dist/{events-4daw0uK9.mjs → events-BV4Dj59a.mjs} +2 -2
  31. package/dist/{host-h3-fRbF9yor.mjs → host-h3-BJ4siyz7.mjs} +1 -1
  32. package/dist/in-page-channel/index.d.mts +14 -14
  33. package/dist/in-page-channel/index.mjs +63 -54
  34. package/dist/{index-BzyopqxV.d.mts → index-pIVt92jP.d.mts} +9 -9
  35. package/dist/{index-D3k0BIhe.d.mts → index-pKl67H6w.d.mts} +4 -4
  36. package/dist/index.d.mts +8 -8
  37. package/dist/index.mjs +2 -2
  38. package/dist/{instance-registry-BjlMQbFB.mjs → instance-registry-C7-41RSp.mjs} +8 -8
  39. package/dist/{instance-shell-Tcp5hGoq.d.mts → instance-shell-7Z52PE4_.d.mts} +18 -18
  40. package/dist/{instance-shell-CpVW4zG0.mjs → instance-shell-cdVETpfz.mjs} +227 -58
  41. package/dist/internal/index.d.mts +40 -23
  42. package/dist/internal/index.mjs +10 -10
  43. package/dist/node/auth.d.mts +2 -2
  44. package/dist/node/auth.mjs +2 -2
  45. package/dist/node/hub-internals.d.mts +2 -2
  46. package/dist/node/hub-internals.mjs +2 -2
  47. package/dist/node/index.d.mts +5 -5
  48. package/dist/node/index.mjs +2 -2
  49. package/dist/{nostics-SPGDgHEP.d.mts → nostics-0sKe5HIj.d.mts} +2 -2
  50. package/dist/{nostics-CzECRXpE.mjs → nostics-D0PvLZsn.mjs} +1 -1
  51. package/dist/origin-DGDH8BI9.d.mts +45 -0
  52. package/dist/origin-DZit9g29.mjs +80 -0
  53. package/dist/recipes/common-rpc-functions.d.mts +5 -5
  54. package/dist/recipes/common-rpc-functions.mjs +3 -3
  55. package/dist/recipes/interactive-auth.d.mts +6 -6
  56. package/dist/recipes/interactive-auth.mjs +6 -6
  57. package/dist/{remote-assets-DezQmPQU.mjs → remote-assets-BIFWOlBW.mjs} +26 -6
  58. package/dist/{remote-assets-B13_vRkJ.d.mts → remote-assets-eBvSKZMS.d.mts} +7 -7
  59. package/dist/{revoke-COLW0cOi.mjs → revoke-cqztiCX4.mjs} +1 -1
  60. package/dist/rpc/dump.d.mts +2 -11
  61. package/dist/rpc/dump.mjs +1 -1
  62. package/dist/rpc/index.d.mts +2 -2
  63. package/dist/rpc/index.mjs +3 -3
  64. package/dist/rpc/transports/sse-client.d.mts +1 -1
  65. package/dist/rpc/transports/sse-client.mjs +30 -14
  66. package/dist/rpc/transports/sse-server.d.mts +4 -4
  67. package/dist/rpc/transports/sse-server.mjs +7 -7
  68. package/dist/rpc/transports/ws-bun.d.mts +5 -5
  69. package/dist/rpc/transports/ws-bun.mjs +8 -2
  70. package/dist/rpc/transports/ws-client.d.mts +1 -1
  71. package/dist/rpc/transports/ws-client.mjs +2 -2
  72. package/dist/rpc/transports/ws-deno.d.mts +4 -4
  73. package/dist/rpc/transports/ws-deno.mjs +8 -2
  74. package/dist/rpc/transports/ws-server.d.mts +2 -1
  75. package/dist/rpc/transports/ws-server.mjs +232 -1
  76. package/dist/{rpc-core-B3W3z9ff.d.mts → rpc-core-Ceu6AUz8.d.mts} +4 -4
  77. package/dist/{rpc-core-DlHd276T.mjs → rpc-core-DVQ7xi89.mjs} +14 -2
  78. package/dist/{serialization-BGzEwAdr.mjs → serialization-DTZnPQ1-.mjs} +20 -18
  79. package/dist/{services-install-CqqQVls5.mjs → services-install-P_DV7VYL.mjs} +32 -21
  80. package/dist/session-DPfj6zQG.mjs +16 -0
  81. package/dist/{shared-state--sduc6Xi.mjs → shared-state-CaxB1q0h.mjs} +2 -2
  82. package/dist/{simple-schema-DQPZrAaZ.mjs → simple-schema-Bi40l-P6.mjs} +2 -2
  83. package/dist/{sse-client-DwX021ST.d.mts → sse-client-BQ4jS3eO.d.mts} +4 -4
  84. package/dist/{state-CK9LjrnT.mjs → state-CeQQWzM-.mjs} +4 -4
  85. package/dist/{static-DV_qUSRS.mjs → static-DZ8P2Kn7.mjs} +130 -135
  86. package/dist/{storage-BXNVhKyR.mjs → storage-Dccf_IyD.mjs} +1 -1
  87. package/dist/types/index.d.mts +6 -6
  88. package/dist/{types-CMdPYhOx.d.mts → types-Dq4i156u.d.mts} +17 -17
  89. package/dist/utils/agent-tool-name.d.mts +2 -2
  90. package/dist/utils/agent-tool-name.mjs +2 -2
  91. package/dist/utils/colors.d.mts +1 -1
  92. package/dist/utils/crypto-token.d.mts +1 -1
  93. package/dist/utils/crypto-token.mjs +1 -1
  94. package/dist/utils/events.d.mts +1 -1
  95. package/dist/utils/nostics.d.mts +1 -1
  96. package/dist/utils/nostics.mjs +1 -1
  97. package/dist/utils/open.mjs +1 -1
  98. package/dist/utils/origin.d.mts +2 -0
  99. package/dist/utils/origin.mjs +80 -0
  100. package/dist/utils/remote-assets.d.mts +2 -2
  101. package/dist/utils/remote-assets.mjs +1 -1
  102. package/dist/utils/serve-static.d.mts +4 -4
  103. package/dist/utils/serve-static.mjs +56 -19
  104. package/dist/utils/shared-state.d.mts +1 -1
  105. package/dist/utils/shared-state.mjs +1 -1
  106. package/dist/utils/simple-schema.d.mts +5 -5
  107. package/dist/utils/simple-schema.mjs +2 -2
  108. package/dist/utils/streaming-channel.d.mts +1 -1
  109. package/dist/utils/streaming-channel.mjs +2 -2
  110. package/dist/utils/when.d.mts +5 -5
  111. package/dist/{validation-YrZH6atx.mjs → validation-BOy8IoFZ.mjs} +2 -2
  112. package/dist/{wire-codec-0K-o5MYW.mjs → wire-codec-dcCeXcSo.mjs} +3 -3
  113. package/dist/{ws-client-7_lZi-B9.d.mts → ws-client-Xpxt0oPA.d.mts} +3 -3
  114. package/dist/{ws-server-VyHlanzy.d.mts → ws-server-D2nv68Hg.d.mts} +13 -37
  115. package/package.json +2 -1
  116. package/dist/ws-server-Y_AumUQH.mjs +0 -294
@@ -1,15 +1,15 @@
1
- import { v as RpcFunctionDefinitionAny } from "../types-CMdPYhOx.mjs";
2
- import { At as AgentResource, F as DevframeDefinition, Ft as AgentToolProvider, It as AgentToolProviderHandle, Lt as DevframeAgentHost$1, Mt as AgentResourceInput, Nt as AgentTool, Ot as AgentHandle, Pt as AgentToolInput, Rt as DevframeAgentHostEvents, jt as AgentResourceContent, kt as AgentManifest, o as DevframeNodeContext, yt as DevframeHost, zt as EventEmitter } from "../context-CLF4-8Pp.mjs";
3
- import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-assets-B13_vRkJ.mjs";
4
- import { a as InstanceShellInit, c as StartedServer, d as samePath, f as DevframeInstanceRecord, h as registerDevframeInstance, i as InstanceShellApi, l as createInstanceShell, m as listLiveDevframeInstances, n as InstanceRegisterConfig, o as InstanceShellInternals, p as DevframeInstanceRegistration, r as InstanceShell, s as InstanceWsTier, t as CreateInstanceShellOptions, u as resolveInstanceRegister } from "../instance-shell-Tcp5hGoq.mjs";
5
- import { n as normalizeBasePath, r as resolveBasePath } from "../_shared-mtXpcJIv.mjs";
6
- import { n as CreateContextRpcServerOptions, r as createContextRpcServer, t as ContextRpcServer } from "../rpc-core-B3W3z9ff.mjs";
1
+ import { v as RpcFunctionDefinitionAny } from "../types-Dq4i156u.mjs";
2
+ import { At as AgentManifest, Bt as EventEmitter, F as DevframeDefinition, Ft as AgentToolInput, It as AgentToolProvider, Lt as AgentToolProviderHandle, Mt as AgentResourceContent, Nt as AgentResourceInput, Pt as AgentTool, Rt as DevframeAgentHost$1, bt as DevframeHost, jt as AgentResource, kt as AgentHandle, o as DevframeNodeContext, zt as DevframeAgentHostEvents } from "../context-4AIVRLYF.mjs";
3
+ import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-assets-eBvSKZMS.mjs";
4
+ import { a as InstanceShellInit, c as StartedServer, d as samePath, f as DevframeInstanceRecord, h as registerDevframeInstance, i as InstanceShellApi, l as createInstanceShell, m as listLiveDevframeInstances, n as InstanceRegisterConfig, o as InstanceShellInternals, p as DevframeInstanceRegistration, r as InstanceShell, s as InstanceWsTier, t as CreateInstanceShellOptions, u as resolveInstanceRegister } from "../instance-shell-7Z52PE4_.mjs";
5
+ import { i as resolveBasePath, n as ResolvedMcpConfig, o as resolveMcpConfig, r as normalizeBasePath } from "../_shared-CK3czkH4.mjs";
6
+ import { n as CreateContextRpcServerOptions, r as createContextRpcServer, t as ContextRpcServer } from "../rpc-core-Ceu6AUz8.mjs";
7
7
  //#region src/client-assets.d.ts
8
8
  /**
9
- * Resolve a definition's client assets source — the built SPA served as its
9
+ * Resolve a definition's client assets source: the built SPA served as its
10
10
  * UI. Prefers the top-level {@link DevframeDefinition.clientAssets} and falls
11
11
  * back to the deprecated `cli.distDir`, so both the new and legacy shapes
12
- * resolve. Returns `undefined` when neither is set (bridge mode — the SPA is
12
+ * resolve. Returns `undefined` when neither is set (bridge mode, where the SPA is
13
13
  * hosted elsewhere).
14
14
  *
15
15
  * Internal: exposed to first-party integrations via `devframe/internal`, not
@@ -22,9 +22,9 @@ declare function resolveClientAssets(d: DevframeDefinition): StaticAssetsSource
22
22
  * How {@link coerceAgentPositionalArgs} treats an args object that carries
23
23
  * neither declared schemas nor `arg0`/`arg1`/… keys:
24
24
  *
25
- * - `'wrap'` — pass the object itself as the single positional argument.
25
+ * - `'wrap'`: pass the object itself as the single positional argument.
26
26
  * RPC-backed tools use this: an untyped RPC may take one raw object.
27
- * - `'drop'` — call with zero arguments. Command-backed tools use this:
27
+ * - `'drop'`: call with zero arguments. Command-backed tools use this:
28
28
  * a handler's positional parameters come solely from its declared
29
29
  * `agent.args` schemas, so undeclared payload is ignored.
30
30
  */
@@ -46,6 +46,11 @@ type AgentArgsFallback = 'wrap' | 'drop';
46
46
  declare function coerceAgentPositionalArgs(args: unknown, schemas: readonly unknown[] | undefined, fallback?: AgentArgsFallback): unknown[];
47
47
  //#endregion
48
48
  //#region src/node/diagnostics.d.ts
49
+ /**
50
+ * DF00xx codes are allocated across packages (e.g. @devframes/json-render
51
+ * owns DF0037–DF0041), so this file alone doesn't show the next free
52
+ * number; check `docs/content/6.errors/` for the full allocation before adding one.
53
+ */
49
54
  declare const diagnostics: import("nostics").Diagnostics<{
50
55
  readonly DF0006: {
51
56
  readonly why: (p: {
@@ -113,7 +118,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
113
118
  channel: string;
114
119
  id: string;
115
120
  }) => string;
116
- readonly fix: "Track the producer lifecycle — guard writes with the `stream.signal.aborted` flag.";
121
+ readonly fix: "Track the producer lifecycle by guarding writes with the `stream.signal.aborted` flag.";
117
122
  };
118
123
  readonly DF0032: {
119
124
  readonly why: (p: {
@@ -145,7 +150,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
145
150
  readonly why: (p: {
146
151
  name: string;
147
152
  }) => string;
148
- readonly fix: "Complete the auth handshake (or connect with a static/pre-shared token) before calling a trusted method. Untrusted callers may only call `anonymous:`-prefixed methods — see `isAnonymousRpcMethod`.";
153
+ readonly fix: "Complete the auth handshake (or connect with a static/pre-shared token) before calling a trusted method. Untrusted callers may only call `anonymous:`-prefixed methods; see `isAnonymousRpcMethod`.";
149
154
  };
150
155
  readonly DF0037: {
151
156
  readonly why: (p: {
@@ -194,7 +199,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
194
199
  readonly why: (p: {
195
200
  port: number;
196
201
  }) => string;
197
- readonly fix: "Call devframe_connect_list-instances for the current instance list — the instance may have stopped or changed port.";
202
+ readonly fix: "Call devframe_connect_list-instances for the current instance list; the instance may have stopped or changed port.";
198
203
  };
199
204
  readonly DF0051: {
200
205
  readonly why: (p: {
@@ -214,7 +219,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
214
219
  readonly why: (p: {
215
220
  id: string;
216
221
  }) => string;
217
- readonly fix: "Await `instance.ready` (or any request through `instance.handler`) before reading `connectionMeta()` — the WebSocket binding it describes is only known once initialization completes.";
222
+ readonly fix: "Await `instance.ready` (or any request through `instance.handler`) before reading `connectionMeta()`; the WebSocket binding it describes is only known once initialization completes.";
218
223
  };
219
224
  readonly DF0055: {
220
225
  readonly why: (p: {
@@ -230,7 +235,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
230
235
  };
231
236
  readonly DF0057: {
232
237
  readonly why: () => string;
233
- readonly fix: "Clients connect over the SSE endpoint instead — no upgrade wiring is needed. Remove `ws: false` if the instance should serve a WebSocket after all.";
238
+ readonly fix: "Clients connect over the SSE endpoint instead, so no upgrade wiring is needed. Remove `ws: false` if the instance should serve a WebSocket after all.";
234
239
  };
235
240
  readonly DF0058: {
236
241
  readonly why: (p: {
@@ -261,7 +266,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
261
266
  required: string;
262
267
  installed: string;
263
268
  }) => string;
264
- readonly fix: "Align the installed assets package with the version its node package declares — they are published in lockstep.";
269
+ readonly fix: "Align the installed assets package with the version its node package declares; they are published in lockstep.";
265
270
  };
266
271
  readonly DF0062: {
267
272
  readonly why: (p: {
@@ -291,7 +296,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
291
296
  field: "package" | "version";
292
297
  value: string;
293
298
  }) => string;
294
- readonly fix: "A remote-assets `package` must be a valid npm package name and `version` an exact semver version (e.g. `1.2.3`) — they are interpolated into CDN URLs and the cache path.";
299
+ readonly fix: "A remote-assets `package` must be a valid npm package name and `version` an exact semver version (e.g. `1.2.3`); they are interpolated into CDN URLs and the cache path.";
295
300
  };
296
301
  readonly DF0066: {
297
302
  readonly why: (p: {
@@ -327,7 +332,7 @@ declare const diagnostics: import("nostics").Diagnostics<{
327
332
  package: string;
328
333
  reason: string;
329
334
  }) => string;
330
- readonly fix: "A service package's default export must be a factory returning a `DevframeServiceDefinition` — an object with `package`, `version`, `scope`, and a `setup` function.";
335
+ readonly fix: "A service package's default export must be a factory returning a `DevframeServiceDefinition`, an object with `package`, `version`, `scope`, and a `setup` function.";
331
336
  };
332
337
  readonly DF0072: {
333
338
  readonly why: (p: {
@@ -335,6 +340,18 @@ declare const diagnostics: import("nostics").Diagnostics<{
335
340
  }) => string;
336
341
  readonly fix: "Check the method id, and ensure the service/plugin that registers it is installed (e.g. declared in `services`) before the build collects the dump.";
337
342
  };
343
+ readonly DF0075: {
344
+ readonly why: (p: {
345
+ runtime: string;
346
+ }) => string;
347
+ readonly fix: "Keep the SSE endpoint enabled (drop `sse: false`) so clients connect over it on Bun/Deno, or move the socket to a side-car (`ws: { sidecar: true }`) which binds the native WebSocket adapter on its own port.";
348
+ };
349
+ readonly DF0076: {
350
+ readonly why: (p: {
351
+ runtime: string;
352
+ }) => string;
353
+ readonly fix: "On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` with `attachBunWsTransport` / `attachDenoWsTransport` (see the hub-deno-minimal example), or connect over the SSE endpoint instead.";
354
+ };
338
355
  }, readonly [(d: import("nostics").Diagnostic, { method }?: {
339
356
  method?: "log" | "warn" | "error";
340
357
  }) => void]>;
@@ -384,7 +401,7 @@ interface CreateH3DevframeHostOptions {
384
401
  */
385
402
  origin: string | (() => string);
386
403
  /**
387
- * Register a static-file handler at `base` serving files from `source` —
404
+ * Register a static-file handler at `base` serving files from `source`:
388
405
  * a local directory or a resolved remote-assets back-proxy store (both
389
406
  * accepted by `devframe/utils/serve-static`). `mountStatic` forwards to
390
407
  * it; when omitted the host serves no SPA (bridge mode, where the SPA is
@@ -407,7 +424,7 @@ interface CreateH3DevframeHostOptions {
407
424
  workspaceRoot?: string;
408
425
  }
409
426
  /**
410
- * h3-backed {@link DevframeHost} — used by the standalone CLI adapter.
427
+ * h3-backed {@link DevframeHost}, used by the standalone CLI adapter.
411
428
  */
412
429
  declare function createH3DevframeHost(options: CreateH3DevframeHostOptions): DevframeHost;
413
430
  //#endregion
@@ -440,7 +457,7 @@ interface RpcWireCodec {
440
457
  * JSON (methods declared `jsonSerializable: true`) and `s:`-prefixed
441
458
  * structured-clone (everything else, including all error envelopes), with a
442
459
  * request-id → method map so a response independently picks the same
443
- * encoder as its request. One codec per connection — request-id spaces
460
+ * encoder as its request. One codec per connection; request-id spaces
444
461
  * don't collide across connections.
445
462
  *
446
463
  * @internal
@@ -448,7 +465,7 @@ interface RpcWireCodec {
448
465
  declare function createRpcWireCodec(definitions?: ReadonlyMap<string, Pick<RpcFunctionDefinitionAny, 'jsonSerializable'>>): RpcWireCodec;
449
466
  /**
450
467
  * Peek at a wire frame's birpc envelope without engaging a codec's
451
- * request-id bookkeeping — used by the SSE transport to route a frame
468
+ * request-id bookkeeping; used by the SSE transport to route a frame
452
469
  * (park a POST for its response / answer with a bare 202) before it is
453
470
  * handed to birpc proper.
454
471
  *
@@ -459,4 +476,4 @@ declare function peekRpcWireFrame(raw: string): {
459
476
  i?: string;
460
477
  };
461
478
  //#endregion
462
- export { type AgentArgsFallback, type ContextRpcServer, type CreateContextRpcServerOptions, CreateH3DevframeHostOptions, type CreateInstanceShellOptions, DevframeAgentHost, type DevframeInstanceRecord, type DevframeInstanceRegistration, type InstanceRegisterConfig, type InstanceShell, type InstanceShellApi, type InstanceShellInit, type InstanceShellInternals, type InstanceWsTier, type RpcWireCodec, type StartedServer, coerceAgentPositionalArgs, createContextRpcServer, createH3DevframeHost, createInstanceShell, createRpcWireCodec, diagnostics, importRuntimeModule, listLiveDevframeInstances, normalizeBasePath, normalizeHttpServerUrl, peekRpcWireFrame, registerDevframeInstance, resolveBasePath, resolveClientAssets, resolveInstanceRegister, samePath };
479
+ export { type AgentArgsFallback, type ContextRpcServer, type CreateContextRpcServerOptions, CreateH3DevframeHostOptions, type CreateInstanceShellOptions, DevframeAgentHost, type DevframeInstanceRecord, type DevframeInstanceRegistration, type InstanceRegisterConfig, type InstanceShell, type InstanceShellApi, type InstanceShellInit, type InstanceShellInternals, type InstanceWsTier, type ResolvedMcpConfig, type RpcWireCodec, type StartedServer, coerceAgentPositionalArgs, createContextRpcServer, createH3DevframeHost, createInstanceShell, createRpcWireCodec, diagnostics, importRuntimeModule, listLiveDevframeInstances, normalizeBasePath, normalizeHttpServerUrl, peekRpcWireFrame, registerDevframeInstance, resolveBasePath, resolveClientAssets, resolveInstanceRegister, resolveMcpConfig, samePath };
@@ -1,10 +1,10 @@
1
- import { t as resolveClientAssets } from "../client-assets-C7SXgTWY.mjs";
2
- import { n as peekRpcWireFrame, t as createRpcWireCodec } from "../wire-codec-0K-o5MYW.mjs";
3
- import { t as diagnostics } from "../diagnostics-BXWW3VK-.mjs";
4
- import { a as DevframeAgentHost, o as coerceAgentPositionalArgs } from "../services-install-CqqQVls5.mjs";
5
- import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-BM3PdYli.mjs";
6
- import { t as createH3DevframeHost } from "../host-h3-fRbF9yor.mjs";
7
- import { a as importRuntimeModule, i as normalizeHttpServerUrl, n as resolveInstanceRegister, r as samePath, t as createInstanceShell } from "../instance-shell-CpVW4zG0.mjs";
8
- import { i as registerDevframeInstance, n as listLiveDevframeInstances } from "../instance-registry-BjlMQbFB.mjs";
9
- import { t as createContextRpcServer } from "../rpc-core-DlHd276T.mjs";
10
- export { DevframeAgentHost, coerceAgentPositionalArgs, createContextRpcServer, createH3DevframeHost, createInstanceShell, createRpcWireCodec, diagnostics, importRuntimeModule, listLiveDevframeInstances, normalizeBasePath, normalizeHttpServerUrl, peekRpcWireFrame, registerDevframeInstance, resolveBasePath, resolveClientAssets, resolveInstanceRegister, samePath };
1
+ import { t as resolveClientAssets } from "../client-assets-DNdhagGm.mjs";
2
+ import { n as peekRpcWireFrame, t as createRpcWireCodec } from "../wire-codec-dcCeXcSo.mjs";
3
+ import { t as diagnostics } from "../diagnostics-BMfN8mb1.mjs";
4
+ import { a as DevframeAgentHost, o as coerceAgentPositionalArgs } from "../services-install-P_DV7VYL.mjs";
5
+ import { i as resolveMcpConfig, n as resolveBasePath, t as normalizeBasePath } from "../_shared-C08SdQRl.mjs";
6
+ import { t as createH3DevframeHost } from "../host-h3-BJ4siyz7.mjs";
7
+ import { a as importRuntimeModule, i as normalizeHttpServerUrl, n as resolveInstanceRegister, r as samePath, t as createInstanceShell } from "../instance-shell-cdVETpfz.mjs";
8
+ import { i as registerDevframeInstance, n as listLiveDevframeInstances } from "../instance-registry-C7-41RSp.mjs";
9
+ import { t as createContextRpcServer } from "../rpc-core-DVQ7xi89.mjs";
10
+ export { DevframeAgentHost, coerceAgentPositionalArgs, createContextRpcServer, createH3DevframeHost, createInstanceShell, createRpcWireCodec, diagnostics, importRuntimeModule, listLiveDevframeInstances, normalizeBasePath, normalizeHttpServerUrl, peekRpcWireFrame, registerDevframeInstance, resolveBasePath, resolveClientAssets, resolveInstanceRegister, resolveMcpConfig, samePath };
@@ -1,3 +1,3 @@
1
- import { Ct as DevframeAuthHandler } from "../context-CLF4-8Pp.mjs";
2
- import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-D3k0BIhe.mjs";
1
+ import { wt as DevframeAuthHandler } from "../context-4AIVRLYF.mjs";
2
+ import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-pKl67H6w.mjs";
3
3
  export { DevframeAuthHandler, buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,3 +1,3 @@
1
- import { n as revokeAuthToken, t as revokeActiveConnectionsForToken } from "../revoke-COLW0cOi.mjs";
2
- import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CK9LjrnT.mjs";
1
+ import { n as revokeAuthToken, t as revokeActiveConnectionsForToken } from "../revoke-cqztiCX4.mjs";
2
+ import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CeQQWzM-.mjs";
3
3
  export { buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,3 +1,3 @@
1
- import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-DftYyXaR.mjs";
2
- import { n as normalizeBasePath, r as resolveBasePath } from "../_shared-mtXpcJIv.mjs";
1
+ import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-rgBSPFHS.mjs";
2
+ import { i as resolveBasePath, r as normalizeBasePath } from "../_shared-CK3czkH4.mjs";
3
3
  export { type DevframeInternalContext, type InternalAnonymousAuthStorage, type RemoteTokenRecord, getInternalContext, internalContextMap, normalizeBasePath, resolveBasePath };
@@ -1,3 +1,3 @@
1
- import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-BM3PdYli.mjs";
2
- import { n as internalContextMap, t as getInternalContext } from "../context-KUqAfawQ.mjs";
1
+ import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-C08SdQRl.mjs";
2
+ import { n as internalContextMap, t as getInternalContext } from "../context-DIUvJW4D.mjs";
3
3
  export { getInternalContext, internalContextMap, normalizeBasePath, resolveBasePath };
@@ -1,6 +1,6 @@
1
- import "../index-BzyopqxV.mjs";
2
- import { v as RpcFunctionDefinitionAny } from "../types-CMdPYhOx.mjs";
3
- import { k as SharedState, l as RpcFunctionsHost, o as DevframeNodeContext, yt as DevframeHost } from "../context-CLF4-8Pp.mjs";
1
+ import "../index-pIVt92jP.mjs";
2
+ import { v as RpcFunctionDefinitionAny } from "../types-Dq4i156u.mjs";
3
+ import { bt as DevframeHost, k as SharedState, l as RpcFunctionsHost, o as DevframeNodeContext } from "../context-4AIVRLYF.mjs";
4
4
  import { BirpcGroup } from "birpc";
5
5
  //#region src/node/context.d.ts
6
6
  interface CreateHostContextOptions {
@@ -13,7 +13,7 @@ interface CreateHostContextOptions {
13
13
  * serves (from `DevframeDefinition.importMetaUrl`). Supplies the default
14
14
  * `resolveFrom` base for remote {@link DevframeViewHost.hostStatic} sources
15
15
  * that don't set one, so a locally installed copy of an assets package is
16
- * served with zero network. An internal plumbing detail — it isn't part of
16
+ * served with zero network. An internal plumbing detail; it isn't part of
17
17
  * the public {@link DevframeNodeContext} surface.
18
18
  */
19
19
  importMetaUrl?: string;
@@ -28,7 +28,7 @@ interface CreateHostContextOptions {
28
28
  * Framework- and build-tool-agnostic core of the Devframe node context.
29
29
  * Wires the RPC host, view (HTTP file-serving) host, diagnostics, and
30
30
  * agent subsystems. Host adapters can wrap this to augment `ctx` with
31
- * extra surfaces — for example, `@vitejs/devtools-kit`'s
31
+ * extra surfaces; for example, `@vitejs/devtools-kit`'s
32
32
  * `createKitContext` attaches `docks`, `terminals`, `messages`, and
33
33
  * `commands` when mounted into Vite DevTools.
34
34
  */
@@ -1,3 +1,3 @@
1
- import { t as createHostContext } from "../context-omlma_1n.mjs";
2
- import { t as createStorage } from "../storage-BXNVhKyR.mjs";
1
+ import { t as createHostContext } from "../context-CwPUinjn.mjs";
2
+ import { t as createStorage } from "../storage-Dccf_IyD.mjs";
3
3
  export { createHostContext, createStorage };
@@ -10,7 +10,7 @@ declare function devframeReporter(d: Diagnostic, { method }?: {
10
10
  method?: 'log' | 'warn' | 'error';
11
11
  }): void;
12
12
  /**
13
- * Options accepted by {@link defineDiagnostics} — identical to `nostics`'s
13
+ * Options accepted by {@link defineDiagnostics}, identical to `nostics`'s
14
14
  * own `DefineDiagnosticsOptions`, minus the reporter devframe already
15
15
  * prepends.
16
16
  */
@@ -20,7 +20,7 @@ type DevframeDefineDiagnosticsOptions<Codes extends Record<string, DiagnosticDef
20
20
  * ANSI console reporter pre-wired ahead of any `reporters` passed in. Every
21
21
  * `diagnostics.ts` in devframe core, `@devframes/hub`, `@devframes/json-render`,
22
22
  * and the built-in plugins defines its codes through this instead of
23
- * `nostics`'s own `defineDiagnostics` — the reporter registration lives
23
+ * `nostics`'s own `defineDiagnostics`; the reporter registration lives
24
24
  * here, once, so none of them need to build their own reporter (`colors`,
25
25
  * `ansiFormatter`) or take a direct dependency on `nostics` themselves.
26
26
  */
@@ -45,7 +45,7 @@ function devframeReporter(d, { method = "warn" } = {}) {
45
45
  * ANSI console reporter pre-wired ahead of any `reporters` passed in. Every
46
46
  * `diagnostics.ts` in devframe core, `@devframes/hub`, `@devframes/json-render`,
47
47
  * and the built-in plugins defines its codes through this instead of
48
- * `nostics`'s own `defineDiagnostics` — the reporter registration lives
48
+ * `nostics`'s own `defineDiagnostics`; the reporter registration lives
49
49
  * here, once, so none of them need to build their own reporter (`colors`,
50
50
  * `ansiFormatter`) or take a direct dependency on `nostics` themselves.
51
51
  */
@@ -0,0 +1,45 @@
1
+ //#region src/utils/origin.d.ts
2
+ /**
3
+ * Origin and hostname predicates shared by the RPC transports (the WS upgrade,
4
+ * SSE, and MCP origin gates) and the instance shell's authentication-link
5
+ * origin validation. Kept dependency-free and runtime-agnostic so any consumer
6
+ * can pull in a single check without dragging in a transport's `crossws`
7
+ * import.
8
+ */
9
+ /**
10
+ * Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
11
+ * subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
12
+ * `127.0.0.0/8` loopback block.
13
+ *
14
+ * The IPv4 case is matched **structurally**: the whole hostname must be a
15
+ * canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
16
+ * `startsWith('127.')` prefix check would also accept an attacker-controlled
17
+ * DNS name that merely *begins* with `127.` (`127.attacker.example`,
18
+ * `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
19
+ * the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
20
+ * cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
21
+ * genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
22
+ * those DNS names.
23
+ */
24
+ declare function isLoopbackHostname(hostname: string): boolean;
25
+ /**
26
+ * Default origin policy for a localhost dev tool: allow requests with no
27
+ * `Origin` header (native, non-browser clients), allow any loopback origin
28
+ * (so cross-port localhost dev setups keep working), and allow explicitly
29
+ * configured origins. Everything else, such as a real remote page in the dev's
30
+ * browser, is rejected.
31
+ */
32
+ declare function isAllowedOrigin(origin: string | undefined, allowedOrigins: readonly string[]): boolean;
33
+ /**
34
+ * Decide whether a request-derived origin candidate may back a devframe's
35
+ * advertised public origin, the destination of the OTP magic link. Stricter
36
+ * than {@link isAllowedOrigin}: it rejects credentials, a path, a query, a
37
+ * fragment, a malformed port, and non-HTTP(S) schemes, and adopts a candidate
38
+ * only when its hostname is loopback or its canonical origin exactly matches
39
+ * an `allowedOrigins` entry (a caller with no static list passes none, so only
40
+ * loopback qualifies). Returns the canonical origin to adopt, or `undefined`
41
+ * to reject. Forwarded headers are never consulted.
42
+ */
43
+ declare function validateOriginCandidate(candidate: string, allowedOrigins?: readonly string[]): string | undefined;
44
+ //#endregion
45
+ export { isLoopbackHostname as n, validateOriginCandidate as r, isAllowedOrigin as t };
@@ -0,0 +1,80 @@
1
+ //#region src/utils/origin.ts
2
+ /**
3
+ * Origin and hostname predicates shared by the RPC transports (the WS upgrade,
4
+ * SSE, and MCP origin gates) and the instance shell's authentication-link
5
+ * origin validation. Kept dependency-free and runtime-agnostic so any consumer
6
+ * can pull in a single check without dragging in a transport's `crossws`
7
+ * import.
8
+ */
9
+ /**
10
+ * Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
11
+ * subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
12
+ * `127.0.0.0/8` loopback block.
13
+ *
14
+ * The IPv4 case is matched **structurally**: the whole hostname must be a
15
+ * canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
16
+ * `startsWith('127.')` prefix check would also accept an attacker-controlled
17
+ * DNS name that merely *begins* with `127.` (`127.attacker.example`,
18
+ * `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
19
+ * the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
20
+ * cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
21
+ * genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
22
+ * those DNS names.
23
+ */
24
+ function isLoopbackHostname(hostname) {
25
+ const h = hostname.replace(/^\[|\]$/g, "");
26
+ if (h === "localhost" || h.endsWith(".localhost") || h === "::1") return true;
27
+ return isLoopbackIPv4(h);
28
+ }
29
+ /** A canonical dotted-decimal IPv4 literal in `127.0.0.0/8`. */
30
+ function isLoopbackIPv4(hostname) {
31
+ const octets = hostname.split(".");
32
+ if (octets.length !== 4 || !octets.every(isDecimalOctet)) return false;
33
+ return Number(octets[0]) === 127;
34
+ }
35
+ /** A single canonical IPv4 octet: 1–3 digits, no leading zero, value 0–255. */
36
+ function isDecimalOctet(part) {
37
+ if (!/^\d{1,3}$/.test(part) || part.length > 1 && part[0] === "0") return false;
38
+ return Number(part) <= 255;
39
+ }
40
+ /**
41
+ * Default origin policy for a localhost dev tool: allow requests with no
42
+ * `Origin` header (native, non-browser clients), allow any loopback origin
43
+ * (so cross-port localhost dev setups keep working), and allow explicitly
44
+ * configured origins. Everything else, such as a real remote page in the dev's
45
+ * browser, is rejected.
46
+ */
47
+ function isAllowedOrigin(origin, allowedOrigins) {
48
+ if (!origin) return true;
49
+ if (allowedOrigins.includes(origin)) return true;
50
+ try {
51
+ return isLoopbackHostname(new URL(origin).hostname);
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Decide whether a request-derived origin candidate may back a devframe's
58
+ * advertised public origin, the destination of the OTP magic link. Stricter
59
+ * than {@link isAllowedOrigin}: it rejects credentials, a path, a query, a
60
+ * fragment, a malformed port, and non-HTTP(S) schemes, and adopts a candidate
61
+ * only when its hostname is loopback or its canonical origin exactly matches
62
+ * an `allowedOrigins` entry (a caller with no static list passes none, so only
63
+ * loopback qualifies). Returns the canonical origin to adopt, or `undefined`
64
+ * to reject. Forwarded headers are never consulted.
65
+ */
66
+ function validateOriginCandidate(candidate, allowedOrigins) {
67
+ let url;
68
+ try {
69
+ url = new URL(candidate);
70
+ } catch {
71
+ return;
72
+ }
73
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
74
+ if (url.username || url.password || url.search || url.hash || url.pathname !== "/" && url.pathname !== "") return void 0;
75
+ const canonical = url.origin;
76
+ if (canonical === "null") return void 0;
77
+ if (isLoopbackHostname(url.hostname) || allowedOrigins?.includes(canonical)) return canonical;
78
+ }
79
+ //#endregion
80
+ export { isLoopbackHostname as n, validateOriginCandidate as r, isAllowedOrigin as t };
@@ -1,6 +1,6 @@
1
- import "../index-BzyopqxV.mjs";
2
- import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-CMdPYhOx.mjs";
3
- import "../context-CLF4-8Pp.mjs";
1
+ import "../index-pIVt92jP.mjs";
2
+ import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-Dq4i156u.mjs";
3
+ import "../context-4AIVRLYF.mjs";
4
4
  import { SimpleSchema } from "../utils/simple-schema.mjs";
5
5
  //#region src/recipes/common-rpc-functions.d.ts
6
6
  /**
@@ -34,7 +34,7 @@ declare const KNOWN_EDITORS: KnownEditor[];
34
34
  * })
35
35
  * ```
36
36
  *
37
- * @deprecated Use the `@devframes/service-open` wire service instead — one
37
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
38
38
  * host-level installation shared by every plugin and feature-detectable from
39
39
  * clients, with workspace-root path containment on top of the editor gating.
40
40
  */
@@ -64,7 +64,7 @@ declare const openInEditor: {
64
64
  * ctx.rpc.register(openInFinder)
65
65
  * ```
66
66
  *
67
- * @deprecated Use the `@devframes/service-open` wire service instead — one
67
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
68
68
  * host-level installation shared by every plugin and feature-detectable from
69
69
  * clients, with workspace-root path containment.
70
70
  */
@@ -1,5 +1,5 @@
1
1
  import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs";
2
- import { t as s } from "../simple-schema-DQPZrAaZ.mjs";
2
+ import { t as s } from "../simple-schema-Bi40l-P6.mjs";
3
3
  //#region src/recipes/common-rpc-functions.ts
4
4
  /** Runtime list of every {@link KnownEditor}. */
5
5
  const KNOWN_EDITORS = [
@@ -57,7 +57,7 @@ const KNOWN_EDITORS = [
57
57
  * })
58
58
  * ```
59
59
  *
60
- * @deprecated Use the `@devframes/service-open` wire service instead — one
60
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
61
61
  * host-level installation shared by every plugin and feature-detectable from
62
62
  * clients, with workspace-root path containment on top of the editor gating.
63
63
  */
@@ -83,7 +83,7 @@ const openInEditor = defineRpcFunction({
83
83
  * ctx.rpc.register(openInFinder)
84
84
  * ```
85
85
  *
86
- * @deprecated Use the `@devframes/service-open` wire service instead — one
86
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
87
87
  * host-level installation shared by every plugin and feature-detectable from
88
88
  * clients, with workspace-root path containment.
89
89
  */
@@ -1,9 +1,9 @@
1
- import { Ct as DevframeAuthHandler, o as DevframeNodeContext, s as DevframeNodeRpcSession } from "../context-CLF4-8Pp.mjs";
2
- import "../index-D3k0BIhe.mjs";
1
+ import { o as DevframeNodeContext, s as DevframeNodeRpcSession, wt as DevframeAuthHandler } from "../context-4AIVRLYF.mjs";
2
+ import "../index-pKl67H6w.mjs";
3
3
  //#region src/recipes/interactive-auth.d.ts
4
4
  interface CreateInteractiveAuthOptions {
5
5
  /**
6
- * Static, pre-shared bearer tokens that are always trusted — for CI runs
6
+ * Static, pre-shared bearer tokens that are always trusted, for CI runs
7
7
  * or shared machines where the interactive code prompt would only get in
8
8
  * the way. Checked in both the handshake handler and the connect-time
9
9
  * hook, alongside tokens minted by a real code exchange.
@@ -11,7 +11,7 @@ interface CreateInteractiveAuthOptions {
11
11
  clientAuthTokens?: string[];
12
12
  /**
13
13
  * Print the current code + magic-link URL. Devframe stays headless, so
14
- * there is no default banner printed automatically — call
14
+ * there is no default banner printed automatically; call
15
15
  * `auth.printBanner()` yourself once the server is listening. Override
16
16
  * this to customize the format; defaults to a small boxed message on
17
17
  * stdout.
@@ -41,10 +41,10 @@ interface CreateInteractiveAuthOptions {
41
41
  * Package the interactive OTP auth protocol devframe's primitives
42
42
  * (`exchangeTempAuthCode`, `verifyAuthToken`, `revokeAuthToken`,
43
43
  * `getTempAuthCode`, `buildOtpAuthUrl`) implement into a ready-made
44
- * {@link DevframeAuthHandler} — the handshake RPC functions, the resolver
44
+ * {@link DevframeAuthHandler}: the handshake RPC functions, the resolver
45
45
  * gate, the connect-time trust hook, and the startup banner.
46
46
  *
47
- * The auth storage stays internal to this handler — callers never reach into
47
+ * The auth storage stays internal to this handler; callers never reach into
48
48
  * `devframe/node/hub-internals` themselves.
49
49
  *
50
50
  * ```ts
@@ -1,9 +1,9 @@
1
- import { s as colors } from "../nostics-CzECRXpE.mjs";
1
+ import { s as colors } from "../nostics-D0PvLZsn.mjs";
2
2
  import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs";
3
3
  import { isAnonymousRpcMethod } from "../constants.mjs";
4
- import { a as verifyAuthToken, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CK9LjrnT.mjs";
5
- import { t as getInternalContext } from "../context-KUqAfawQ.mjs";
6
- import { t as s } from "../simple-schema-DQPZrAaZ.mjs";
4
+ import { a as verifyAuthToken, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CeQQWzM-.mjs";
5
+ import { t as getInternalContext } from "../context-DIUvJW4D.mjs";
6
+ import { t as s } from "../simple-schema-Bi40l-P6.mjs";
7
7
  //#region src/recipes/interactive-auth.ts
8
8
  function defaultBanner(info) {
9
9
  console.log(`\n ${colors.dim("devframe auth code")} ${colors.bold(info.code)}\n ${colors.dim("or open")} ${colors.cyan(info.url)}\n`);
@@ -12,10 +12,10 @@ function defaultBanner(info) {
12
12
  * Package the interactive OTP auth protocol devframe's primitives
13
13
  * (`exchangeTempAuthCode`, `verifyAuthToken`, `revokeAuthToken`,
14
14
  * `getTempAuthCode`, `buildOtpAuthUrl`) implement into a ready-made
15
- * {@link DevframeAuthHandler} — the handshake RPC functions, the resolver
15
+ * {@link DevframeAuthHandler}: the handshake RPC functions, the resolver
16
16
  * gate, the connect-time trust hook, and the startup banner.
17
17
  *
18
- * The auth storage stays internal to this handler — callers never reach into
18
+ * The auth storage stays internal to this handler; callers never reach into
19
19
  * `devframe/node/hub-internals` themselves.
20
20
  *
21
21
  * ```ts
@@ -1,8 +1,8 @@
1
- import { t as diagnostics } from "./diagnostics-BXWW3VK-.mjs";
1
+ import { t as diagnostics } from "./diagnostics-BMfN8mb1.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { isatty } from "node:tty";
4
4
  import { formatWithOptions, inspect } from "node:util";
5
- import { dirname, extname, join, normalize, sep } from "pathe";
5
+ import { dirname, extname, isAbsolute, join, normalize, resolve, sep } from "pathe";
6
6
  import { createReadStream, existsSync } from "node:fs";
7
7
  import { Buffer } from "node:buffer";
8
8
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -302,7 +302,7 @@ const MANIFEST_FILENAME = ".manifest.json";
302
302
  * list is dropped, because it describes the *provider's* transfer rather than
303
303
  * the file: hop-by-hop and encoding headers no longer match the body `fetch`
304
304
  * already decoded, and a CDN's policy headers (`set-cookie`, `cache-control`,
305
- * framing/CSP) belong to its origin — replaying them under the dev server's
305
+ * framing/CSP) belong to its origin, so replaying them under the dev server's
306
306
  * origin could just as well break the iframe these assets render in.
307
307
  */
308
308
  const PROXIED_HEADERS = [
@@ -436,6 +436,24 @@ function candidatePaths(prefix, cleaned) {
436
436
  if (!/\.[a-z0-9]+$/i.test(cleaned) && !candidates.includes(`${prefix}index.html`)) candidates.push(`${prefix}index.html`);
437
437
  return candidates;
438
438
  }
439
+ /**
440
+ * Resolve the safe destination for a provider-listed `filePath` beneath
441
+ * `prefix`, materializing into the already-resolved `root`, or `null` when
442
+ * the entry is unsafe or lies outside the selected `prefix`. A compromised
443
+ * provider is an untrusted boundary even though the built-in jsDelivr/unpkg
444
+ * listings never emit any of this: reject an absolute path, a backslash
445
+ * (never normalized into a separator; Windows-style traversal stays rejected
446
+ * on every platform), and any suffix whose resolved destination would land
447
+ * outside `root`. `target === root` is deliberately unsafe too: it names the
448
+ * directory itself, never a writable file.
449
+ */
450
+ function materializeTarget(filePath, prefix, root) {
451
+ if (filePath.includes("\\") || isAbsolute(filePath) || !filePath.startsWith(prefix)) return null;
452
+ const suffix = filePath.slice(prefix.length);
453
+ if (!suffix || isAbsolute(suffix)) return null;
454
+ const target = resolve(root, suffix);
455
+ return target === root || !target.startsWith(root + sep) ? null : target;
456
+ }
439
457
  function createStore(assets, cacheDir) {
440
458
  const normalized = {
441
459
  ...assets,
@@ -582,8 +600,10 @@ function createStore(assets, cacheDir) {
582
600
  } catch (error) {
583
601
  return fail(errText(error), error);
584
602
  }
585
- for (const filePath of files.filter((f) => f.startsWith(prefix))) {
586
- const target = join(targetDir, filePath.slice(prefix.length));
603
+ const root = resolve(targetDir);
604
+ for (const filePath of files) {
605
+ const target = materializeTarget(filePath, prefix, root);
606
+ if (target == null) continue;
587
607
  const url = provider.fileUrl(normalized.package, normalized.version, filePath);
588
608
  let res;
589
609
  try {
@@ -625,7 +645,7 @@ function assertValidRemoteAssets(assets) {
625
645
  * {@link RemoteAssetsStore} back-proxy. Remote caches live under
626
646
  * `<projectStorageDir>/.remote-assets/<package>@<version>/`.
627
647
  *
628
- * A remote source's `package`/`version` are validated first (`DF0065`) — both
648
+ * A remote source's `package`/`version` are validated first (`DF0065`); both
629
649
  * are interpolated into CDN URLs and the cache path.
630
650
  *
631
651
  * `defaultResolveFrom` (typically the declaring devframe's `importMetaUrl`)