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
package/dist/client/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as DEVFRAME_EVENTS } from "../events-
|
|
1
|
+
import { t as DEVFRAME_EVENTS } from "../events-BV4Dj59a.mjs";
|
|
2
2
|
import { t as hash } from "../hash-DdPnc4k3.mjs";
|
|
3
3
|
import { colors } from "../utils/colors.mjs";
|
|
4
4
|
import { createEventEmitter } from "../utils/events.mjs";
|
|
5
|
-
import { t as createSharedState } from "../shared-state
|
|
5
|
+
import { t as createSharedState } from "../shared-state-CaxB1q0h.mjs";
|
|
6
6
|
import { i as structuredCloneStringify, n as structuredCloneParse, t as structuredCloneDeserialize } from "../structured-clone-CgtQ61SA.mjs";
|
|
7
7
|
import { createStreamReader, createStreamSink } from "../utils/streaming-channel.mjs";
|
|
8
8
|
import { defineDiagnostics } from "nostics";
|
|
@@ -10,6 +10,7 @@ import { ansiFormatter } from "nostics/formatters/ansi";
|
|
|
10
10
|
import { withBase, withProtocol } from "ufo";
|
|
11
11
|
import { createBirpc } from "birpc";
|
|
12
12
|
//#region src/constants.ts
|
|
13
|
+
/** Devframe runtime routes and static output conventions. */
|
|
13
14
|
const DEVFRAME_CONNECTION_META_FILENAME = "__connection.json";
|
|
14
15
|
/**
|
|
15
16
|
* Global key holding the serializable connection prepared by
|
|
@@ -110,7 +111,7 @@ function devframeReporter(d, { method = "warn" } = {}) {
|
|
|
110
111
|
* ANSI console reporter pre-wired ahead of any `reporters` passed in. Every
|
|
111
112
|
* `diagnostics.ts` in devframe core, `@devframes/hub`, `@devframes/json-render`,
|
|
112
113
|
* and the built-in plugins defines its codes through this instead of
|
|
113
|
-
* `nostics`'s own `defineDiagnostics
|
|
114
|
+
* `nostics`'s own `defineDiagnostics`; the reporter registration lives
|
|
114
115
|
* here, once, so none of them need to build their own reporter (`colors`,
|
|
115
116
|
* `ansiFormatter`) or take a direct dependency on `nostics` themselves.
|
|
116
117
|
*/
|
|
@@ -126,7 +127,7 @@ const diagnostics = defineDiagnostics$1({
|
|
|
126
127
|
docsBase: "https://devfra.me/errors",
|
|
127
128
|
codes: {
|
|
128
129
|
DF0019: {
|
|
129
|
-
why: (p) => `RPC function "${p.name}" has \`agent\` set but \`jsonSerializable\` is not \`true
|
|
130
|
+
why: (p) => `RPC function "${p.name}" has \`agent\` set but \`jsonSerializable\` is not \`true\`; MCP requires JSON-serializable data.`,
|
|
130
131
|
fix: "Set `jsonSerializable: true` if the payload is JSON-safe, or remove `agent` to keep it RPC-only."
|
|
131
132
|
},
|
|
132
133
|
DF0020: {
|
|
@@ -207,7 +208,7 @@ async function validateRpcArgs(name, argsSchema, args) {
|
|
|
207
208
|
/**
|
|
208
209
|
* Validate a handler's resolved return value against its declared schema.
|
|
209
210
|
* Throws `DF0039` when the value fails the schema, otherwise returns the
|
|
210
|
-
* original value unchanged (guard-only, never rewriting the payload
|
|
211
|
+
* original value unchanged (guard-only, never rewriting the payload; see
|
|
211
212
|
* {@link validateRpcArgs}). Passes through when no return schema is set.
|
|
212
213
|
*
|
|
213
214
|
* @internal
|
|
@@ -350,16 +351,16 @@ function assertAgentJsonSerializable(fn) {
|
|
|
350
351
|
* instances, or `undefined` inside an array (silently becomes `null`).
|
|
351
352
|
*
|
|
352
353
|
* Native pass-throughs (no extra work needed):
|
|
353
|
-
* - circular references
|
|
354
|
-
* - `BigInt` at top level
|
|
354
|
+
* - circular references: `JSON.stringify` raises `TypeError`.
|
|
355
|
+
* - `BigInt` at top level: caught here for a friendlier error path.
|
|
355
356
|
*
|
|
356
357
|
* Lenient cases (allowed without throwing):
|
|
357
|
-
* - `undefined` as an object property
|
|
358
|
+
* - `undefined` as an object property: legitimate optional field;
|
|
358
359
|
* JSON.stringify just omits it.
|
|
359
|
-
* - `undefined` at the root
|
|
360
|
-
* - `Symbol` / `Function` values
|
|
360
|
+
* - `undefined` at the root: legitimate "action returned nothing".
|
|
361
|
+
* - `Symbol` / `Function` values: semantically "drop me" in JSON.
|
|
361
362
|
*
|
|
362
|
-
* `fnName` is used only for the diagnostic message
|
|
363
|
+
* `fnName` is used only for the diagnostic message; pass the RPC
|
|
363
364
|
* function name when calling from a wire serializer / dump writer so
|
|
364
365
|
* the error points at the offending function.
|
|
365
366
|
*/
|
|
@@ -371,19 +372,21 @@ function strictJsonStringify(value, fnName = "") {
|
|
|
371
372
|
if (Array.isArray(holder)) throw nonJsonAt(fnName, "undefined", holder, key);
|
|
372
373
|
return val;
|
|
373
374
|
}
|
|
374
|
-
if (original
|
|
375
|
-
if (typeof original === "bigint") throw nonJsonAt(fnName, "BigInt", holder, key);
|
|
376
|
-
if (typeof original === "object") {
|
|
377
|
-
if (original instanceof Map) throw nonJsonAt(fnName, "Map", holder, key);
|
|
378
|
-
if (original instanceof Set) throw nonJsonAt(fnName, "Set", holder, key);
|
|
379
|
-
if (original instanceof Date) throw nonJsonAt(fnName, "Date", holder, key);
|
|
380
|
-
if (Array.isArray(original)) return val;
|
|
381
|
-
const proto = Object.getPrototypeOf(original);
|
|
382
|
-
if (proto !== null && proto !== Object.prototype) throw nonJsonAt(fnName, original.constructor?.name ?? "class instance", holder, key);
|
|
383
|
-
}
|
|
375
|
+
if (original !== null) assertJsonSafe(original, holder, key, fnName);
|
|
384
376
|
return val;
|
|
385
377
|
});
|
|
386
378
|
}
|
|
379
|
+
/** Throw `DF0020` when `original` is a type JSON can't round-trip losslessly. */
|
|
380
|
+
function assertJsonSafe(original, holder, key, fnName) {
|
|
381
|
+
if (typeof original === "bigint") throw nonJsonAt(fnName, "BigInt", holder, key);
|
|
382
|
+
if (typeof original !== "object") return;
|
|
383
|
+
if (original instanceof Map) throw nonJsonAt(fnName, "Map", holder, key);
|
|
384
|
+
if (original instanceof Set) throw nonJsonAt(fnName, "Set", holder, key);
|
|
385
|
+
if (original instanceof Date) throw nonJsonAt(fnName, "Date", holder, key);
|
|
386
|
+
if (Array.isArray(original)) return;
|
|
387
|
+
const proto = Object.getPrototypeOf(original);
|
|
388
|
+
if (proto !== null && proto !== Object.prototype) throw nonJsonAt(fnName, original.constructor?.name ?? "class instance", holder, key);
|
|
389
|
+
}
|
|
387
390
|
function nonJsonAt(fnName, type, parent, key) {
|
|
388
391
|
const path = formatPath(parent, key);
|
|
389
392
|
return diagnostics.DF0020({
|
|
@@ -506,6 +509,10 @@ async function setupDevframeConnection(options = {}) {
|
|
|
506
509
|
if (options.connectionMeta) {
|
|
507
510
|
const connection = {
|
|
508
511
|
connectionMeta: options.connectionMeta,
|
|
512
|
+
/**
|
|
513
|
+
* Preserve the established connectionMeta behavior: an explicitly
|
|
514
|
+
* supplied descriptor resolves from the caller's explicit base.
|
|
515
|
+
*/
|
|
509
516
|
metaBaseUrl: resolveMetaBaseUrl(bases[0] ?? "./"),
|
|
510
517
|
authToken: readStoredAuthToken(options.authToken ?? options.connectionMeta.authToken)
|
|
511
518
|
};
|
|
@@ -605,7 +612,7 @@ function consumeOtpFromUrl(param = DEVFRAME_OTP_URL_PARAM) {
|
|
|
605
612
|
*
|
|
606
613
|
* Higher-level integrations (e.g. Vite DevTools) that want to drive their own
|
|
607
614
|
* authentication UI can disable `connectDevframe`'s built-in handling with
|
|
608
|
-
* `otpParam: false` and call this
|
|
615
|
+
* `otpParam: false` and call this (or {@link consumeOtpFromUrl}) themselves.
|
|
609
616
|
*/
|
|
610
617
|
async function authenticateWithUrlOtp(rpc, options = {}) {
|
|
611
618
|
const code = consumeOtpFromUrl(options.param ?? "devframe_otp");
|
|
@@ -763,7 +770,7 @@ const EMPTY_WIRE_DEFS = /* @__PURE__ */ new Map();
|
|
|
763
770
|
* JSON (methods declared `jsonSerializable: true`) and `s:`-prefixed
|
|
764
771
|
* structured-clone (everything else, including all error envelopes), with a
|
|
765
772
|
* request-id → method map so a response independently picks the same
|
|
766
|
-
* encoder as its request. One codec per connection
|
|
773
|
+
* encoder as its request. One codec per connection; request-id spaces
|
|
767
774
|
* don't collide across connections.
|
|
768
775
|
*
|
|
769
776
|
* @internal
|
|
@@ -791,9 +798,32 @@ function createRpcWireCodec(definitions = EMPTY_WIRE_DEFS) {
|
|
|
791
798
|
//#endregion
|
|
792
799
|
//#region src/rpc/transports/sse-client.ts
|
|
793
800
|
function NOOP$1() {}
|
|
801
|
+
/** Split the next complete SSE frame (up to a blank line) off the buffer. */
|
|
802
|
+
function takeFrame(buffer) {
|
|
803
|
+
const boundary = buffer.search(/\n\n|\r\n\r\n/);
|
|
804
|
+
if (boundary < 0) return void 0;
|
|
805
|
+
return {
|
|
806
|
+
frame: buffer.slice(0, boundary),
|
|
807
|
+
rest: buffer.slice(boundary + (buffer[boundary] === "\r" ? 4 : 2))
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
/** Parse one SSE frame's lines into its event name and data lines. */
|
|
811
|
+
function parseFrame(frame) {
|
|
812
|
+
let event = "message";
|
|
813
|
+
const data = [];
|
|
814
|
+
for (const rawLine of frame.split(/\r?\n/)) {
|
|
815
|
+
if (rawLine.startsWith(":")) continue;
|
|
816
|
+
if (rawLine.startsWith("event:")) event = rawLine.slice(6).trimStart();
|
|
817
|
+
else if (rawLine.startsWith("data:")) data.push(rawLine.slice(5).replace(/^ /, ""));
|
|
818
|
+
}
|
|
819
|
+
return {
|
|
820
|
+
event,
|
|
821
|
+
data
|
|
822
|
+
};
|
|
823
|
+
}
|
|
794
824
|
/**
|
|
795
825
|
* Build a birpc `ChannelOptions` object backed by an SSE stream (server →
|
|
796
|
-
* client) and HTTP `POST` (client → server)
|
|
826
|
+
* client) and HTTP `POST` (client → server): the WebSocket-free counterpart
|
|
797
827
|
* to `createWsRpcChannel`, wire-compatible with `attachSseRpcTransport`.
|
|
798
828
|
*
|
|
799
829
|
* The stream is consumed via `fetch` streaming (not `EventSource`), so it
|
|
@@ -801,7 +831,7 @@ function NOOP$1() {}
|
|
|
801
831
|
* (`event: session`) carries the session id; every `POST` echoes it in the
|
|
802
832
|
* `x-birpc-session` header. A response to a client-initiated request comes
|
|
803
833
|
* back in the `POST`'s own body and is re-injected into the channel; a
|
|
804
|
-
* dropped stream terminates the channel
|
|
834
|
+
* dropped stream terminates the channel; there is no reconnect, matching
|
|
805
835
|
* the WS channel's closed-is-done semantics.
|
|
806
836
|
*/
|
|
807
837
|
function createSseRpcChannel(options) {
|
|
@@ -852,17 +882,10 @@ function createSseRpcChannel(options) {
|
|
|
852
882
|
if (done) break;
|
|
853
883
|
buffer += decoder.decode(value, { stream: true });
|
|
854
884
|
for (;;) {
|
|
855
|
-
const
|
|
856
|
-
if (
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
let event = "message";
|
|
860
|
-
const data = [];
|
|
861
|
-
for (const rawLine of frame.split(/\r?\n/)) {
|
|
862
|
-
if (rawLine.startsWith(":")) continue;
|
|
863
|
-
if (rawLine.startsWith("event:")) event = rawLine.slice(6).trimStart();
|
|
864
|
-
else if (rawLine.startsWith("data:")) data.push(rawLine.slice(5).replace(/^ /, ""));
|
|
865
|
-
}
|
|
885
|
+
const taken = takeFrame(buffer);
|
|
886
|
+
if (!taken) break;
|
|
887
|
+
buffer = taken.rest;
|
|
888
|
+
const { event, data } = parseFrame(taken.frame);
|
|
866
889
|
if (data.length > 0) dispatch(event, data.join("\n"));
|
|
867
890
|
}
|
|
868
891
|
}
|
|
@@ -955,8 +978,8 @@ function promiseWithResolver() {
|
|
|
955
978
|
//#endregion
|
|
956
979
|
//#region src/client/rpc-live.ts
|
|
957
980
|
/**
|
|
958
|
-
* The transport-independent half of a live RPC client mode
|
|
959
|
-
* status, pending-call guarding, and the trust handshake
|
|
981
|
+
* The transport-independent half of a live RPC client mode (connection
|
|
982
|
+
* status, pending-call guarding, and the trust handshake), shared by the
|
|
960
983
|
* WebSocket and SSE modes. Each transport supplies only its channel.
|
|
961
984
|
*/
|
|
962
985
|
function createLiveRpcClientMode(options) {
|
|
@@ -984,7 +1007,7 @@ function createLiveRpcClientMode(options) {
|
|
|
984
1007
|
}
|
|
985
1008
|
/**
|
|
986
1009
|
* Wrap an in-flight call promise so it settles on server response, on an
|
|
987
|
-
* optional wall-clock timeout, or when the connection drops
|
|
1010
|
+
* optional wall-clock timeout, or when the connection drops, so it never hangs.
|
|
988
1011
|
*/
|
|
989
1012
|
function guardCall(promise, method) {
|
|
990
1013
|
return new Promise((resolve, reject) => {
|
|
@@ -1053,6 +1076,11 @@ function createLiveRpcClientMode(options) {
|
|
|
1053
1076
|
currentAuthToken = token;
|
|
1054
1077
|
const result = await serverRpc.$call("anonymous:devframe:auth", {
|
|
1055
1078
|
authToken: token,
|
|
1079
|
+
/**
|
|
1080
|
+
* Sent raw; the server parses it into a display label (see
|
|
1081
|
+
* `describeUA` in `node/auth/state.ts`) so `ua-parser-modern` stays
|
|
1082
|
+
* out of the browser bundle.
|
|
1083
|
+
*/
|
|
1056
1084
|
ua: navigator.userAgent,
|
|
1057
1085
|
origin: location.origin
|
|
1058
1086
|
});
|
|
@@ -1175,7 +1203,7 @@ function resolveSseUrl(sse, metaBaseUrl, loc) {
|
|
|
1175
1203
|
return new URL(str, base).href;
|
|
1176
1204
|
}
|
|
1177
1205
|
/**
|
|
1178
|
-
* The SSE-backed live client mode
|
|
1206
|
+
* The SSE-backed live client mode, picked by `connectDevframe` when the
|
|
1179
1207
|
* server advertises SSE as its primary transport (`backend: 'sse'`) or when
|
|
1180
1208
|
* the caller pins `transport: 'sse'`. Same status machine, call guarding,
|
|
1181
1209
|
* and trust handshake as the WebSocket mode, over `createSseRpcChannel`.
|
|
@@ -1218,13 +1246,11 @@ function createSseRpcClientMode(options) {
|
|
|
1218
1246
|
* the original `name`, and re-attaches any custom own properties.
|
|
1219
1247
|
*/
|
|
1220
1248
|
function reviveDumpError(stored) {
|
|
1221
|
-
const
|
|
1222
|
-
const
|
|
1223
|
-
error
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
error[key] = stored[key];
|
|
1227
|
-
}
|
|
1249
|
+
const { name, message, cause: rawCause, ...extras } = stored;
|
|
1250
|
+
const cause = rawCause instanceof Error ? rawCause : isPlainErrorShape(rawCause) ? reviveDumpError(rawCause) : rawCause;
|
|
1251
|
+
const error = cause !== void 0 ? new Error(message, { cause }) : new Error(message);
|
|
1252
|
+
error.name = name;
|
|
1253
|
+
Object.assign(error, extras);
|
|
1228
1254
|
return error;
|
|
1229
1255
|
}
|
|
1230
1256
|
function isPlainErrorShape(value) {
|
|
@@ -1305,15 +1331,21 @@ async function createStaticRpcClientMode(options) {
|
|
|
1305
1331
|
return {
|
|
1306
1332
|
transport: "static",
|
|
1307
1333
|
isTrusted: true,
|
|
1334
|
+
/**
|
|
1335
|
+
* A static backend has no live socket; every call is a local fetch, so it
|
|
1336
|
+
* is "connected" for its whole life.
|
|
1337
|
+
*/
|
|
1308
1338
|
status: "connected",
|
|
1309
1339
|
connectionError: null,
|
|
1310
1340
|
requestTrust: async () => true,
|
|
1311
1341
|
requestTrustWithToken: async () => true,
|
|
1342
|
+
/** Static backends are always trusted, so there's nothing to exchange. */
|
|
1312
1343
|
requestTrustWithCode: async () => null,
|
|
1313
1344
|
ensureTrusted: async () => true,
|
|
1314
1345
|
call: (...args) => staticCaller.call(args[0], args.slice(1)),
|
|
1315
1346
|
callEvent: (...args) => staticCaller.callEvent(args[0], args.slice(1)),
|
|
1316
1347
|
callOptional: (...args) => staticCaller.callOptional(args[0], args.slice(1)),
|
|
1348
|
+
/** No live socket to close; every call is a local fetch. */
|
|
1317
1349
|
close: () => {}
|
|
1318
1350
|
};
|
|
1319
1351
|
}
|
|
@@ -1426,7 +1458,7 @@ const EMPTY_DEFS = /* @__PURE__ */ new Map();
|
|
|
1426
1458
|
* Build a birpc `ChannelOptions` object backed by a browser `WebSocket`.
|
|
1427
1459
|
* Pass the result straight to `createRpcClient`'s `channel` option.
|
|
1428
1460
|
*
|
|
1429
|
-
* Also returns `close()`, closing the underlying socket
|
|
1461
|
+
* Also returns `close()`, closing the underlying socket, mirroring the server transport's
|
|
1430
1462
|
* existing `WsRpcTransport.close()`. `birpc`'s own `ChannelOptions` has no teardown of its own.
|
|
1431
1463
|
*/
|
|
1432
1464
|
function createWsRpcChannel(options) {
|
|
@@ -1488,7 +1520,7 @@ function createWsRpcChannel(options) {
|
|
|
1488
1520
|
* The object / relative-path forms connect to the page's own origin (only the
|
|
1489
1521
|
* `http`→`ws` protocol swap is applied), resolving the path against where
|
|
1490
1522
|
* `__connection.json` was loaded. This is deliberately host-agnostic so the
|
|
1491
|
-
* connection survives a reverse proxy that changes the domain or port
|
|
1523
|
+
* connection survives a reverse proxy that changes the domain or port, since the
|
|
1492
1524
|
* client trusts its own location, never a server-baked hostname. An explicit
|
|
1493
1525
|
* `port`/`host` (or a full `ws(s)://` URL string) opts into a cross-origin
|
|
1494
1526
|
* endpoint, e.g. a side-car server on its own port.
|
|
@@ -1643,7 +1675,7 @@ function createScopedClientContext(rpc, namespace) {
|
|
|
1643
1675
|
//#region src/client/rpc.ts
|
|
1644
1676
|
/**
|
|
1645
1677
|
* Resolve the requested `transport` option against what the server
|
|
1646
|
-
* advertises. `'auto'` trusts the advertisement
|
|
1678
|
+
* advertises. `'auto'` trusts the advertisement: the server's declared
|
|
1647
1679
|
* primary (`backend`), preferring the WebSocket when both endpoints are
|
|
1648
1680
|
* present; an explicit `'websocket'` / `'sse'` pins that transport and
|
|
1649
1681
|
* throws when the server doesn't advertise it.
|
|
@@ -1663,7 +1695,7 @@ function resolveClientTransport(requested, meta) {
|
|
|
1663
1695
|
if (meta.backend === "sse" && hasSse) return "sse";
|
|
1664
1696
|
if (hasWebsocket) return "websocket";
|
|
1665
1697
|
if (hasSse) return "sse";
|
|
1666
|
-
throw new Error("[devframe] This server advertises no RPC transport (backend \"none\")
|
|
1698
|
+
throw new Error("[devframe] This server advertises no RPC transport (backend \"none\"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.");
|
|
1667
1699
|
}
|
|
1668
1700
|
async function getDevframeRpcClient(options = {}) {
|
|
1669
1701
|
const { baseURL = "./", rpcOptions = {}, cacheOptions = false } = options;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
//#region src/client-assets.ts
|
|
2
2
|
/**
|
|
3
|
-
* Resolve a definition's client assets source
|
|
3
|
+
* Resolve a definition's client assets source: the built SPA served as its
|
|
4
4
|
* UI. Prefers the top-level {@link DevframeDefinition.clientAssets} and falls
|
|
5
5
|
* back to the deprecated `cli.distDir`, so both the new and legacy shapes
|
|
6
|
-
* resolve. Returns `undefined` when neither is set (bridge mode
|
|
6
|
+
* resolve. Returns `undefined` when neither is set (bridge mode, where the SPA is
|
|
7
7
|
* hosted elsewhere).
|
|
8
8
|
*
|
|
9
9
|
* Internal: exposed to first-party integrations via `devframe/internal`, not
|
package/dist/constants.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//#region src/events.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Centralized registry of the core devframe event names
|
|
3
|
+
* Centralized registry of the core devframe event names: the node-side host
|
|
4
4
|
* bus events, the client RPC connection events, and the server→client
|
|
5
|
-
* broadcast notifications
|
|
5
|
+
* broadcast notifications, so these names live in one place instead of
|
|
6
6
|
* scattered string literals.
|
|
7
7
|
*
|
|
8
8
|
* **Keep this in sync with [`docs/content/8.references/3.events.md`](../../../docs/content/8.references/3.events.md)**
|
|
@@ -77,6 +77,7 @@ declare const DEVFRAME_EVENTS: {
|
|
|
77
77
|
};
|
|
78
78
|
//#endregion
|
|
79
79
|
//#region src/constants.d.ts
|
|
80
|
+
/** Devframe runtime routes and static output conventions. */
|
|
80
81
|
declare const DEVFRAME_CONNECTION_META_FILENAME = "__connection.json";
|
|
81
82
|
/**
|
|
82
83
|
* Global key holding the serializable connection prepared by
|
|
@@ -87,7 +88,7 @@ declare const DEVFRAME_CONNECTION_KEY = "__DEVFRAME_CONNECTION__";
|
|
|
87
88
|
/**
|
|
88
89
|
* Route the WebSocket RPC endpoint is bound to, relative to a devframe's
|
|
89
90
|
* base path. Sits next to `__connection.json` so the deployed SPA can reach
|
|
90
|
-
* it on the same origin it loaded from
|
|
91
|
+
* it on the same origin it loaded from: the dev server shares one port for
|
|
91
92
|
* both HTTP and WS, and a host server (Vite, etc.) can mount the WS upgrade
|
|
92
93
|
* handler here without colliding with its own routes (HMR, asset serving).
|
|
93
94
|
*/
|
|
@@ -97,7 +98,7 @@ declare const DEVFRAME_WS_ROUTE = "__ws";
|
|
|
97
98
|
* path. A single method-dispatched route: `GET` opens the event stream
|
|
98
99
|
* (server→client), `POST` carries RPC frames (client→server). Sits next to
|
|
99
100
|
* `__connection.json` so the deployed SPA reaches it on the same origin it
|
|
100
|
-
* loaded from
|
|
101
|
+
* loaded from; the transport for hosts and proxies where the WebSocket
|
|
101
102
|
* upgrade isn't available.
|
|
102
103
|
*/
|
|
103
104
|
declare const DEVFRAME_SSE_ROUTE = "__sse";
|
|
@@ -111,7 +112,7 @@ declare const DEVFRAME_SSE_SESSION_HEADER = "x-birpc-session";
|
|
|
111
112
|
/**
|
|
112
113
|
* Route the Streamable-HTTP MCP endpoint is bound to, relative to a
|
|
113
114
|
* devframe's base path. Sits next to `__connection.json` and the WS route
|
|
114
|
-
* so an MCP client reaches it on the same origin the SPA loaded from
|
|
115
|
+
* so an MCP client reaches it on the same origin the SPA loaded from; the
|
|
115
116
|
* dev server shares one port for HTTP, WS, and MCP. Opt-in via `cli.mcp`.
|
|
116
117
|
*/
|
|
117
118
|
declare const DEVFRAME_MCP_ROUTE = "__mcp";
|
|
@@ -156,7 +157,7 @@ declare const DEVFRAME_VIEWER_ORIGIN_TOKEN_QUERY_PARAM = "devframe_viewer_origin
|
|
|
156
157
|
/**
|
|
157
158
|
* `postMessage` type the remote-assets fallback page posts to `window.parent`
|
|
158
159
|
* on load. That page is what a devframe serves (with a 502) when its client
|
|
159
|
-
* assets can be reached neither locally nor through their CDN provider
|
|
160
|
+
* assets can be reached neither locally nor through their CDN provider; the
|
|
160
161
|
* message lets an embedding viewer replace the bare page with its own UI
|
|
161
162
|
* (`@devframes/hub-ui` does, in its iframe view). Payload shape:
|
|
162
163
|
* `RemoteAssetsErrorMessage` (`devframe/types`).
|
|
@@ -164,7 +165,7 @@ declare const DEVFRAME_VIEWER_ORIGIN_TOKEN_QUERY_PARAM = "devframe_viewer_origin
|
|
|
164
165
|
declare const DEVFRAME_REMOTE_ASSETS_ERROR_MESSAGE_TYPE: string;
|
|
165
166
|
/**
|
|
166
167
|
* Prefix that marks an RPC method as callable before a connection is
|
|
167
|
-
* trusted. This is the *only* rule the pre-trust gate applies
|
|
168
|
+
* trusted. This is the *only* rule the pre-trust gate applies; there is no
|
|
168
169
|
* per-method allowlist. Any handshake method a host adapter needs to reach
|
|
169
170
|
* before authentication must be named `anonymous:<rest>` (e.g.
|
|
170
171
|
* `anonymous:devframe:auth`).
|
package/dist/constants.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { t as DEVFRAME_EVENTS } from "./events-
|
|
1
|
+
import { t as DEVFRAME_EVENTS } from "./events-BV4Dj59a.mjs";
|
|
2
2
|
//#region src/constants.ts
|
|
3
|
+
/** Devframe runtime routes and static output conventions. */
|
|
3
4
|
const DEVFRAME_CONNECTION_META_FILENAME = "__connection.json";
|
|
4
5
|
/**
|
|
5
6
|
* Global key holding the serializable connection prepared by
|
|
@@ -10,7 +11,7 @@ const DEVFRAME_CONNECTION_KEY = "__DEVFRAME_CONNECTION__";
|
|
|
10
11
|
/**
|
|
11
12
|
* Route the WebSocket RPC endpoint is bound to, relative to a devframe's
|
|
12
13
|
* base path. Sits next to `__connection.json` so the deployed SPA can reach
|
|
13
|
-
* it on the same origin it loaded from
|
|
14
|
+
* it on the same origin it loaded from: the dev server shares one port for
|
|
14
15
|
* both HTTP and WS, and a host server (Vite, etc.) can mount the WS upgrade
|
|
15
16
|
* handler here without colliding with its own routes (HMR, asset serving).
|
|
16
17
|
*/
|
|
@@ -20,7 +21,7 @@ const DEVFRAME_WS_ROUTE = "__ws";
|
|
|
20
21
|
* path. A single method-dispatched route: `GET` opens the event stream
|
|
21
22
|
* (server→client), `POST` carries RPC frames (client→server). Sits next to
|
|
22
23
|
* `__connection.json` so the deployed SPA reaches it on the same origin it
|
|
23
|
-
* loaded from
|
|
24
|
+
* loaded from; the transport for hosts and proxies where the WebSocket
|
|
24
25
|
* upgrade isn't available.
|
|
25
26
|
*/
|
|
26
27
|
const DEVFRAME_SSE_ROUTE = "__sse";
|
|
@@ -34,7 +35,7 @@ const DEVFRAME_SSE_SESSION_HEADER = "x-birpc-session";
|
|
|
34
35
|
/**
|
|
35
36
|
* Route the Streamable-HTTP MCP endpoint is bound to, relative to a
|
|
36
37
|
* devframe's base path. Sits next to `__connection.json` and the WS route
|
|
37
|
-
* so an MCP client reaches it on the same origin the SPA loaded from
|
|
38
|
+
* so an MCP client reaches it on the same origin the SPA loaded from; the
|
|
38
39
|
* dev server shares one port for HTTP, WS, and MCP. Opt-in via `cli.mcp`.
|
|
39
40
|
*/
|
|
40
41
|
const DEVFRAME_MCP_ROUTE = "__mcp";
|
|
@@ -79,7 +80,7 @@ const DEVFRAME_VIEWER_ORIGIN_TOKEN_QUERY_PARAM = "devframe_viewer_origin_token";
|
|
|
79
80
|
/**
|
|
80
81
|
* `postMessage` type the remote-assets fallback page posts to `window.parent`
|
|
81
82
|
* on load. That page is what a devframe serves (with a 502) when its client
|
|
82
|
-
* assets can be reached neither locally nor through their CDN provider
|
|
83
|
+
* assets can be reached neither locally nor through their CDN provider; the
|
|
83
84
|
* message lets an embedding viewer replace the bare page with its own UI
|
|
84
85
|
* (`@devframes/hub-ui` does, in its iframe view). Payload shape:
|
|
85
86
|
* `RemoteAssetsErrorMessage` (`devframe/types`).
|
|
@@ -87,7 +88,7 @@ const DEVFRAME_VIEWER_ORIGIN_TOKEN_QUERY_PARAM = "devframe_viewer_origin_token";
|
|
|
87
88
|
const DEVFRAME_REMOTE_ASSETS_ERROR_MESSAGE_TYPE = DEVFRAME_EVENTS.postMessage.remoteAssetsError;
|
|
88
89
|
/**
|
|
89
90
|
* Prefix that marks an RPC method as callable before a connection is
|
|
90
|
-
* trusted. This is the *only* rule the pre-trust gate applies
|
|
91
|
+
* trusted. This is the *only* rule the pre-trust gate applies; there is no
|
|
91
92
|
* per-method allowlist. Any handshake method a host adapter needs to reach
|
|
92
93
|
* before authentication must be named `anonymous:<rest>` (e.g.
|
|
93
94
|
* `anonymous:devframe:auth`).
|