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.
- package/dist/{_shared-BM3PdYli.mjs → _shared-C08SdQRl.mjs} +15 -4
- package/dist/{_shared-mtXpcJIv.d.mts → _shared-CK3czkH4.d.mts} +25 -2
- package/dist/adapters/build.d.mts +6 -6
- package/dist/adapters/build.mjs +32 -22
- package/dist/adapters/cac.d.mts +16 -1
- package/dist/adapters/cac.mjs +8 -7
- package/dist/adapters/dev.d.mts +13 -13
- package/dist/adapters/dev.mjs +2 -2
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/initiate.d.mts +28 -26
- package/dist/adapters/initiate.mjs +1 -1
- package/dist/adapters/mcp.d.mts +28 -14
- package/dist/adapters/mcp.mjs +75 -39
- package/dist/{agent-tool-name-EgfoFO8C.mjs → agent-tool-name-DGzeuWcO.mjs} +2 -2
- package/dist/cli/main.d.mts +1 -1
- package/dist/cli/main.mjs +41 -17
- package/dist/client/index.d.mts +36 -36
- package/dist/client/index.mjs +83 -51
- package/dist/{client-assets-C7SXgTWY.mjs → client-assets-DNdhagGm.mjs} +2 -2
- package/dist/constants.d.mts +8 -7
- package/dist/constants.mjs +7 -6
- package/dist/{context-CLF4-8Pp.d.mts → context-4AIVRLYF.d.mts} +158 -122
- package/dist/{context-omlma_1n.mjs → context-CwPUinjn.mjs} +126 -88
- package/dist/{context-KUqAfawQ.mjs → context-DIUvJW4D.mjs} +3 -3
- package/dist/{context-DftYyXaR.d.mts → context-rgBSPFHS.d.mts} +5 -5
- package/dist/{crypto-token-XCqTSMg9.mjs → crypto-token-TVbGGFuj.mjs} +1 -1
- package/dist/{dev-CzkPCJwi.mjs → dev-Eqq5PX0k.mjs} +37 -18
- package/dist/{diagnostics-BXWW3VK-.mjs → diagnostics-BMfN8mb1.mjs} +30 -17
- package/dist/{diagnostics-CD8nlgll.mjs → diagnostics-D0EVm5M6.mjs} +2 -2
- package/dist/{events-4daw0uK9.mjs → events-BV4Dj59a.mjs} +2 -2
- package/dist/{host-h3-fRbF9yor.mjs → host-h3-BJ4siyz7.mjs} +1 -1
- package/dist/in-page-channel/index.d.mts +14 -14
- package/dist/in-page-channel/index.mjs +63 -54
- package/dist/{index-BzyopqxV.d.mts → index-pIVt92jP.d.mts} +9 -9
- package/dist/{index-D3k0BIhe.d.mts → index-pKl67H6w.d.mts} +4 -4
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +2 -2
- package/dist/{instance-registry-BjlMQbFB.mjs → instance-registry-C7-41RSp.mjs} +8 -8
- package/dist/{instance-shell-Tcp5hGoq.d.mts → instance-shell-7Z52PE4_.d.mts} +18 -18
- package/dist/{instance-shell-CpVW4zG0.mjs → instance-shell-cdVETpfz.mjs} +227 -58
- package/dist/internal/index.d.mts +40 -23
- package/dist/internal/index.mjs +10 -10
- package/dist/node/auth.d.mts +2 -2
- package/dist/node/auth.mjs +2 -2
- package/dist/node/hub-internals.d.mts +2 -2
- package/dist/node/hub-internals.mjs +2 -2
- package/dist/node/index.d.mts +5 -5
- package/dist/node/index.mjs +2 -2
- package/dist/{nostics-SPGDgHEP.d.mts → nostics-0sKe5HIj.d.mts} +2 -2
- package/dist/{nostics-CzECRXpE.mjs → nostics-D0PvLZsn.mjs} +1 -1
- package/dist/origin-DGDH8BI9.d.mts +45 -0
- package/dist/origin-DZit9g29.mjs +80 -0
- package/dist/recipes/common-rpc-functions.d.mts +5 -5
- package/dist/recipes/common-rpc-functions.mjs +3 -3
- package/dist/recipes/interactive-auth.d.mts +6 -6
- package/dist/recipes/interactive-auth.mjs +6 -6
- package/dist/{remote-assets-DezQmPQU.mjs → remote-assets-BIFWOlBW.mjs} +26 -6
- package/dist/{remote-assets-B13_vRkJ.d.mts → remote-assets-eBvSKZMS.d.mts} +7 -7
- package/dist/{revoke-COLW0cOi.mjs → revoke-cqztiCX4.mjs} +1 -1
- package/dist/rpc/dump.d.mts +2 -11
- package/dist/rpc/dump.mjs +1 -1
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +3 -3
- package/dist/rpc/transports/sse-client.d.mts +1 -1
- package/dist/rpc/transports/sse-client.mjs +30 -14
- package/dist/rpc/transports/sse-server.d.mts +4 -4
- package/dist/rpc/transports/sse-server.mjs +7 -7
- package/dist/rpc/transports/ws-bun.d.mts +5 -5
- package/dist/rpc/transports/ws-bun.mjs +8 -2
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-client.mjs +2 -2
- package/dist/rpc/transports/ws-deno.d.mts +4 -4
- package/dist/rpc/transports/ws-deno.mjs +8 -2
- package/dist/rpc/transports/ws-server.d.mts +2 -1
- package/dist/rpc/transports/ws-server.mjs +232 -1
- package/dist/{rpc-core-B3W3z9ff.d.mts → rpc-core-Ceu6AUz8.d.mts} +4 -4
- package/dist/{rpc-core-DlHd276T.mjs → rpc-core-DVQ7xi89.mjs} +14 -2
- package/dist/{serialization-BGzEwAdr.mjs → serialization-DTZnPQ1-.mjs} +20 -18
- package/dist/{services-install-CqqQVls5.mjs → services-install-P_DV7VYL.mjs} +32 -21
- package/dist/session-DPfj6zQG.mjs +16 -0
- package/dist/{shared-state--sduc6Xi.mjs → shared-state-CaxB1q0h.mjs} +2 -2
- package/dist/{simple-schema-DQPZrAaZ.mjs → simple-schema-Bi40l-P6.mjs} +2 -2
- package/dist/{sse-client-DwX021ST.d.mts → sse-client-BQ4jS3eO.d.mts} +4 -4
- package/dist/{state-CK9LjrnT.mjs → state-CeQQWzM-.mjs} +4 -4
- package/dist/{static-DV_qUSRS.mjs → static-DZ8P2Kn7.mjs} +130 -135
- package/dist/{storage-BXNVhKyR.mjs → storage-Dccf_IyD.mjs} +1 -1
- package/dist/types/index.d.mts +6 -6
- package/dist/{types-CMdPYhOx.d.mts → types-Dq4i156u.d.mts} +17 -17
- package/dist/utils/agent-tool-name.d.mts +2 -2
- package/dist/utils/agent-tool-name.mjs +2 -2
- package/dist/utils/colors.d.mts +1 -1
- package/dist/utils/crypto-token.d.mts +1 -1
- package/dist/utils/crypto-token.mjs +1 -1
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/nostics.d.mts +1 -1
- package/dist/utils/nostics.mjs +1 -1
- package/dist/utils/open.mjs +1 -1
- package/dist/utils/origin.d.mts +2 -0
- package/dist/utils/origin.mjs +80 -0
- package/dist/utils/remote-assets.d.mts +2 -2
- package/dist/utils/remote-assets.mjs +1 -1
- package/dist/utils/serve-static.d.mts +4 -4
- package/dist/utils/serve-static.mjs +56 -19
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -1
- package/dist/utils/simple-schema.d.mts +5 -5
- package/dist/utils/simple-schema.mjs +2 -2
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/streaming-channel.mjs +2 -2
- package/dist/utils/when.d.mts +5 -5
- package/dist/{validation-YrZH6atx.mjs → validation-BOy8IoFZ.mjs} +2 -2
- package/dist/{wire-codec-0K-o5MYW.mjs → wire-codec-dcCeXcSo.mjs} +3 -3
- package/dist/{ws-client-7_lZi-B9.d.mts → ws-client-Xpxt0oPA.d.mts} +3 -3
- package/dist/{ws-server-VyHlanzy.d.mts → ws-server-D2nv68Hg.d.mts} +13 -37
- package/package.json +2 -1
- 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-
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
30
|
-
* - `BigInt` at top level
|
|
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
|
|
33
|
+
* - `undefined` as an object property: legitimate optional field;
|
|
34
34
|
* JSON.stringify just omits it.
|
|
35
|
-
* - `undefined` at the root
|
|
36
|
-
* - `Symbol` / `Function` values
|
|
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
|
|
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
|
|
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-
|
|
2
|
-
import { t as diagnostics } from "./diagnostics-
|
|
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
|
|
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
|
-
|
|
361
|
-
|
|
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
|
|
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
|
|
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 [
|
|
935
|
-
state =
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
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)
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
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-
|
|
2
|
-
import { t as diagnostics } from "./diagnostics-
|
|
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.
|
|
159
|
+
for (const [key, value] of Object.entries(error)) {
|
|
160
160
|
if (key === "name" || key === "message" || key === "cause") continue;
|
|
161
|
-
out[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
|
|
172
|
-
const
|
|
173
|
-
error
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
*
|
|
196
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
385
|
-
if (
|
|
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,
|