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,12 +1,12 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.mjs";
2
2
  import { createRpcServer } from "./rpc/server.mjs";
3
- import { t as diagnostics } from "./diagnostics-BXWW3VK-.mjs";
3
+ import { t as diagnostics } from "./diagnostics-BMfN8mb1.mjs";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  //#region src/node/rpc-core.ts
6
6
  var rpc_core_exports = /* @__PURE__ */ __exportAll({ createContextRpcServer: () => createContextRpcServer });
7
7
  /**
8
8
  * Bind a devframe context's registered RPC functions to a birpc group,
9
- * transport-agnostically — the shared core under the instance shell's own
9
+ * transport-agnostically: the shared core under the instance shell's own
10
10
  * HTTP+WS binding (Node http + WS) and the Bun fetch-upgrade tier of
11
11
  * `createHandler`.
12
12
  *
@@ -26,8 +26,20 @@ function createContextRpcServer(options) {
26
26
  for (const fn of authHandler.rpcFunctions) if (!rpcHost.definitions.has(fn.name)) rpcHost.register(fn);
27
27
  }
28
28
  const rpcGroup = createRpcServer(rpcHost.functions, { rpcOptions: {
29
+ /**
30
+ * Forwarded as-is so a host with its own structured diagnostics
31
+ * keeps seeing RPC failures.
32
+ */
29
33
  onFunctionError: options.rpcOptions?.onFunctionError,
30
34
  onGeneralError: options.rpcOptions?.onGeneralError,
35
+ /**
36
+ * Wrap each RPC handler in an AsyncLocalStorage context so
37
+ * `ctx.rpc.getCurrentRpcSession()` works inside handlers (used
38
+ * by streaming subscribe/unsubscribe/cancel and shared-state
39
+ * sync), and (when an `authorize` gate is configured) reject
40
+ * the call before it ever reaches the handler. Mirrors
41
+ * `packages/core/src/node/ws.ts`'s resolver.
42
+ */
31
43
  resolver(name, fn) {
32
44
  const rpc = this;
33
45
  if (!fn) return void 0;
@@ -1,4 +1,4 @@
1
- import { t as diagnostics } from "./diagnostics-CD8nlgll.mjs";
1
+ import { t as diagnostics } from "./diagnostics-D0EVm5M6.mjs";
2
2
  //#region src/rpc/serialization.ts
3
3
  /**
4
4
  * Wire format used by the live RPC transports (WebSocket and SSE).
@@ -14,7 +14,7 @@ import { t as diagnostics } from "./diagnostics-CD8nlgll.mjs";
14
14
  *
15
15
  * birpc envelopes always start with `{`, so a leading byte that is not
16
16
  * `s` is unambiguously JSON. Each direction independently chooses its
17
- * encoding from local definitions — request and response are not
17
+ * encoding from local definitions; request and response are not
18
18
  * coupled by a mirror rule.
19
19
  */
20
20
  const STRUCTURED_CLONE_PREFIX = "s:";
@@ -26,16 +26,16 @@ const STRUCTURED_CLONE_PREFIX = "s:";
26
26
  * instances, or `undefined` inside an array (silently becomes `null`).
27
27
  *
28
28
  * Native pass-throughs (no extra work needed):
29
- * - circular references — `JSON.stringify` raises `TypeError`.
30
- * - `BigInt` at top level — caught here for a friendlier error path.
29
+ * - circular references: `JSON.stringify` raises `TypeError`.
30
+ * - `BigInt` at top level: caught here for a friendlier error path.
31
31
  *
32
32
  * Lenient cases (allowed without throwing):
33
- * - `undefined` as an object property — legitimate optional field;
33
+ * - `undefined` as an object property: legitimate optional field;
34
34
  * JSON.stringify just omits it.
35
- * - `undefined` at the root — legitimate "action returned nothing".
36
- * - `Symbol` / `Function` values — semantically "drop me" in JSON.
35
+ * - `undefined` at the root: legitimate "action returned nothing".
36
+ * - `Symbol` / `Function` values: semantically "drop me" in JSON.
37
37
  *
38
- * `fnName` is used only for the diagnostic message — pass the RPC
38
+ * `fnName` is used only for the diagnostic message; pass the RPC
39
39
  * function name when calling from a wire serializer / dump writer so
40
40
  * the error points at the offending function.
41
41
  */
@@ -47,19 +47,21 @@ function strictJsonStringify(value, fnName = "") {
47
47
  if (Array.isArray(holder)) throw nonJsonAt(fnName, "undefined", holder, key);
48
48
  return val;
49
49
  }
50
- if (original === null) return val;
51
- if (typeof original === "bigint") throw nonJsonAt(fnName, "BigInt", holder, key);
52
- if (typeof original === "object") {
53
- if (original instanceof Map) throw nonJsonAt(fnName, "Map", holder, key);
54
- if (original instanceof Set) throw nonJsonAt(fnName, "Set", holder, key);
55
- if (original instanceof Date) throw nonJsonAt(fnName, "Date", holder, key);
56
- if (Array.isArray(original)) return val;
57
- const proto = Object.getPrototypeOf(original);
58
- if (proto !== null && proto !== Object.prototype) throw nonJsonAt(fnName, original.constructor?.name ?? "class instance", holder, key);
59
- }
50
+ if (original !== null) assertJsonSafe(original, holder, key, fnName);
60
51
  return val;
61
52
  });
