devframe 0.8.1 → 0.9.0-beta.1
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-CttmCMBi.mjs +70 -0
- package/dist/_shared-DmpWW-HH.d.mts +43 -0
- package/dist/adapters/build.d.mts +1 -1
- package/dist/adapters/build.mjs +6 -5
- package/dist/adapters/cac.d.mts +1 -1
- package/dist/adapters/cac.mjs +157 -1
- package/dist/adapters/dev.d.mts +25 -34
- package/dist/adapters/dev.mjs +2 -1
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/initiate.d.mts +223 -0
- package/dist/adapters/initiate.mjs +2 -0
- package/dist/adapters/mcp.d.mts +26 -2
- package/dist/adapters/mcp.mjs +2 -2
- package/dist/cli/main.mjs +2 -2
- package/dist/client/index.d.mts +70 -6
- package/dist/client/index.mjs +743 -408
- package/dist/constants.d.mts +19 -6
- package/dist/constants.mjs +19 -6
- package/dist/{context-CQefP2jR.mjs → context-C33rR7n0.mjs} +1 -1
- package/dist/{context-DFzmxCLa.d.mts → context-CSCwoABx.d.mts} +1 -1
- package/dist/{host-h3-Kz7t5Xab.mjs → context-Du11TLcO.mjs} +5 -255
- package/dist/dev-BEveeA5H.mjs +233 -0
- package/dist/{devframe-qgCKL683.d.mts → devframe-Bdd9YXTy.d.mts} +88 -25
- package/dist/{diagnostics-B5-qHeqD.mjs → diagnostics-DLYH5oD3.mjs} +20 -0
- package/dist/dist-D8jAMwxU.mjs +227 -0
- package/dist/helpers/vite.d.mts +43 -39
- package/dist/helpers/vite.mjs +26 -38
- package/dist/host-agent-CpbAoqBx.mjs +230 -0
- package/dist/host-h3-CzCZwtuV.mjs +26 -0
- package/dist/{fetch-CK0S253E.mjs → http-DLr_cJZ7.mjs} +42 -4
- package/dist/{index-B7RgLw--.d.mts → index-CZRd2K1C.d.mts} +2 -2
- package/dist/{index-Dbw1p5ch.d.mts → index-DSCq4M4q.d.mts} +2 -31
- package/dist/index.d.mts +9 -4
- package/dist/index.mjs +8 -1
- package/dist/{instance-registry-D6fxYu36.mjs → instance-registry-BQqGoDO9.mjs} +9 -2
- package/dist/instance-shell-DBTXTSjN.d.mts +264 -0
- package/dist/instance-shell-KRdee1QF.mjs +485 -0
- package/dist/internal/index.d.mts +150 -0
- package/dist/internal/index.mjs +7 -0
- package/dist/node/auth.d.mts +2 -2
- package/dist/node/hub-internals.d.mts +2 -14
- package/dist/node/hub-internals.mjs +2 -2
- package/dist/node/index.d.mts +3 -267
- package/dist/node/index.mjs +3 -5
- package/dist/recipes/common-rpc-functions.d.mts +3 -3
- package/dist/recipes/interactive-auth.d.mts +3 -3
- package/dist/recipes/interactive-auth.mjs +6 -6
- package/dist/rolldown-runtime-JspESFgx.mjs +35 -0
- package/dist/rpc/dump.d.mts +77 -1
- package/dist/rpc/dump.mjs +1 -1
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +3 -17
- package/dist/rpc/transports/sse-client.d.mts +2 -0
- package/dist/rpc/transports/sse-client.mjs +142 -0
- package/dist/rpc/transports/sse-server.d.mts +61 -0
- package/dist/rpc/transports/sse-server.mjs +209 -0
- package/dist/rpc/transports/ws-bun.d.mts +35 -0
- package/dist/rpc/transports/ws-bun.mjs +31 -0
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-client.mjs +10 -18
- package/dist/rpc/transports/ws-server.d.mts +2 -2
- package/dist/rpc/transports/ws-server.mjs +2 -214
- package/dist/rpc-core-CGctXToO.d.mts +48 -0
- package/dist/rpc-core-CqcJkAu9.mjs +81 -0
- package/dist/{serialization-C8Mnw9hK.mjs → serialization-BHY8M5NQ.mjs} +1 -1
- package/dist/{shared-state-6kHolYZy.mjs → shared-state-fRRbRUtD.mjs} +1 -1
- package/dist/sse-client-BsIK3hMD.d.mts +37 -0
- package/dist/{dump-CgZShDRB.mjs → static-CvjkO8QE.mjs} +2 -265
- package/dist/{storage-Dzoc3NVC.mjs → storage-BcmVEJRc.mjs} +2 -2
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +1 -6
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/launch-editor.mjs +1 -25
- package/dist/utils/open.mjs +1 -1
- package/dist/utils/serve-static.mjs +1 -1
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -1
- package/dist/utils/simple-schema.d.mts +101 -1
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/validation-BiuDXTKW.mjs +266 -0
- package/dist/wire-codec-9VhIKnyp.mjs +58 -0
- package/dist/{ws-client-B6Tnr0ic.d.mts → ws-client-CdNuATYa.d.mts} +6 -1
- package/dist/ws-server-Bk1hOG3X.mjs +267 -0
- package/dist/{ws-server-J-zkiOyp.d.mts → ws-server-Ces08fjP.d.mts} +102 -13
- package/package.json +10 -9
- package/skills/devframe/SKILL.md +84 -85
- package/dist/_shared-bWRzeSa0.mjs +0 -19
- package/dist/adapters/cli.d.mts +0 -11
- package/dist/adapters/cli.mjs +0 -6
- package/dist/cac-B1LM3zit.mjs +0 -157
- package/dist/dev-BSHFZGZr.mjs +0 -437
- package/dist/http-Dvgxujcu.mjs +0 -38
- package/dist/index-vAX6bYuc.d.mts +0 -78
- package/dist/recipes/open-helpers.d.mts +0 -6
- package/dist/recipes/open-helpers.mjs +0 -6
- package/dist/server-CXaDDUl0.mjs +0 -148
- package/dist/server-E9z4ZWbd.d.mts +0 -132
- package/dist/simple-schema-BDzLeJDk.d.mts +0 -102
- package/dist/utils/promise.d.mts +0 -8
- package/dist/utils/promise.mjs +0 -15
- package/dist/utils/scope.d.mts +0 -11
- package/dist/utils/scope.mjs +0 -15
- package/dist/{open-Deb5xmIT.mjs → open-Dz4V4irZ.mjs} +1 -1
|
@@ -1,214 +1,2 @@
|
|
|
1
|
-
import "../../
|
|
2
|
-
|
|
3
|
-
import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-CbAV5rFI.mjs";
|
|
4
|
-
import { n as randomToken, r as timingSafeEqual } from "../../crypto-token-XCqTSMg9.mjs";
|
|
5
|
-
import { createServer } from "node:http";
|
|
6
|
-
import { createServer as createServer$1 } from "node:https";
|
|
7
|
-
import crossws from "crossws/adapters/node";
|
|
8
|
-
//#region src/rpc/transports/ws-server.ts
|
|
9
|
-
/**
|
|
10
|
-
* Create a live, token-protected origin allowlist for external browser
|
|
11
|
-
* viewers. Pass it to {@link WsRpcTransportOptions.allowedOrigins}, then use
|
|
12
|
-
* `registerFromUrl()` in the connection metadata handler to authorize a
|
|
13
|
-
* viewer without sharing a mutable array or disabling DNS-rebinding protection.
|
|
14
|
-
*/
|
|
15
|
-
function createWsOriginRegistry(options = {}) {
|
|
16
|
-
const token = randomToken();
|
|
17
|
-
const origins = new Set(options.allowedOrigins ?? []);
|
|
18
|
-
function normalizeOrigin(origin) {
|
|
19
|
-
if (!origin) return;
|
|
20
|
-
try {
|
|
21
|
-
const url = new URL(origin);
|
|
22
|
-
const normalized = url.origin === "null" ? `${url.protocol}//${url.host}` : url.origin;
|
|
23
|
-
return origin === normalized ? normalized : void 0;
|
|
24
|
-
} catch {}
|
|
25
|
-
}
|
|
26
|
-
function registerOrigin(origin, candidateToken) {
|
|
27
|
-
const normalized = normalizeOrigin(origin);
|
|
28
|
-
if (!normalized || !candidateToken || !timingSafeEqual(token, candidateToken)) return false;
|
|
29
|
-
if (options.validateOrigin && !options.validateOrigin(normalized)) return false;
|
|
30
|
-
origins.add(normalized);
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
token,
|
|
35
|
-
registerFromUrl(url) {
|
|
36
|
-
let parsed;
|
|
37
|
-
try {
|
|
38
|
-
parsed = new URL(url, "http://localhost");
|
|
39
|
-
} catch {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const origin = parsed.searchParams.get("devframe_viewer_origin") ?? void 0;
|
|
43
|
-
return registerOrigin(origin, parsed.searchParams.get("devframe_viewer_origin_token") ?? void 0) ? origin : void 0;
|
|
44
|
-
},
|
|
45
|
-
isAllowed(origin) {
|
|
46
|
-
return isAllowedOrigin(origin, [...origins]);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
let sessionId = 0;
|
|
51
|
-
const EMPTY_DEFS = /* @__PURE__ */ new Map();
|
|
52
|
-
function NOOP() {}
|
|
53
|
-
/** Compare two URL paths ignoring a trailing slash. */
|
|
54
|
-
function pathMatches(a, b) {
|
|
55
|
-
const strip = (p) => p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
56
|
-
return strip(a) === strip(b);
|
|
57
|
-
}
|
|
58
|
-
function isLoopbackHostname(hostname) {
|
|
59
|
-
const h = hostname.replace(/^\[|\]$/g, "");
|
|
60
|
-
return h === "localhost" || h === "127.0.0.1" || h === "::1" || h.endsWith(".localhost") || h.startsWith("127.");
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Default origin policy for a localhost dev tool: allow requests with no
|
|
64
|
-
* `Origin` header (native, non-browser clients), allow any loopback origin
|
|
65
|
-
* (so cross-port localhost dev setups keep working), and allow explicitly
|
|
66
|
-
* configured origins. Everything else — a real remote page in the dev's
|
|
67
|
-
* browser — is rejected.
|
|
68
|
-
*/
|
|
69
|
-
function isAllowedOrigin(origin, allowedOrigins) {
|
|
70
|
-
if (!origin) return true;
|
|
71
|
-
if (allowedOrigins.includes(origin)) return true;
|
|
72
|
-
try {
|
|
73
|
-
return isLoopbackHostname(new URL(origin).hostname);
|
|
74
|
-
} catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function isWsOriginRegistry(value) {
|
|
79
|
-
return !!value && !Array.isArray(value);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Route `upgrade` events on a server to the crossws adapter, optionally
|
|
83
|
-
* filtered to a single `path`. Non-matching requests are left untouched so
|
|
84
|
-
* other upgrade listeners (e.g. a Vite dev server's HMR socket) can claim
|
|
85
|
-
* them, unless `destroyUnmatched` is set. Returns a detach function that
|
|
86
|
-
* removes the listener.
|
|
87
|
-
*/
|
|
88
|
-
function routeUpgrades(server, ws, path, destroyUnmatched, allowedOrigins) {
|
|
89
|
-
const listener = (req, socket, head) => {
|
|
90
|
-
socket.on("error", () => {});
|
|
91
|
-
if (path) {
|
|
92
|
-
let pathname = req.url ?? "/";
|
|
93
|
-
try {
|
|
94
|
-
pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
95
|
-
} catch {}
|
|
96
|
-
if (!pathMatches(pathname, path)) {
|
|
97
|
-
if (destroyUnmatched) {
|
|
98
|
-
socket.write("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
|
|
99
|
-
socket.destroy();
|
|
100
|
-
}
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
const originAllowed = isWsOriginRegistry(allowedOrigins) ? allowedOrigins.isAllowed(req.headers.origin) : isAllowedOrigin(req.headers.origin, allowedOrigins || []);
|
|
105
|
-
if (allowedOrigins !== false && !originAllowed) {
|
|
106
|
-
socket.write("HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n");
|
|
107
|
-
socket.destroy();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
ws.handleUpgrade(req, socket, head);
|
|
111
|
-
};
|
|
112
|
-
server.on("upgrade", listener);
|
|
113
|
-
return () => server.off("upgrade", listener);
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Attach a WebSocket transport to an existing RPC group, powered by
|
|
117
|
-
* [crossws](https://crossws.h3.dev). Either attach to an existing HTTP(S)
|
|
118
|
-
* `server` (sharing its port, optionally scoped to a `path`), or let this
|
|
119
|
-
* helper create a standalone server from `port` / `host` / `https`.
|
|
120
|
-
*
|
|
121
|
-
* Returns the crossws node adapter plus `detach` (remove the upgrade
|
|
122
|
-
* listener from a shared `server`) and `close` (full deterministic
|
|
123
|
-
* teardown).
|
|
124
|
-
*/
|
|
125
|
-
function attachWsRpcTransport(rpcGroup, options = {}) {
|
|
126
|
-
const { server, port, host = "localhost", path, destroyUnmatched = false, https, allowedOrigins, onConnected = NOOP, onDisconnected = NOOP, definitions = EMPTY_DEFS, serialize: serializeOverride, deserialize: deserializeOverride } = options;
|
|
127
|
-
const states = /* @__PURE__ */ new WeakMap();
|
|
128
|
-
const ws = crossws({ hooks: {
|
|
129
|
-
open: (peer) => {
|
|
130
|
-
const meta = {
|
|
131
|
-
id: sessionId++,
|
|
132
|
-
peer,
|
|
133
|
-
subscribedStates: /* @__PURE__ */ new Set()
|
|
134
|
-
};
|
|
135
|
-
const pendingRequestMethods = /* @__PURE__ */ new Map();
|
|
136
|
-
const state = {
|
|
137
|
-
meta,
|
|
138
|
-
channel: void 0
|
|
139
|
-
};
|
|
140
|
-
const channel = {
|
|
141
|
-
post: (data) => {
|
|
142
|
-
peer.send(data);
|
|
143
|
-
},
|
|
144
|
-
on: (fn) => {
|
|
145
|
-
state.onMessage = fn;
|
|
146
|
-
},
|
|
147
|
-
serialize: serializeOverride ?? ((msg) => {
|
|
148
|
-
let method;
|
|
149
|
-
if (msg.t === "q") method = msg.m;
|
|
150
|
-
else {
|
|
151
|
-
method = pendingRequestMethods.get(msg.i);
|
|
152
|
-
pendingRequestMethods.delete(msg.i);
|
|
153
|
-
}
|
|
154
|
-
if (!(msg.t === "s" && "e" in msg) && !!method && definitions.get(method)?.jsonSerializable === true) return strictJsonStringify(msg, method ?? "");
|
|
155
|
-
return `s:${structuredCloneStringify(msg)}`;
|
|
156
|
-
}),
|
|
157
|
-
deserialize: deserializeOverride ?? ((raw) => {
|
|
158
|
-
const msg = raw.startsWith("s:") ? structuredCloneParse(raw.slice(2)) : JSON.parse(raw);
|
|
159
|
-
if (msg.t === "q" && msg.i && msg.m) pendingRequestMethods.set(msg.i, msg.m);
|
|
160
|
-
return msg;
|
|
161
|
-
}),
|
|
162
|
-
meta
|
|
163
|
-
};
|
|
164
|
-
state.channel = channel;
|
|
165
|
-
states.set(peer, state);
|
|
166
|
-
rpcGroup.updateChannels((channels) => {
|
|
167
|
-
channels.push(channel);
|
|
168
|
-
});
|
|
169
|
-
onConnected(peer, meta);
|
|
170
|
-
},
|
|
171
|
-
message: (peer, message) => {
|
|
172
|
-
states.get(peer)?.onMessage?.(message.text());
|
|
173
|
-
},
|
|
174
|
-
close: (peer) => {
|
|
175
|
-
const state = states.get(peer);
|
|
176
|
-
if (!state) return;
|
|
177
|
-
states.delete(peer);
|
|
178
|
-
rpcGroup.updateChannels((channels) => {
|
|
179
|
-
const index = channels.indexOf(state.channel);
|
|
180
|
-
if (index >= 0) channels.splice(index, 1);
|
|
181
|
-
});
|
|
182
|
-
onDisconnected(peer, state.meta);
|
|
183
|
-
}
|
|
184
|
-
} });
|
|
185
|
-
let detach = NOOP;
|
|
186
|
-
let ownedServer;
|
|
187
|
-
if (server) detach = routeUpgrades(server, ws, path, destroyUnmatched, allowedOrigins);
|
|
188
|
-
else if (https) {
|
|
189
|
-
ownedServer = createServer$1(https);
|
|
190
|
-
detach = routeUpgrades(ownedServer, ws, path, true, allowedOrigins);
|
|
191
|
-
ownedServer.listen(port, host);
|
|
192
|
-
} else {
|
|
193
|
-
ownedServer = createServer((_req, res) => {
|
|
194
|
-
res.writeHead(426, { "content-type": "text/plain" });
|
|
195
|
-
res.end("Upgrade Required");
|
|
196
|
-
});
|
|
197
|
-
detach = routeUpgrades(ownedServer, ws, path, true, allowedOrigins);
|
|
198
|
-
ownedServer.listen(port, host);
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
ws,
|
|
202
|
-
detach,
|
|
203
|
-
async close() {
|
|
204
|
-
detach();
|
|
205
|
-
ws.closeAll(void 0, void 0, true);
|
|
206
|
-
if (ownedServer) {
|
|
207
|
-
const srv = ownedServer;
|
|
208
|
-
await new Promise((r) => srv.close(() => r()));
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
//#endregion
|
|
214
|
-
export { attachWsRpcTransport, createWsOriginRegistry, isAllowedOrigin, isLoopbackHostname };
|
|
1
|
+
import { a as isLoopbackHostname, i as isAllowedOrigin, n as createWsOriginRegistry, r as createWsRpcPeerHooks, t as attachWsRpcTransport } from "../../ws-server-Bk1hOG3X.mjs";
|
|
2
|
+
export { attachWsRpcTransport, createWsOriginRegistry, createWsRpcPeerHooks, isAllowedOrigin, isLoopbackHostname };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { $ as DevframeRpcClientFunctions, G as DevframeNodeRpcSession, et as DevframeRpcServerFunctions, p as DevframeAuthHandler, x as DevframeNodeContext } from "./devframe-Bdd9YXTy.mjs";
|
|
2
|
+
import { d as DevframeRpcConnection, u as DevframeNodeRpcSessionMeta } from "./ws-server-Ces08fjP.mjs";
|
|
3
|
+
import "./index-CZRd2K1C.mjs";
|
|
4
|
+
import { BirpcGroup, EventOptions } from "birpc";
|
|
5
|
+
//#region src/node/rpc-core.d.ts
|
|
6
|
+
interface CreateContextRpcServerOptions {
|
|
7
|
+
context: DevframeNodeContext;
|
|
8
|
+
/**
|
|
9
|
+
* Auth intent: `true`/omitted gates by default, `false` opts out (auto-trust
|
|
10
|
+
* handshake shim), a {@link DevframeAuthHandler} installs a custom scheme.
|
|
11
|
+
*/
|
|
12
|
+
auth?: boolean | DevframeAuthHandler;
|
|
13
|
+
/** Lower-level per-call gate by method name and session, without a full handler. */
|
|
14
|
+
authorize?: (methodName: string, session: DevframeNodeRpcSession) => boolean;
|
|
15
|
+
/** Called once per new RPC connection, right after its session is created. */
|
|
16
|
+
onPeerConnect?: (connection: DevframeRpcConnection, session: DevframeNodeRpcSession) => void;
|
|
17
|
+
/** Called once per closed RPC connection, after the transport's disconnect bookkeeping. */
|
|
18
|
+
onPeerDisconnect?: (connection: DevframeRpcConnection, meta: DevframeNodeRpcSessionMeta) => void;
|
|
19
|
+
/** Forwarded verbatim to birpc's `rpcOptions` so a host keeps seeing RPC failures. */
|
|
20
|
+
rpcOptions?: Pick<EventOptions<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>, 'onFunctionError' | 'onGeneralError'>;
|
|
21
|
+
}
|
|
22
|
+
interface ContextRpcServer {
|
|
23
|
+
rpcGroup: BirpcGroup<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>;
|
|
24
|
+
/** The resolved auth handler when `auth` was passed as one. */
|
|
25
|
+
authHandler?: DevframeAuthHandler;
|
|
26
|
+
/**
|
|
27
|
+
* Connection lifecycle handlers to wire into a transport binding
|
|
28
|
+
* (`attachWsRpcTransport`'s `onConnected` / `onDisconnected`, or any other
|
|
29
|
+
* crossws adapter's peer hooks via `createWsRpcPeerHooks`).
|
|
30
|
+
*/
|
|
31
|
+
onConnected?: (connection: DevframeRpcConnection, meta: DevframeNodeRpcSessionMeta) => void;
|
|
32
|
+
onDisconnected: (connection: DevframeRpcConnection, meta: DevframeNodeRpcSessionMeta) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Bind a devframe context's registered RPC functions to a birpc group,
|
|
36
|
+
* transport-agnostically — the shared core under the instance shell's own
|
|
37
|
+
* HTTP+WS binding (Node http + WS) and the Bun fetch-upgrade tier of
|
|
38
|
+
* `createHandler`.
|
|
39
|
+
*
|
|
40
|
+
* Owns everything about serving RPC that is independent of *how* peers
|
|
41
|
+
* connect: the auth handler's function registration, the
|
|
42
|
+
* `AsyncLocalStorage`-based session resolver (so
|
|
43
|
+
* `ctx.rpc.getCurrentRpcSession()` works inside handlers), the
|
|
44
|
+
* `authorize` gate, and the `auth: false` auto-trust handshake shim.
|
|
45
|
+
*/
|
|
46
|
+
declare function createContextRpcServer(options: CreateContextRpcServerOptions): ContextRpcServer;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { CreateContextRpcServerOptions as n, createContextRpcServer as r, ContextRpcServer as t };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { n as __exportAll } from "./rolldown-runtime-JspESFgx.mjs";
|
|
2
|
+
import { createRpcServer } from "./rpc/server.mjs";
|
|
3
|
+
import { t as diagnostics } from "./diagnostics-DLYH5oD3.mjs";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
//#region src/node/rpc-core.ts
|
|
6
|
+
var rpc_core_exports = /* @__PURE__ */ __exportAll({ createContextRpcServer: () => createContextRpcServer });
|
|
7
|
+
/**
|
|
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
|
|
10
|
+
* HTTP+WS binding (Node http + WS) and the Bun fetch-upgrade tier of
|
|
11
|
+
* `createHandler`.
|
|
12
|
+
*
|
|
13
|
+
* Owns everything about serving RPC that is independent of *how* peers
|
|
14
|
+
* connect: the auth handler's function registration, the
|
|
15
|
+
* `AsyncLocalStorage`-based session resolver (so
|
|
16
|
+
* `ctx.rpc.getCurrentRpcSession()` works inside handlers), the
|
|
17
|
+
* `authorize` gate, and the `auth: false` auto-trust handshake shim.
|
|
18
|
+
*/
|
|
19
|
+
function createContextRpcServer(options) {
|
|
20
|
+
const { context } = options;
|
|
21
|
+
const rpcHost = context.rpc;
|
|
22
|
+
const asyncStorage = new AsyncLocalStorage();
|
|
23
|
+
const authHandler = typeof options.auth === "object" ? options.auth : void 0;
|
|
24
|
+
const effectiveAuthorize = options.authorize ?? authHandler?.authorize;
|
|
25
|
+
if (authHandler) {
|
|
26
|
+
for (const fn of authHandler.rpcFunctions) if (!rpcHost.definitions.has(fn.name)) rpcHost.register(fn);
|
|
27
|
+
}
|
|
28
|
+
const rpcGroup = createRpcServer(rpcHost.functions, { rpcOptions: {
|
|
29
|
+
onFunctionError: options.rpcOptions?.onFunctionError,
|
|
30
|
+
onGeneralError: options.rpcOptions?.onGeneralError,
|
|
31
|
+
resolver(name, fn) {
|
|
32
|
+
const rpc = this;
|
|
33
|
+
if (!fn) return void 0;
|
|
34
|
+
return async function(...args) {
|
|
35
|
+
const meta = rpc.$meta;
|
|
36
|
+
if (effectiveAuthorize && !effectiveAuthorize(name, {
|
|
37
|
+
meta,
|
|
38
|
+
rpc
|
|
39
|
+
})) throw diagnostics.DF0036({ name });
|
|
40
|
+
return await asyncStorage.run({
|
|
41
|
+
rpc,
|
|
42
|
+
meta
|
|
43
|
+
}, async () => {
|
|
44
|
+
return (await fn).apply(this, args);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
} });
|
|
49
|
+
rpcHost._rpcGroup = rpcGroup;
|
|
50
|
+
rpcHost._asyncStorage = asyncStorage;
|
|
51
|
+
rpcHost._authDisabled = options.auth === false;
|
|
52
|
+
if (options.auth === false && !rpcHost.definitions.has("anonymous:devframe:auth")) rpcHost.register({
|
|
53
|
+
name: "anonymous:devframe:auth",
|
|
54
|
+
type: "action",
|
|
55
|
+
handler: () => {
|
|
56
|
+
const session = rpcHost.getCurrentRpcSession();
|
|
57
|
+
if (session) session.meta.isTrusted = true;
|
|
58
|
+
return { isTrusted: true };
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const onConnected = authHandler || options.onPeerConnect ? (connection, meta) => {
|
|
62
|
+
const session = {
|
|
63
|
+
meta,
|
|
64
|
+
rpc: rpcGroup.clients.find((client) => client.$meta === meta)
|
|
65
|
+
};
|
|
66
|
+
authHandler?.onConnect(connection, session);
|
|
67
|
+
options.onPeerConnect?.(connection, session);
|
|
68
|
+
} : void 0;
|
|
69
|
+
const onDisconnected = (connection, meta) => {
|
|
70
|
+
options.onPeerDisconnect?.(connection, meta);
|
|
71
|
+
rpcHost._emitSessionDisconnected(meta);
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
rpcGroup,
|
|
75
|
+
authHandler,
|
|
76
|
+
onConnected,
|
|
77
|
+
onDisconnected
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { rpc_core_exports as n, createContextRpcServer as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as diagnostics } from "./diagnostics-hwjXp_UV.mjs";
|
|
2
2
|
//#region src/rpc/serialization.ts
|
|
3
3
|
/**
|
|
4
|
-
* Wire format used by the
|
|
4
|
+
* Wire format used by the live RPC transports (WebSocket and SSE).
|
|
5
5
|
*
|
|
6
6
|
* - **JSON (default, unprefixed):** payload is plain JSON text. Used when
|
|
7
7
|
* the dispatched method is declared `jsonSerializable: true`. Encoded
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createEventEmitter } from "./utils/events.mjs";
|
|
2
2
|
import { nanoid } from "./utils/nanoid.mjs";
|
|
3
|
-
//#region ../../node_modules/.pnpm/immer@11.1.
|
|
3
|
+
//#region ../../node_modules/.pnpm/immer@11.1.16/node_modules/immer/dist/immer.mjs
|
|
4
4
|
var NOTHING = Symbol.for("immer-nothing");
|
|
5
5
|
var DRAFTABLE = Symbol.for("immer-draftable");
|
|
6
6
|
var DRAFT_STATE = Symbol.for("immer-state");
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { v as RpcFunctionDefinitionAny } from "./types-CnJSgRVa.mjs";
|
|
2
|
+
import { ChannelOptions } from "birpc";
|
|
3
|
+
//#region src/rpc/transports/sse-client.d.ts
|
|
4
|
+
interface SseRpcChannelOptions {
|
|
5
|
+
/** Resolved `http(s)://` URL of the SSE endpoint. */
|
|
6
|
+
url: string;
|
|
7
|
+
onConnected?: () => void;
|
|
8
|
+
onError?: (e: Error) => void;
|
|
9
|
+
onDisconnected?: () => void;
|
|
10
|
+
authToken?: string;
|
|
11
|
+
/**
|
|
12
|
+
* RPC function definitions (or just the `jsonSerializable` flag per
|
|
13
|
+
* method) used to dispatch the per-call wire serializer — same contract
|
|
14
|
+
* as the WS channel.
|
|
15
|
+
*/
|
|
16
|
+
definitions?: ReadonlyMap<string, Pick<RpcFunctionDefinitionAny, 'jsonSerializable'>>;
|
|
17
|
+
/** Fetch implementation. Default: `globalThis.fetch`. */
|
|
18
|
+
fetch?: typeof globalThis.fetch;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build a birpc `ChannelOptions` object backed by an SSE stream (server →
|
|
22
|
+
* client) and HTTP `POST` (client → server) — the WebSocket-free counterpart
|
|
23
|
+
* to `createWsRpcChannel`, wire-compatible with `attachSseRpcTransport`.
|
|
24
|
+
*
|
|
25
|
+
* The stream is consumed via `fetch` streaming (not `EventSource`), so it
|
|
26
|
+
* works in browsers and server runtimes alike. The server's first frame
|
|
27
|
+
* (`event: session`) carries the session id; every `POST` echoes it in the
|
|
28
|
+
* `x-birpc-session` header. A response to a client-initiated request comes
|
|
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
|
|
31
|
+
* the WS channel's closed-is-done semantics.
|
|
32
|
+
*/
|
|
33
|
+
declare function createSseRpcChannel(options: SseRpcChannelOptions): ChannelOptions & {
|
|
34
|
+
close: () => void;
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { createSseRpcChannel as n, SseRpcChannelOptions as t };
|