62
53
  }
54
+ /** Throw `DF0020` when `original` is a type JSON can't round-trip losslessly. */
55
+ function assertJsonSafe(original, holder, key, fnName) {
56
+ if (typeof original === "bigint") throw nonJsonAt(fnName, "BigInt", holder, key);
57
+ if (typeof original !== "object") return;
58
+ if (original instanceof Map) throw nonJsonAt(fnName, "Map", holder, key);
59
+ if (original instanceof Set) throw nonJsonAt(fnName, "Set", holder, key);
60
+ if (original instanceof Date) throw nonJsonAt(fnName, "Date", holder, key);
61
+ if (Array.isArray(original)) return;
62
+ const proto = Object.getPrototypeOf(original);
63
+ if (proto !== null && proto !== Object.prototype) throw nonJsonAt(fnName, original.constructor?.name ?? "class instance", holder, key);
64
+ }
63
65
  function nonJsonAt(fnName, type, parent, key) {
64
66
  const path = formatPath(parent, key);
65
67
  return diagnostics.DF0020({
@@ -1,5 +1,5 @@
1
- import { t as DEVFRAME_EVENTS } from "./events-4daw0uK9.mjs";
2
- import { t as diagnostics } from "./diagnostics-BXWW3VK-.mjs";
1
+ import { t as DEVFRAME_EVENTS } from "./events-BV4Dj59a.mjs";
2
+ import { t as diagnostics } from "./diagnostics-BMfN8mb1.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { isAbsolute, join } from "pathe";
@@ -219,6 +219,12 @@ var DevframeAgentHost = class {
219
219
  description: input.description,
220
220
  safety: input.safety ?? "action",
221
221
  tags: input.tags,
222
+ /**
223
+ * Standard Schema `args` are carried raw (mirroring how an RPC-backed
224
+ * tool defers to `ctx.rpc.definitions`); consumers (the MCP adapter)
225
+ * convert to JSON Schema on demand. An explicit `inputSchema` override
226
+ * wins when given.
227
+ */
222
228
  args: input.args,
223
229
  inputSchema: input.inputSchema,
224
230
  outputSchema: input.outputSchema,
@@ -268,7 +274,7 @@ function inferSafety(type) {
268
274
  //#region src/node/services-install.ts
269
275
  /**
270
276
  * Turn a `resolveFrom` value (a file path, a file URL like `import.meta.url`,
271
- * or a directory) into something `createRequire` accepts — a directory gets a
277
+ * or a directory) into something `createRequire` accepts; a directory gets a
272
278
  * synthetic filename appended so resolution starts inside it.
273
279
  */
274
280
  function toRequireBase(resolveFrom) {
@@ -341,6 +347,24 @@ function compareVersions(a, b) {
341
347
  if (a.prerelease && b.prerelease) return a.prerelease < b.prerelease ? -1 : a.prerelease > b.prerelease ? 1 : 0;
342
348
  return 0;
343
349
  }
350
+ /** Whether `version` and `base` share their first `lockUpTo + 1` parts. */
351
+ function partsMatchUpTo(version, base, lockUpTo) {
352
+ for (let i = 0; i <= lockUpTo; i++) if ((version.parts[i] ?? 0) !== (base.parts[i] ?? 0)) return false;
353
+ return true;
354
+ }
355
+ function satisfiesCaret(version, base) {
356
+ if (compareVersions(version, base) < 0) return false;
357
+ const fixedIndex = base.parts.findIndex((part) => part !== 0);
358
+ return partsMatchUpTo(version, base, fixedIndex === -1 ? base.parts.length - 1 : fixedIndex);
359
+ }
360
+ function satisfiesTilde(version, base, segments) {
361
+ if (compareVersions(version, base) < 0) return false;
362
+ return partsMatchUpTo(version, base, segments.length >= 2 ? 1 : 0);
363
+ }
364
+ function satisfiesExactOrPrefix(version, base, segments) {
365
+ for (let i = 0; i < Math.max(segments.length, 3); i++) if (i < segments.length && (version.parts[i] ?? 0) !== (base.parts[i] ?? 0)) return false;
366
+ return segments.length >= 3 ? compareVersions(version, base) === 0 : true;
367
+ }
344
368
  function satisfiesComparator(version, comparator) {
345
369
  const raw = comparator.trim();
346
370
  if (!raw || raw === "*" || raw === "x") return true;
@@ -356,26 +380,13 @@ function satisfiesComparator(version, comparator) {
356
380
  case ">=": return compareVersions(version, base) >= 0;
357
381
  case "<": return compareVersions(version, base) < 0;
358
382
  case "<=": return compareVersions(version, base) <= 0;
359
- case "^": {
360
- if (compareVersions(version, base) < 0) return false;
361
- const fixedIndex = base.parts.findIndex((part) => part !== 0);
362
- const lockUpTo = fixedIndex === -1 ? base.parts.length - 1 : fixedIndex;
363
- for (let i = 0; i <= lockUpTo; i++) if ((version.parts[i] ?? 0) !== (base.parts[i] ?? 0)) return false;
364
- return true;
365
- }
366
- case "~": {
367
- if (compareVersions(version, base) < 0) return false;
368
- const lockUpTo = segments.length >= 2 ? 1 : 0;
369
- for (let i = 0; i <= lockUpTo; i++) if ((version.parts[i] ?? 0) !== (base.parts[i] ?? 0)) return false;
370
- return true;
371
- }
372
- default:
373
- for (let i = 0; i < Math.max(segments.length, 3); i++) if (i < segments.length && (version.parts[i] ?? 0) !== (base.parts[i] ?? 0)) return false;
374
- return segments.length >= 3 ? compareVersions(version, base) === 0 : true;
383
+ case "^": return satisfiesCaret(version, base);
384
+ case "~": return satisfiesTilde(version, base, segments);
385
+ default: return satisfiesExactOrPrefix(version, base, segments);
375
386
  }
376
387
  }
377
388
  /**
378
- * Pragmatic semver range check for service version declarations — supports
389
+ * Pragmatic semver range check for service version declarations; supports
379
390
  * the common forms (`1.2.3`, `^1.2.3`, `~1.2`, `>=1 <3`, `1.x`, `*`, and
380
391
  * `||`-joined alternatives) without pulling in a semver dependency. An
381
392
  * unparseable version or range reads as **not satisfied**.
@@ -402,7 +413,7 @@ function deepMergeTwo(a, b) {
402
413
  }
403
414
  /**
404
415
  * Default option-set merge when a service declares no `mergeOptions`:
405
- * deep-merge in declaration order — objects recurse, arrays union-dedupe,
416
+ * deep-merge in declaration order: objects recurse, arrays union-dedupe,
406
417
  * scalars take the later value. Covers the built-in services (`roots` /
407
418
  * `langs` union, `themes` per-key last-wins) without a custom hook.
408
419
  */
@@ -0,0 +1,16 @@
1
+ //#region src/rpc/transports/session.ts
2
+ let sessionId = 0;
3
+ /**
4
+ * Mint the per-connection session meta every transport binding shares:
5
+ * one id space across transports, so session bookkeeping (streaming
6
+ * subscriptions, shared-state sync, auth trust) never collides between a
7
+ * WS peer and an SSE session on the same server.
8
+ */
9
+ function createRpcSessionMeta() {
10
+ return {
11
+ id: sessionId++,
12
+ subscribedStates: /* @__PURE__ */ new Set()
13
+ };
14
+ }
15
+ //#endregion
16
+ export { createRpcSessionMeta as t };
@@ -931,8 +931,8 @@ function createSharedState(options) {
931
931
  if (syncIds.has(syncId)) return;
932
932
  rememberSyncId(syncIds, syncId);
933
933
  if (enablePatches$1) {
934
- const [newState, patches] = produceWithPatches(state, fn);
935
- state = newState;
934
+ const [nextState, patches] = produceWithPatches(state, fn);
935
+ state = nextState;
936
936
  events.emit("updated", state, patches, syncId);
937
937
  } else {
938
938
  state = produce(state, fn);
@@ -37,7 +37,7 @@ function number() {
37
37
  function boolean() {
38
38
  return make("boolean", (v) => typeof v === "boolean" ? ok(v) : fail("Expected a boolean"));
39
39
  }
40
- /** `undefined` — mirrors valibot's `void`. */
40
+ /** `undefined`, mirroring valibot's `void`. */
41
41
  function voidType() {
42
42
  return make("void", (v) => v === void 0 ? ok(void 0) : fail("Expected undefined"));
43
43
  }
@@ -130,7 +130,7 @@ function describe(schema, description) {
130
130
  };
131
131
  }
132
132
  /**
133
- * Grouped access to every builder — `s.string()`, `s.object({ ... })`,
133
+ * Grouped access to every builder: `s.string()`, `s.object({ ... })`,
134
134
  * `s.void()`, etc. Handy for a valibot-like `import { s } from
135
135
  * 'devframe/utils/simple-schema'` call site.
136
136
  */
@@ -1,4 +1,4 @@
1
- import { v as RpcFunctionDefinitionAny } from "./types-CMdPYhOx.mjs";
1
+ import { v as RpcFunctionDefinitionAny } from "./types-Dq4i156u.mjs";
2
2
  import { ChannelOptions } from "birpc";
3
3
  //#region src/rpc/transports/sse-client.d.ts
4
4
  interface SseRpcChannelOptions {
@@ -10,7 +10,7 @@ interface SseRpcChannelOptions {
10
10
  authToken?: string;
11
11
  /**
12
12
  * RPC function definitions (or just the `jsonSerializable` flag per
13
- * method) used to dispatch the per-call wire serializer — same contract
13
+ * method) used to dispatch the per-call wire serializer, the same contract
14
14
  * as the WS channel.
15
15
  */
16
16
  definitions?: ReadonlyMap<string, Pick<RpcFunctionDefinitionAny, 'jsonSerializable'>>;
@@ -19,7 +19,7 @@ interface SseRpcChannelOptions {
19
19
  }
20
20
  /**
21
21
  * Build a birpc `ChannelOptions` object backed by an SSE stream (server →
22
- * client) and HTTP `POST` (client → server) — the WebSocket-free counterpart
22
+ * client) and HTTP `POST` (client → server): the WebSocket-free counterpart
23
23
  * to `createWsRpcChannel`, wire-compatible with `attachSseRpcTransport`.
24
24
  *
25
25
  * The stream is consumed via `fetch` streaming (not `EventSource`), so it
@@ -27,7 +27,7 @@ interface SseRpcChannelOptions {
27
27
  * (`event: session`) carries the session id; every `POST` echoes it in the
28
28
  * `x-birpc-session` header. A response to a client-initiated request comes
29
29
  * back in the `POST`'s own body and is re-injected into the channel; a
30
- * dropped stream terminates the channel — there is no reconnect, matching
30
+ * dropped stream terminates the channel; there is no reconnect, matching
31
31
  * the WS channel's closed-is-done semantics.
32
32
  */
33
33
  declare function createSseRpcChannel(options: SseRpcChannelOptions): ChannelOptions & {
@@ -1,5 +1,5 @@
1
1
  import { DEVFRAME_OTP_URL_PARAM } from "./constants.mjs";
2
- import { n as randomToken, r as timingSafeEqual, t as randomDigits } from "./crypto-token-XCqTSMg9.mjs";
2
+ import { n as randomToken, r as timingSafeEqual, t as randomDigits } from "./crypto-token-TVbGGFuj.mjs";
3
3
  //#region ../../node_modules/.pnpm/ua-parser-modern@0.1.1/node_modules/ua-parser-modern/dist/index.mjs
4
4
  const EMPTY = "";
5
5
  const UNKNOWN = "?";
@@ -1169,7 +1169,7 @@ function parseUA(uastringOrExtensions, extensions) {
1169
1169
  *
1170
1170
  * The client used to parse+format this itself, but that pulled
1171
1171
  * `ua-parser-modern` into the browser bundle for a label nothing else on
1172
- * the client needs — the client now sends the raw string and parsing
1172
+ * the client needs; the client now sends the raw string and parsing
1173
1173
  * happens here, at the server ingress, keeping the persisted label format
1174
1174
  * identical.
1175
1175
  */
@@ -1221,13 +1221,13 @@ function refreshTempAuthCode() {
1221
1221
  }
1222
1222
  /**
1223
1223
  * Build a "magic link" authentication URL that embeds a one-time code (OTP) in
1224
- * the URL **fragment**. Opening it authenticates the client without typing —
1224
+ * the URL **fragment**. Opening it authenticates the client without typing;
1225
1225
  * print it on startup (devframe stays headless, so the host prints its own
1226
1226
  * banner). Defaults to the current code; the link is subject to the same TTL.
1227
1227
  *
1228
1228
  * The code rides the fragment (`#devframe_otp=…`), not the query string, so it
1229
1229
  * is never sent to the server, written to an access log, or leaked in a
1230
- * `Referer` header — the browser client reads it locally (see
1230
+ * `Referer` header; the browser client reads it locally (see
1231
1231
  * `consumeOtpFromUrl`). Any existing fragment parameters are preserved.
1232
1232
  */
1233
1233
  function buildOtpAuthUrl(baseUrl, code = tempAuthCode) {
@@ -1,5 +1,5 @@
1
- import { n as validateDefinitions, r as getRpcHandler, s as hash } from "./validation-YrZH6atx.mjs";
2
- import { t as diagnostics } from "./diagnostics-CD8nlgll.mjs";
1
+ import { n as validateDefinitions, r as getRpcHandler, s as hash } from "./validation-BOy8IoFZ.mjs";
2
+ import { t as diagnostics } from "./diagnostics-D0EVm5M6.mjs";
3
3
  import { DEVFRAME_RPC_DUMP_DIRNAME } from "./constants.mjs";
4
4
  //#region ../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
5
5
  var Node = class {
@@ -156,9 +156,9 @@ function serializeWithSeen(error, seen) {
156
156
  };
157
157
  const cause = error.cause;
158
158
  if (cause !== void 0) out.cause = cause instanceof Error ? serializeWithSeen(cause, seen) : cause;
159
- for (const key of Object.keys(error)) {
159
+ for (const [key, value] of Object.entries(error)) {
160
160
  if (key === "name" || key === "message" || key === "cause") continue;
161
- out[key] = error[key];
161
+ out[key] = value;
162
162
  }
163
163
  return out;
164
164
  }
@@ -168,13 +168,11 @@ function serializeWithSeen(error, seen) {
168
168
  * the original `name`, and re-attaches any custom own properties.
169
169
  */
170
170
  function reviveDumpError(stored) {
171
- const cause = stored.cause instanceof Error ? stored.cause : isPlainErrorShape(stored.cause) ? reviveDumpError(stored.cause) : stored.cause;
172
- const error = cause !== void 0 ? new Error(stored.message, { cause }) : new Error(stored.message);
173
- error.name = stored.name;
174
- for (const key of Object.keys(stored)) {
175
- if (key === "name" || key === "message" || key === "cause") continue;
176
- error[key] = stored[key];
177
- }
171
+ const { name, message, cause: rawCause, ...extras } = stored;
172
+ const cause = rawCause instanceof Error ? rawCause : isPlainErrorShape(rawCause) ? reviveDumpError(rawCause) : rawCause;
173
+ const error = cause !== void 0 ? new Error(message, { cause }) : new Error(message);
174
+ error.name = name;
175
+ Object.assign(error, extras);
178
176
  return error;
179
177
  }
180
178
  function isPlainErrorShape(value) {
@@ -191,15 +189,77 @@ function getDumpFallbackKey(functionName) {
191
189
  async function resolveGetter(valueOrGetter) {
192
190
  return typeof valueOrGetter === "function" ? await valueOrGetter() : valueOrGetter;
193
191
  }
192
+ /** Run tasks sequentially (`concurrency <= 1`) or through a `p-limit` pool. */
193
+ async function runDumpTasks(tasks, concurrency) {
194
+ if (concurrency <= 1) {
195
+ const out = [];
196
+ for (const task of tasks) out.push(await task());
197
+ return out;
198
+ }
199
+ const limit = pLimit(concurrency);
200
+ return Promise.all(tasks.map((task) => limit(task)));
201
+ }
194
202
  /**
195
- * Collects pre-computed dumps by executing functions with their defined input combinations.
196
- * Static functions without dump config automatically get `{ inputs: [[]] }`.
197
- *
198
- * @example
199
- * ```ts
200
- * const store = await dumpFunctions([greet], context, { concurrency: 10 })
201
- * ```
203
+ * Resolve one definition's handler + dump config and register it in the store.
204
+ * Returns `undefined` for definitions that carry no dump.
202
205
  */
206
+ async function resolveDumpTask(definition, context, store) {
207
+ if (definition.type === "event" || definition.type === "action") return void 0;
208
+ const setupResult = definition.setup ? await Promise.resolve(definition.setup(context)) : {};
209
+ const handler = setupResult.handler || definition.handler;
210
+ if (!handler) throw diagnostics.DF0024({ name: definition.name });
211
+ let dump = setupResult.dump ?? definition.dump;
212
+ if (!dump && definition.type === "static") dump = { inputs: [[]] };
213
+ if (!dump && definition.snapshot) dump = async (_ctx, h) => {
214
+ const output = await Promise.resolve(h());
215
+ return {
216
+ records: [{
217
+ inputs: [],
218
+ output
219
+ }],
220
+ fallback: output
221
+ };
222
+ };
223
+ if (!dump) return void 0;
224
+ if (typeof dump === "function") dump = await Promise.resolve(dump(context, handler));
225
+ store.definitions[definition.name] = {
226
+ name: definition.name,
227
+ type: definition.type
228
+ };
229
+ return {
230
+ handler,
231
+ dump,
232
+ definition
233
+ };
234
+ }
235
+ /**
236
+ * Write a resolved dump's pre-defined records and fallback into the store, and
237
+ * return the per-input execution tasks that fill in the rest.
238
+ */
239
+ function collectDumpTasks(resolution, store) {
240
+ const { definition, handler, dump } = resolution;
241
+ const { inputs, records, fallback } = dump;
242
+ if (records) for (const record of records) store.records[getDumpRecordKey(definition.name, record.inputs)] = record;
243
+ if ("fallback" in dump) store.records[getDumpFallbackKey(definition.name)] = {
244
+ inputs: [],
245
+ output: fallback
246
+ };
247
+ if (!inputs) return [];
248
+ return inputs.map((input) => async () => {
249
+ const recordKey = getDumpRecordKey(definition.name, input);
250
+ try {
251
+ store.records[recordKey] = {
252
+ inputs: input,
253
+ output: await Promise.resolve(handler(...input))
254
+ };
255
+ } catch (error) {
256
+ store.records[recordKey] = {
257
+ inputs: input,
258
+ error: serializeDumpError(error)
259
+ };
260
+ }
261
+ });
262
+ }
203
263
  async function dumpFunctions(definitions, context, options = {}) {
204
264
  validateDefinitions(definitions);
205
265
  const concurrency = options.concurrency === true ? 5 : options.concurrency === false || options.concurrency == null ? 1 : options.concurrency;
@@ -207,79 +267,7 @@ async function dumpFunctions(definitions, context, options = {}) {
207
267
  definitions: {},
208
268
  records: {}
209
269
  };
210
- const tasksResolutions = definitions.map((definition) => async () => {
211
- if (definition.type === "event" || definition.type === "action") return;
212
- const setupResult = definition.setup ? await Promise.resolve(definition.setup(context)) : {};
213
- const handler = setupResult.handler || definition.handler;
214
- if (!handler) throw diagnostics.DF0024({ name: definition.name });
215
- let dump = setupResult.dump ?? definition.dump;
216
- if (!dump && definition.type === "static") dump = { inputs: [[]] };
217
- if (!dump && definition.snapshot) dump = async (_ctx, h) => {
218
- const output = await Promise.resolve(h(...[]));
219
- return {
220
- records: [{
221
- inputs: [],
222
- output
223
- }],
224
- fallback: output
225
- };
226
- };
227
- if (!dump) return;
228
- if (typeof dump === "function") dump = await Promise.resolve(dump(context, handler));
229
- store.definitions[definition.name] = {
230
- name: definition.name,
231
- type: definition.type
232
- };
233
- return {
234
- handler,
235
- dump,
236
- definition
237
- };
238
- });
239
- let functionsToDump = [];
240
- if (concurrency <= 1) for (const task of tasksResolutions) {
241
- const resolution = await task();
242
- if (resolution) functionsToDump.push(resolution);
243
- }
244
- else {
245
- const limit = pLimit(concurrency);
246
- functionsToDump = (await Promise.all(tasksResolutions.map((task) => limit(task)))).filter((x) => !!x);
247
- }
248
- const dumpTasks = [];
249
- for (const { definition, handler, dump } of functionsToDump) {
250
- const { inputs, records, fallback } = dump;
251
- if (records) for (const record of records) {
252
- const recordKey = getDumpRecordKey(definition.name, record.inputs);
253
- store.records[recordKey] = record;
254
- }
255
- if ("fallback" in dump) {
256
- const fallbackKey = getDumpFallbackKey(definition.name);
257
- store.records[fallbackKey] = {
258
- inputs: [],
259
- output: fallback
260
- };
261
- }
262
- if (inputs) for (const input of inputs) dumpTasks.push(async () => {
263
- const recordKey = getDumpRecordKey(definition.name, input);
264
- try {
265
- const output = await Promise.resolve(handler(...input));
266
- store.records[recordKey] = {
267
- inputs: input,
268
- output
269
- };
270
- } catch (error) {
271
- store.records[recordKey] = {
272
- inputs: input,
273
- error: serializeDumpError(error)
274
- };
275
- }
276
- });
277
- }
278
- if (concurrency <= 1) for (const task of dumpTasks) await task();
279
- else {
280
- const limit = pLimit(concurrency);
281
- await Promise.all(dumpTasks.map((task) => limit(task)));
282
- }
270
+ await runDumpTasks((await runDumpTasks(definitions.map((definition) => () => resolveDumpTask(definition, context, store)), concurrency)).filter((x) => !!x).flatMap((resolution) => collectDumpTasks(resolution, store)), concurrency);
283
271
  return store;
284
272
  }
285
273
  /**
@@ -359,6 +347,54 @@ function makeQueryFallbackPath(name) {
359
347
  async function resolveRecord(record) {
360
348
  return typeof record === "function" ? await record() : record;
361
349
  }
350
+ async function collectStaticDefinition(definition, context, serialization, files) {
351
+ const handler = await getRpcHandler(definition, context);
352
+ const path = makeStaticPath(definition.name);
353
+ files[path] = {
354
+ serialization,
355
+ fnName: definition.name,
356
+ data: { output: await Promise.resolve(handler()) }
357
+ };
358
+ return {
359
+ type: "static",
360
+ path,
361
+ serialization
362
+ };
363
+ }
364
+ async function collectQueryDefinition(definition, context, serialization, files) {
365
+ const store = await dumpFunctions([definition], context);
366
+ if (!(definition.name in store.definitions)) return void 0;
367
+ const queryEntry = {
368
+ type: "query",
369
+ records: {},
370
+ serialization
371
+ };
372
+ const prefix = `${definition.name}---`;
373
+ for (const [recordKey, recordOrGetter] of Object.entries(store.records)) {
374
+ if (!recordKey.startsWith(prefix)) continue;
375
+ const key = recordKey.slice(prefix.length);
376
+ const record = await resolveRecord(recordOrGetter);
377
+ if (key === "fallback") {
378
+ const path = makeQueryFallbackPath(definition.name);
379
+ files[path] = {
380
+ serialization,
381
+ fnName: definition.name,
382
+ data: record
383
+ };
384
+ queryEntry.fallback = path;
385
+ } else {
386
+ const path = makeQueryRecordPath(definition.name, key);
387
+ files[path] = {
388
+ serialization,
389
+ fnName: definition.name,
390
+ data: record
391
+ };
392
+ queryEntry.records[key] = path;
393
+ }
394
+ }
395
+ if (!Object.keys(queryEntry.records).length && !queryEntry.fallback) return void 0;
396
+ return queryEntry;
397
+ }
362
398
  async function collectStaticRpcDump(definitions, context) {
363
399
  const manifest = {};
364
400
  const files = {};
@@ -366,53 +402,12 @@ async function collectStaticRpcDump(definitions, context) {
366
402
  const type = definition.type ?? "query";
367
403
  const serialization = definition.jsonSerializable === true ? "json" : "structured-clone";
368
404
  if (type === "static") {
369
- const handler = await getRpcHandler(definition, context);
370
- const path = makeStaticPath(definition.name);
371
- files[path] = {
372
- serialization,
373
- fnName: definition.name,
374
- data: { output: await Promise.resolve(handler()) }
375
- };
376
- manifest[definition.name] = {
377
- type: "static",
378
- path,
379
- serialization
380
- };
405
+ manifest[definition.name] = await collectStaticDefinition(definition, context, serialization, files);
381
406
  continue;
382
407
  }
383
408
  if (type !== "query") continue;
384
- const store = await dumpFunctions([definition], context);
385
- if (!(definition.name in store.definitions)) continue;
386
- const queryEntry = {
387
- type: "query",
388
- records: {},
389
- serialization
390
- };
391
- const prefix = `${definition.name}---`;
392
- for (const [recordKey, recordOrGetter] of Object.entries(store.records)) {
393
- if (!recordKey.startsWith(prefix)) continue;
394
- const key = recordKey.slice(prefix.length);
395
- const record = await resolveRecord(recordOrGetter);
396
- if (key === "fallback") {
397
- const path = makeQueryFallbackPath(definition.name);
398
- files[path] = {
399
- serialization,
400
- fnName: definition.name,
401
- data: record
402
- };
403
- queryEntry.fallback = path;
404
- } else {
405
- const path = makeQueryRecordPath(definition.name, key);
406
- files[path] = {
407
- serialization,
408
- fnName: definition.name,
409
- data: record
410
- };
411
- queryEntry.records[key] = path;
412
- }
413
- }
414
- if (!Object.keys(queryEntry.records).length && !queryEntry.fallback) continue;
415
- manifest[definition.name] = queryEntry;
409
+ const queryEntry = await collectQueryDefinition(definition, context, serialization, files);
410
+ if (queryEntry) manifest[definition.name] = queryEntry;
416
411
  }
417
412
  return {
418
413
  manifest,
@@ -1,4 +1,4 @@
1
- import { t as diagnostics } from "./diagnostics-BXWW3VK-.mjs";
1
+ import { t as diagnostics } from "./diagnostics-BMfN8mb1.mjs";
2
2
  import { createSharedState } from "devframe/utils/shared-state";
3
3
  import process from "node:process";
4
4
  import { dirname } from "pathe";