devframe 0.9.8 → 0.9.10
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-CCzf9Hub.d.mts +83 -0
- package/dist/_shared-U8D-xzrp.mjs +115 -0
- package/dist/adapters/build.d.mts +6 -6
- package/dist/adapters/build.mjs +33 -36
- package/dist/adapters/cac.d.mts +12 -1
- package/dist/adapters/cac.mjs +8 -8
- package/dist/adapters/dev.d.mts +17 -17
- package/dist/adapters/dev.mjs +2 -2
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/initiate.d.mts +31 -28
- package/dist/adapters/initiate.mjs +1 -1
- package/dist/adapters/mcp.d.mts +28 -14
- package/dist/adapters/mcp.mjs +76 -40
- 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 +90 -52
- 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-omlma_1n.mjs → context-B29Oh0oA.mjs} +166 -93
- package/dist/{context-DftYyXaR.d.mts → context-BJiKJqyW.d.mts} +5 -5
- package/dist/{context-CLF4-8Pp.d.mts → context-CHW4BZOj.d.mts} +203 -134
- package/dist/{context-KUqAfawQ.mjs → context-jXO5vzjH.mjs} +3 -3
- package/dist/{crypto-token-XCqTSMg9.mjs → crypto-token-TVbGGFuj.mjs} +1 -1
- package/dist/{dev-CzkPCJwi.mjs → dev-CRYHx7iG.mjs} +73 -40
- package/dist/{diagnostics-BXWW3VK-.mjs → diagnostics-DZA6KQ_Z.mjs} +32 -19
- package/dist/{events-4daw0uK9.mjs → events-BV4Dj59a.mjs} +2 -2
- package/dist/{services-install-CqqQVls5.mjs → host-agent-CKqSTEX9.mjs} +15 -151
- package/dist/{host-h3-fRbF9yor.mjs → host-h3-BROI6SQ4.mjs} +2 -2
- package/dist/in-page-channel/index.d.mts +14 -14
- package/dist/in-page-channel/index.mjs +63 -54
- package/dist/{index-D3k0BIhe.d.mts → index-CNC390b_.d.mts} +4 -4
- package/dist/{index-BzyopqxV.d.mts → index-pIVt92jP.d.mts} +9 -9
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +2 -2
- package/dist/{instance-registry-BjlMQbFB.mjs → instance-registry-DCq762YJ.mjs} +9 -9
- package/dist/{instance-shell-Tcp5hGoq.d.mts → instance-shell-DZipaP9k.d.mts} +18 -18
- package/dist/{instance-shell-CpVW4zG0.mjs → instance-shell-DvYCwrDy.mjs} +223 -67
- package/dist/internal/index.d.mts +45 -26
- 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-DMFzLSoH.mjs} +27 -7
- 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 +19 -12
- package/dist/rpc/dump.mjs +2 -2
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +2 -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-DlHd276T.mjs → rpc-core-CvkU23bQ.mjs} +14 -2
- package/dist/{rpc-core-B3W3z9ff.d.mts → rpc-core-DsyDViQy.d.mts} +4 -4
- package/dist/serialization-DFg5sUt6.mjs +116 -0
- package/dist/services-install-Ben4yh52.mjs +154 -0
- 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-Mwt6--el.mjs} +17 -9
- package/dist/{storage-BXNVhKyR.mjs → storage-B70AXK64.mjs} +2 -2
- 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-CfV1s0SF.mjs} +2 -2
- package/dist/{wire-codec-0K-o5MYW.mjs → wire-codec-BHGt0sSs.mjs} +3 -3
- package/dist/{static-DV_qUSRS.mjs → write-BuLCrn9h.mjs} +153 -137
- 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 +3 -6
- package/skills/devframe/SKILL.md +5 -3
- package/dist/_shared-BM3PdYli.mjs +0 -68
- package/dist/_shared-mtXpcJIv.d.mts +0 -41
- package/dist/diagnostics-CD8nlgll.mjs +0 -39
- package/dist/serialization-BGzEwAdr.mjs +0 -77
- package/dist/ws-server-Y_AumUQH.mjs +0 -294
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devframe",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.10",
|
|
5
5
|
"description": "Framework for building one portable devtool integration that runs in any viewer.",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"./utils/nanoid": "./dist/utils/nanoid.mjs",
|
|
57
57
|
"./utils/nostics": "./dist/utils/nostics.mjs",
|
|
58
58
|
"./utils/open": "./dist/utils/open.mjs",
|
|
59
|
+
"./utils/origin": "./dist/utils/origin.mjs",
|
|
59
60
|
"./utils/remote-assets": "./dist/utils/remote-assets.mjs",
|
|
60
61
|
"./utils/simple-schema": "./dist/utils/simple-schema.mjs",
|
|
61
62
|
"./utils/serve-static": "./dist/utils/serve-static.mjs",
|
|
@@ -76,21 +77,18 @@
|
|
|
76
77
|
],
|
|
77
78
|
"peerDependencies": {
|
|
78
79
|
"@modelcontextprotocol/client": "^2.0.0",
|
|
79
|
-
"@modelcontextprotocol/server": "^2.0.0",
|
|
80
80
|
"cac": "^7.0.0"
|
|
81
81
|
},
|
|
82
82
|
"peerDependenciesMeta": {
|
|
83
83
|
"@modelcontextprotocol/client": {
|
|
84
84
|
"optional": true
|
|
85
85
|
},
|
|
86
|
-
"@modelcontextprotocol/server": {
|
|
87
|
-
"optional": true
|
|
88
|
-
},
|
|
89
86
|
"cac": {
|
|
90
87
|
"optional": true
|
|
91
88
|
}
|
|
92
89
|
},
|
|
93
90
|
"dependencies": {
|
|
91
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
94
92
|
"@standard-schema/spec": "^1.1.0",
|
|
95
93
|
"birpc": "^4.2.0",
|
|
96
94
|
"crossws": "^0.4.12",
|
|
@@ -102,7 +100,6 @@
|
|
|
102
100
|
},
|
|
103
101
|
"devDependencies": {
|
|
104
102
|
"@modelcontextprotocol/client": "^2.0.0",
|
|
105
|
-
"@modelcontextprotocol/server": "^2.0.0",
|
|
106
103
|
"cac": "^7.0.0",
|
|
107
104
|
"get-port-please": "^3.2.0",
|
|
108
105
|
"immer": "^11.1.18",
|
package/skills/devframe/SKILL.md
CHANGED
|
@@ -405,7 +405,9 @@ defineRpcFunction({
|
|
|
405
405
|
})
|
|
406
406
|
```
|
|
407
407
|
|
|
408
|
-
Or register tools / resources directly on `ctx.agent.registerTool({ id, description, safety, handler })` and `ctx.agent.registerResource({ id, name, mimeType, read })`.
|
|
408
|
+
Or register tools / resources directly on `ctx.agent.registerTool({ id, description, safety, handler })` and `ctx.agent.registerResource({ id, name, mimeType, read })`.
|
|
409
|
+
|
|
410
|
+
The dev server serves this surface over HTTP automatically: the `mcp: 'auto'` default mounts the Streamable-HTTP route at `<base>__mcp` once the agent surface is non-empty (`mcp: true` forces on, `mcp: false` off). For stdio:
|
|
409
411
|
|
|
410
412
|
```ts
|
|
411
413
|
import { createMcpServer } from 'devframe/adapters/mcp'
|
|
@@ -413,7 +415,7 @@ import { createMcpServer } from 'devframe/adapters/mcp'
|
|
|
413
415
|
await createMcpServer(myDevframe, { transport: 'stdio' })
|
|
414
416
|
```
|
|
415
417
|
|
|
416
|
-
|
|
418
|
+
The CLI adapter also exposes `my-tool mcp` (route node-side logs to stderr - stdout is the transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that coding agents use to prompt for confirmation. In a hub, `ctx.commands` entries opt into the same agent-facing API with an `agent` field and reach MCP through the aggregate endpoint.
|
|
417
419
|
|
|
418
420
|
## Author SPA
|
|
419
421
|
|
|
@@ -508,7 +510,7 @@ Plus broadcasts (`devframe:docks:activate`, `devframe:terminals:updated`, `devfr
|
|
|
508
510
|
|
|
509
511
|
The hub is headless; `DevframeHubUi` is pure data (`viewer` / `embedded` / `assets` / `setup`). `@devframes/hub-ui`'s `createUi()` is the reference hub UI provider - a standalone devtools page plus a floating dock injected via one `<script type="module" src="/__devframes/embedded.js">` tag. It takes `branding`, `dockPreferences`, and `embeddedVisibility` (`'normal'` / `'passive'` / `'hidden'`). Another hub UI provider supplies a different object to the same slot and reuses all the infrastructure. Renderer modules for opt-in dock types compose at the hub via `initHub({ renderers })`.
|
|
510
512
|
|
|
511
|
-
Two copyable reference hubs mount every built-in devframe behind an icon dock rail - the shape Vite DevTools wears, shrunk to the smallest thing you can build your own hub UI provider from: [`examples/hub-vite/`](https://github.com/devframes/devframe/tree/main/examples/hub-vite) (~120-line Vite host, vanilla DOM UI) and [`examples/hub-next/`](https://github.com/devframes/devframe/tree/main/examples/hub-next) (Next.js App Router). The `hub
|
|
513
|
+
Two copyable reference hubs mount every built-in devframe behind an icon dock rail - the shape Vite DevTools wears, shrunk to the smallest thing you can build your own hub UI provider from: [`examples/custom-hub-vite/`](https://github.com/devframes/devframe/tree/main/examples/custom-hub-vite) (~120-line Vite host, vanilla DOM UI) and [`examples/custom-hub-next/`](https://github.com/devframes/devframe/tree/main/examples/custom-hub-next) (Next.js App Router). The `hub-*` family (`hub-vite`, `hub-next`, `hub-deno`, `hub-fastify`, `hub-hono`, `hub-nitro`, `hub-rsbuild`, `hub-sveltekit`) shows the default `createUi()` mount across Vite, Next, Nitro, Hono, Fastify, SvelteKit, Deno, and Rsbuild.
|
|
512
514
|
|
|
513
515
|
## Framework kits: two scopes
|
|
514
516
|
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import "./constants.mjs";
|
|
2
|
-
import { n as getPort } from "./dist-CZXfGEkd.mjs";
|
|
3
|
-
import { cleanDoubleSlashes, withLeadingSlash, withTrailingSlash, withoutLeadingSlash } from "ufo";
|
|
4
|
-
//#region src/adapters/_shared.ts
|
|
5
|
-
const DEFAULT_PORT = 9999;
|
|
6
|
-
/**
|
|
7
|
-
* Resolve the mount base path for a devframe's SPA. Hosted adapters
|
|
8
|
-
* (`vite`, `embedded`) default to `/__<id>/` so they don't collide
|
|
9
|
-
* with the host app; standalone adapters (`cli`, `build`)
|
|
10
|
-
* default to `/` because they own the origin.
|
|
11
|
-
*
|
|
12
|
-
* The devframe author can override with `basePath` on the definition.
|
|
13
|
-
*/
|
|
14
|
-
function resolveBasePath(def, kind) {
|
|
15
|
-
if (def.basePath) return normalizeBasePath(def.basePath);
|
|
16
|
-
return kind === "standalone" ? "/" : `/__${def.id}/`;
|
|
17
|
-
}
|
|
18
|
-
function normalizeBasePath(base) {
|
|
19
|
-
return cleanDoubleSlashes(withTrailingSlash(withLeadingSlash(base)));
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Resolve the listening port for `createDevServer` (and `createHandler`'s
|
|
23
|
-
* side-car tiers), honoring the definition's `cli.port` / `cli.portRange` /
|
|
24
|
-
* `cli.random` settings. Exposed separately so authors who run their own
|
|
25
|
-
* argv parsing can resolve a port up-front (to print it, log it, etc.)
|
|
26
|
-
* before starting the server.
|
|
27
|
-
*/
|
|
28
|
-
async function resolveDevServerPort(def, options = {}) {
|
|
29
|
-
const host = options.host ?? def.cli?.host ?? "localhost";
|
|
30
|
-
const portOptions = {
|
|
31
|
-
port: options.defaultPort ?? def.cli?.port ?? DEFAULT_PORT,
|
|
32
|
-
host
|
|
33
|
-
};
|
|
34
|
-
if (def.cli?.portRange) portOptions.portRange = def.cli.portRange;
|
|
35
|
-
if (def.cli?.random) portOptions.random = def.cli.random;
|
|
36
|
-
return getPort(portOptions);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Normalize the `cli.mcp` / `mcp` option (`boolean | McpRouteOptions`) into
|
|
40
|
-
* concrete options, or `undefined` when the MCP route is disabled.
|
|
41
|
-
*/
|
|
42
|
-
function resolveMcpConfig(mcp) {
|
|
43
|
-
if (!mcp) return void 0;
|
|
44
|
-
return mcp === true ? {} : mcp;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Resolve the `mcp` entry a `__connection.json` should advertise for a dev
|
|
48
|
-
* server started with the given `mcp` option (falling back to `def.cli?.mcp`,
|
|
49
|
-
* exactly like `createDevServer`), or `undefined` when the route is
|
|
50
|
-
* disabled.
|
|
51
|
-
*
|
|
52
|
-
* Hosted bridges that hand-roll their connection meta pass the side-car
|
|
53
|
-
* `port`: the advertised path becomes absolute (the side-car mounts at `/`)
|
|
54
|
-
* and the client dials `<page-host>:<port><path>`. Without `port` the path
|
|
55
|
-
* stays relative, resolved against `__connection.json`'s own location (the
|
|
56
|
-
* same-server default).
|
|
57
|
-
*/
|
|
58
|
-
function resolveMcpConnectionMeta(def, mcp, port) {
|
|
59
|
-
const config = resolveMcpConfig(mcp ?? def.cli?.mcp);
|
|
60
|
-
if (!config) return void 0;
|
|
61
|
-
const route = withoutLeadingSlash(config.path ?? "__mcp");
|
|
62
|
-
return port != null ? {
|
|
63
|
-
path: withLeadingSlash(route),
|
|
64
|
-
port
|
|
65
|
-
} : { path: route };
|
|
66
|
-
}
|
|
67
|
-
//#endregion
|
|
68
|
-
export { resolveMcpConnectionMeta as i, resolveBasePath as n, resolveDevServerPort as r, normalizeBasePath as t };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { F as DevframeDefinition, G as McpRouteOptions, I as DevframeDeploymentKind, t as ConnectionMeta } from "./context-CLF4-8Pp.mjs";
|
|
2
|
-
//#region src/adapters/_shared.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the mount base path for a devframe's SPA. Hosted adapters
|
|
5
|
-
* (`vite`, `embedded`) default to `/__<id>/` so they don't collide
|
|
6
|
-
* with the host app; standalone adapters (`cli`, `build`)
|
|
7
|
-
* default to `/` because they own the origin.
|
|
8
|
-
*
|
|
9
|
-
* The devframe author can override with `basePath` on the definition.
|
|
10
|
-
*/
|
|
11
|
-
declare function resolveBasePath(def: DevframeDefinition, kind: DevframeDeploymentKind): string;
|
|
12
|
-
declare function normalizeBasePath(base: string): string;
|
|
13
|
-
interface ResolveDevServerPortOptions {
|
|
14
|
-
/** Bind host (passed to `get-port-please` for in-use detection). */
|
|
15
|
-
host?: string;
|
|
16
|
-
/** Override the preferred port. Default: `def.cli?.port ?? 9999`. */
|
|
17
|
-
defaultPort?: number;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Resolve the listening port for `createDevServer` (and `createHandler`'s
|
|
21
|
-
* side-car tiers), honoring the definition's `cli.port` / `cli.portRange` /
|
|
22
|
-
* `cli.random` settings. Exposed separately so authors who run their own
|
|
23
|
-
* argv parsing can resolve a port up-front (to print it, log it, etc.)
|
|
24
|
-
* before starting the server.
|
|
25
|
-
*/
|
|
26
|
-
declare function resolveDevServerPort(def: DevframeDefinition, options?: ResolveDevServerPortOptions): Promise<number>;
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the `mcp` entry a `__connection.json` should advertise for a dev
|
|
29
|
-
* server started with the given `mcp` option (falling back to `def.cli?.mcp`,
|
|
30
|
-
* exactly like `createDevServer`), or `undefined` when the route is
|
|
31
|
-
* disabled.
|
|
32
|
-
*
|
|
33
|
-
* Hosted bridges that hand-roll their connection meta pass the side-car
|
|
34
|
-
* `port`: the advertised path becomes absolute (the side-car mounts at `/`)
|
|
35
|
-
* and the client dials `<page-host>:<port><path>`. Without `port` the path
|
|
36
|
-
* stays relative, resolved against `__connection.json`'s own location (the
|
|
37
|
-
* same-server default).
|
|
38
|
-
*/
|
|
39
|
-
declare function resolveMcpConnectionMeta(def: DevframeDefinition, mcp: boolean | McpRouteOptions | undefined, port?: number): ConnectionMeta['mcp'];
|
|
40
|
-
//#endregion
|
|
41
|
-
export { resolveMcpConnectionMeta as a, resolveDevServerPort as i, normalizeBasePath as n, resolveBasePath as r, ResolveDevServerPortOptions as t };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { i as defineDiagnostics } from "./nostics-CzECRXpE.mjs";
|
|
2
|
-
//#region src/rpc/diagnostics.ts
|
|
3
|
-
const diagnostics = defineDiagnostics({
|
|
4
|
-
docsBase: "https://devfra.me/errors",
|
|
5
|
-
codes: {
|
|
6
|
-
DF0019: {
|
|
7
|
-
why: (p) => `RPC function "${p.name}" has \`agent\` set but \`jsonSerializable\` is not \`true\` — MCP requires JSON-serializable data.`,
|
|
8
|
-
fix: "Set `jsonSerializable: true` if the payload is JSON-safe, or remove `agent` to keep it RPC-only."
|
|
9
|
-
},
|
|
10
|
-
DF0020: {
|
|
11
|
-
why: (p) => `RPC function "${p.name}" declares \`jsonSerializable: true\` but the value at "${p.path}" is a ${p.type}.`,
|
|
12
|
-
fix: "Either drop `jsonSerializable: true` (falls back to structured-clone) or change the value to a JSON-safe shape."
|
|
13
|
-
},
|
|
14
|
-
DF0021: {
|
|
15
|
-
why: (p) => `RPC function "${p.name}" is already registered`,
|
|
16
|
-
fix: "Use the `force` parameter to overwrite an existing registration."
|
|
17
|
-
},
|
|
18
|
-
DF0022: { why: (p) => `RPC function "${p.name}" is not registered. Use register() to add new functions.` },
|
|
19
|
-
DF0023: { why: (p) => `RPC function "${p.name}" is not registered` },
|
|
20
|
-
DF0024: { why: (p) => `Either handler or setup function must be provided for RPC function "${p.name}"` },
|
|
21
|
-
DF0025: { why: (p) => `Function "${p.name}" not found in dump store` },
|
|
22
|
-
DF0026: { why: (p) => `No dump match for "${p.name}" with args: ${p.args}` },
|
|
23
|
-
DF0027: { why: (p) => `Function "${p.name}" with type "${p.type}" cannot have dump configuration. Only "static" and "query" types support dumps.` },
|
|
24
|
-
DF0028: {
|
|
25
|
-
why: (p) => `Function "${p.name}" with type "${p.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`,
|
|
26
|
-
fix: "Remove `snapshot: true`, or change the function type to `query`."
|
|
27
|
-
},
|
|
28
|
-
DF0043: {
|
|
29
|
-
why: (p) => `RPC function "${p.name}" received an invalid argument at position ${p.index}: ${p.issues}`,
|
|
30
|
-
fix: "Pass a value that satisfies the `args` schema declared for this function."
|
|
31
|
-
},
|
|
32
|
-
DF0044: {
|
|
33
|
-
why: (p) => `RPC function "${p.name}" returned a value that failed its \`returns\` schema: ${p.issues}`,
|
|
34
|
-
fix: "Make the handler return a value that satisfies the `returns` schema, or relax the schema."
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
//#endregion
|
|
39
|
-
export { diagnostics as t };
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { t as diagnostics } from "./diagnostics-CD8nlgll.mjs";
|
|
2
|
-
//#region src/rpc/serialization.ts
|
|
3
|
-
/**
|
|
4
|
-
* Wire format used by the live RPC transports (WebSocket and SSE).
|
|
5
|
-
*
|
|
6
|
-
* - **JSON (default, unprefixed):** payload is plain JSON text. Used when
|
|
7
|
-
* the dispatched method is declared `jsonSerializable: true`. Encoded
|
|
8
|
-
* via {@link strictJsonStringify} (rejects non-JSON values), decoded
|
|
9
|
-
* via `JSON.parse`.
|
|
10
|
-
* - **Structured-clone (`s:` prefix):** payload is `s:` followed by
|
|
11
|
-
* `structured-clone-es` text. Used when the method is declared
|
|
12
|
-
* `jsonSerializable: false` (or omitted, the default). Round-trips
|
|
13
|
-
* `Map`, `Set`, `Date`, `BigInt`, cycles, and class instances.
|
|
14
|
-
*
|
|
15
|
-
* birpc envelopes always start with `{`, so a leading byte that is not
|
|
16
|
-
* `s` is unambiguously JSON. Each direction independently chooses its
|
|
17
|
-
* encoding from local definitions — request and response are not
|
|
18
|
-
* coupled by a mirror rule.
|
|
19
|
-
*/
|
|
20
|
-
const STRUCTURED_CLONE_PREFIX = "s:";
|
|
21
|
-
/**
|
|
22
|
-
* `JSON.stringify` with a single-pass strict replacer.
|
|
23
|
-
*
|
|
24
|
-
* Throws `DF0020` synchronously when the value contains a type JSON
|
|
25
|
-
* cannot round-trip losslessly: `Map`, `Set`, `Date`, `BigInt`, class
|
|
26
|
-
* instances, or `undefined` inside an array (silently becomes `null`).
|
|
27
|
-
*
|
|
28
|
-
* Native pass-throughs (no extra work needed):
|
|
29
|
-
* - circular references — `JSON.stringify` raises `TypeError`.
|
|
30
|
-
* - `BigInt` at top level — caught here for a friendlier error path.
|
|
31
|
-
*
|
|
32
|
-
* Lenient cases (allowed without throwing):
|
|
33
|
-
* - `undefined` as an object property — legitimate optional field;
|
|
34
|
-
* JSON.stringify just omits it.
|
|
35
|
-
* - `undefined` at the root — legitimate "action returned nothing".
|
|
36
|
-
* - `Symbol` / `Function` values — semantically "drop me" in JSON.
|
|
37
|
-
*
|
|
38
|
-
* `fnName` is used only for the diagnostic message — pass the RPC
|
|
39
|
-
* function name when calling from a wire serializer / dump writer so
|
|
40
|
-
* the error points at the offending function.
|
|
41
|
-
*/
|
|
42
|
-
function strictJsonStringify(value, fnName = "") {
|
|
43
|
-
return JSON.stringify(value, function strictReplacer(key, val) {
|
|
44
|
-
const holder = this;
|
|
45
|
-
const original = holder != null ? holder[key] : val;
|
|
46
|
-
if (original === void 0) {
|
|
47
|
-
if (Array.isArray(holder)) throw nonJsonAt(fnName, "undefined", holder, key);
|
|
48
|
-
return val;
|
|
49
|
-
}
|
|
50
|
-
if (original === null) return val;
|
|
51
|
-
if (typeof original === "bigint") throw nonJsonAt(fnName, "BigInt", holder, key);
|
|
52
|
-
if (typeof original === "object") {
|
|
53
|
-
if (original instanceof Map) throw nonJsonAt(fnName, "Map", holder, key);
|
|
54
|
-
if (original instanceof Set) throw nonJsonAt(fnName, "Set", holder, key);
|
|
55
|
-
if (original instanceof Date) throw nonJsonAt(fnName, "Date", holder, key);
|
|
56
|
-
if (Array.isArray(original)) return val;
|
|
57
|
-
const proto = Object.getPrototypeOf(original);
|
|
58
|
-
if (proto !== null && proto !== Object.prototype) throw nonJsonAt(fnName, original.constructor?.name ?? "class instance", holder, key);
|
|
59
|
-
}
|
|
60
|
-
return val;
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
function nonJsonAt(fnName, type, parent, key) {
|
|
64
|
-
const path = formatPath(parent, key);
|
|
65
|
-
return diagnostics.DF0020({
|
|
66
|
-
name: fnName || "<anonymous>",
|
|
67
|
-
type,
|
|
68
|
-
path
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
function formatPath(parent, key) {
|
|
72
|
-
if (Array.isArray(parent)) return `[${key}]`;
|
|
73
|
-
if (key === "") return "<root>";
|
|
74
|
-
return key;
|
|
75
|
-
}
|
|
76
|
-
//#endregion
|
|
77
|
-
export { strictJsonStringify as n, STRUCTURED_CLONE_PREFIX as t };
|
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import "./constants.mjs";
|
|
2
|
-
import { t as createRpcWireCodec } from "./wire-codec-0K-o5MYW.mjs";
|
|
3
|
-
import { n as randomToken, r as timingSafeEqual } from "./crypto-token-XCqTSMg9.mjs";
|
|
4
|
-
import { createServer } from "node:http";
|
|
5
|
-
import { createServer as createServer$1 } from "node:https";
|
|
6
|
-
import crossws from "crossws/adapters/node";
|
|
7
|
-
//#region src/rpc/transports/session.ts
|
|
8
|
-
let sessionId = 0;
|
|
9
|
-
/**
|
|
10
|
-
* Mint the per-connection session meta every transport binding shares —
|
|
11
|
-
* one id space across transports, so session bookkeeping (streaming
|
|
12
|
-
* subscriptions, shared-state sync, auth trust) never collides between a
|
|
13
|
-
* WS peer and an SSE session on the same server.
|
|
14
|
-
*/
|
|
15
|
-
function createRpcSessionMeta() {
|
|
16
|
-
return {
|
|
17
|
-
id: sessionId++,
|
|
18
|
-
subscribedStates: /* @__PURE__ */ new Set()
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/rpc/transports/ws-server.ts
|
|
23
|
-
/**
|
|
24
|
-
* Create a live, token-protected origin allowlist for external browser
|
|
25
|
-
* viewers. Pass it to {@link WsRpcTransportOptions.allowedOrigins}, then use
|
|
26
|
-
* `registerFromUrl()` in the connection metadata handler to authorize a
|
|
27
|
-
* viewer without sharing a mutable array or disabling DNS-rebinding protection.
|
|
28
|
-
*/
|
|
29
|
-
function createWsOriginRegistry(options = {}) {
|
|
30
|
-
const token = randomToken();
|
|
31
|
-
const origins = new Set(options.allowedOrigins ?? []);
|
|
32
|
-
function normalizeOrigin(origin) {
|
|
33
|
-
if (!origin) return;
|
|
34
|
-
try {
|
|
35
|
-
const url = new URL(origin);
|
|
36
|
-
const normalized = url.origin === "null" ? `${url.protocol}//${url.host}` : url.origin;
|
|
37
|
-
return origin === normalized ? normalized : void 0;
|
|
38
|
-
} catch {}
|
|
39
|
-
}
|
|
40
|
-
function registerOrigin(origin, candidateToken) {
|
|
41
|
-
const normalized = normalizeOrigin(origin);
|
|
42
|
-
if (!normalized || !candidateToken || !timingSafeEqual(token, candidateToken)) return false;
|
|
43
|
-
if (options.validateOrigin && !options.validateOrigin(normalized)) return false;
|
|
44
|
-
origins.add(normalized);
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
token,
|
|
49
|
-
registerFromUrl(url) {
|
|
50
|
-
let parsed;
|
|
51
|
-
try {
|
|
52
|
-
parsed = new URL(url, "http://localhost");
|
|
53
|
-
} catch {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
const origin = parsed.searchParams.get("devframe_viewer_origin") ?? void 0;
|
|
57
|
-
return registerOrigin(origin, parsed.searchParams.get("devframe_viewer_origin_token") ?? void 0) ? origin : void 0;
|
|
58
|
-
},
|
|
59
|
-
isAllowed(origin) {
|
|
60
|
-
return isAllowedOrigin(origin, [...origins]);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
const EMPTY_DEFS = /* @__PURE__ */ new Map();
|
|
65
|
-
function NOOP() {}
|
|
66
|
-
function listen(server, port, host) {
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const onError = (error) => reject(error);
|
|
69
|
-
server.once("error", onError);
|
|
70
|
-
try {
|
|
71
|
-
server.listen(port, host, () => {
|
|
72
|
-
server.off("error", onError);
|
|
73
|
-
resolve();
|
|
74
|
-
});
|
|
75
|
-
} catch (error) {
|
|
76
|
-
server.off("error", onError);
|
|
77
|
-
reject(error);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
/** Compare two URL paths ignoring a trailing slash. */
|
|
82
|
-
function pathMatches(a, b) {
|
|
83
|
-
const strip = (p) => p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
84
|
-
return strip(a) === strip(b);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
|
|
88
|
-
* subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
|
|
89
|
-
* `127.0.0.0/8` loopback block.
|
|
90
|
-
*
|
|
91
|
-
* The IPv4 case is matched **structurally** — the whole hostname must be a
|
|
92
|
-
* canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
|
|
93
|
-
* `startsWith('127.')` prefix check would also accept an attacker-controlled
|
|
94
|
-
* DNS name that merely *begins* with `127.` (`127.attacker.example`,
|
|
95
|
-
* `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
|
|
96
|
-
* the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
|
|
97
|
-
* cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
|
|
98
|
-
* genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
|
|
99
|
-
* those DNS names.
|
|
100
|
-
*/
|
|
101
|
-
function isLoopbackHostname(hostname) {
|
|
102
|
-
const h = hostname.replace(/^\[|\]$/g, "");
|
|
103
|
-
if (h === "localhost" || h.endsWith(".localhost") || h === "::1") return true;
|
|
104
|
-
return isLoopbackIPv4(h);
|
|
105
|
-
}
|
|
106
|
-
/** A canonical dotted-decimal IPv4 literal in `127.0.0.0/8`. */
|
|
107
|
-
function isLoopbackIPv4(hostname) {
|
|
108
|
-
const octets = hostname.split(".");
|
|
109
|
-
if (octets.length !== 4 || !octets.every(isDecimalOctet)) return false;
|
|
110
|
-
return Number(octets[0]) === 127;
|
|
111
|
-
}
|
|
112
|
-
/** A single canonical IPv4 octet: 1–3 digits, no leading zero, value 0–255. */
|
|
113
|
-
function isDecimalOctet(part) {
|
|
114
|
-
if (!/^\d{1,3}$/.test(part) || part.length > 1 && part[0] === "0") return false;
|
|
115
|
-
return Number(part) <= 255;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Default origin policy for a localhost dev tool: allow requests with no
|
|
119
|
-
* `Origin` header (native, non-browser clients), allow any loopback origin
|
|
120
|
-
* (so cross-port localhost dev setups keep working), and allow explicitly
|
|
121
|
-
* configured origins. Everything else — a real remote page in the dev's
|
|
122
|
-
* browser — is rejected.
|
|
123
|
-
*/
|
|
124
|
-
function isAllowedOrigin(origin, allowedOrigins) {
|
|
125
|
-
if (!origin) return true;
|
|
126
|
-
if (allowedOrigins.includes(origin)) return true;
|
|
127
|
-
try {
|
|
128
|
-
return isLoopbackHostname(new URL(origin).hostname);
|
|
129
|
-
} catch {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
function isWsOriginRegistry(value) {
|
|
134
|
-
return !!value && !Array.isArray(value);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Build the `upgrade` listener that hands a request to the crossws adapter,
|
|
138
|
-
* optionally filtered to a single `path`. Non-matching requests are left
|
|
139
|
-
* untouched so other upgrade listeners (e.g. a Vite dev server's HMR socket)
|
|
140
|
-
* can claim them, unless `destroyUnmatched` is set.
|
|
141
|
-
*/
|
|
142
|
-
function createUpgradeListener(ws, path, destroyUnmatched, allowedOrigins) {
|
|
143
|
-
return (req, socket, head) => {
|
|
144
|
-
socket.on("error", () => {});
|
|
145
|
-
if (path) {
|
|
146
|
-
let pathname = req.url ?? "/";
|
|
147
|
-
try {
|
|
148
|
-
pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
149
|
-
} catch {}
|
|
150
|
-
if (!pathMatches(pathname, path)) {
|
|
151
|
-
if (destroyUnmatched) {
|
|
152
|
-
socket.write("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
|
|
153
|
-
socket.destroy();
|
|
154
|
-
}
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const originAllowed = isWsOriginRegistry(allowedOrigins) ? allowedOrigins.isAllowed(req.headers.origin) : isAllowedOrigin(req.headers.origin, allowedOrigins || []);
|
|
159
|
-
if (allowedOrigins !== false && !originAllowed) {
|
|
160
|
-
socket.write("HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n");
|
|
161
|
-
socket.destroy();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
ws.handleUpgrade(req, socket, head);
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* The per-peer lifecycle hooks driving a devframe RPC WebSocket, shaped for
|
|
169
|
-
* any [crossws](https://crossws.h3.dev) adapter. {@link attachWsRpcTransport}
|
|
170
|
-
* feeds them to the Node adapter; runtime-specific attachments (e.g. Bun's
|
|
171
|
-
* fetch-upgrade adapter) reuse the same hooks so every transport speaks the
|
|
172
|
-
* identical wire protocol — one birpc channel per peer, per-method
|
|
173
|
-
* `jsonSerializable` dispatch between strict JSON and structured-clone.
|
|
174
|
-
*/
|
|
175
|
-
function createWsRpcPeerHooks(rpcGroup, options = {}) {
|
|
176
|
-
const { onConnected = NOOP, onDisconnected = NOOP, definitions = EMPTY_DEFS, serialize: serializeOverride, deserialize: deserializeOverride } = options;
|
|
177
|
-
const states = /* @__PURE__ */ new WeakMap();
|
|
178
|
-
return {
|
|
179
|
-
open: (peer) => {
|
|
180
|
-
const meta = createRpcSessionMeta();
|
|
181
|
-
meta.peer = peer;
|
|
182
|
-
const connection = {
|
|
183
|
-
id: meta.id,
|
|
184
|
-
transport: "websocket",
|
|
185
|
-
request: peer.request,
|
|
186
|
-
send: (data) => peer.send(data),
|
|
187
|
-
close: (code, reason) => peer.close(code, reason),
|
|
188
|
-
peer
|
|
189
|
-
};
|
|
190
|
-
const codec = createRpcWireCodec(definitions);
|
|
191
|
-
const state = {
|
|
192
|
-
meta,
|
|
193
|
-
connection,
|
|
194
|
-
channel: void 0
|
|
195
|
-
};
|
|
196
|
-
const channel = {
|
|
197
|
-
post: (data) => {
|
|
198
|
-
peer.send(data);
|
|
199
|
-
},
|
|
200
|
-
on: (fn) => {
|
|
201
|
-
state.onMessage = fn;
|
|
202
|
-
},
|
|
203
|
-
serialize: serializeOverride ?? codec.serialize,
|
|
204
|
-
deserialize: deserializeOverride ?? codec.deserialize,
|
|
205
|
-
meta
|
|
206
|
-
};
|
|
207
|
-
state.channel = channel;
|
|
208
|
-
states.set(peer, state);
|
|
209
|
-
rpcGroup.updateChannels((channels) => {
|
|
210
|
-
channels.push(channel);
|
|
211
|
-
});
|
|
212
|
-
onConnected(connection, meta);
|
|
213
|
-
},
|
|
214
|
-
message: (peer, message) => {
|
|
215
|
-
states.get(peer)?.onMessage?.(message.text());
|
|
216
|
-
},
|
|
217
|
-
close: (peer) => {
|
|
218
|
-
const state = states.get(peer);
|
|
219
|
-
if (!state) return;
|
|
220
|
-
states.delete(peer);
|
|
221
|
-
rpcGroup.updateChannels((channels) => {
|
|
222
|
-
const index = channels.indexOf(state.channel);
|
|
223
|
-
if (index >= 0) channels.splice(index, 1);
|
|
224
|
-
});
|
|
225
|
-
onDisconnected(state.connection, state.meta);
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Attach a WebSocket transport to an existing RPC group, powered by
|
|
231
|
-
* [crossws](https://crossws.h3.dev). Either attach to an existing HTTP(S)
|
|
232
|
-
* `server` (sharing its port, optionally scoped to a `path`), or let this
|
|
233
|
-
* helper create a standalone server from `port` / `host` / `https`.
|
|
234
|
-
*
|
|
235
|
-
* Returns the crossws node adapter, standalone-server readiness/address
|
|
236
|
-
* accessors, `detach` (remove the upgrade listener from a shared `server`),
|
|
237
|
-
* and `close` (full deterministic teardown).
|
|
238
|
-
*/
|
|
239
|
-
function attachWsRpcTransport(rpcGroup, options = {}) {
|
|
240
|
-
const { server, port, host = "localhost", path, destroyUnmatched = false, unbound, https, allowedOrigins } = options;
|
|
241
|
-
const ws = crossws({ hooks: createWsRpcPeerHooks(rpcGroup, options) });
|
|
242
|
-
const sharedUpgradeListener = createUpgradeListener(ws, path, destroyUnmatched, allowedOrigins);
|
|
243
|
-
const ownedUpgradeListener = createUpgradeListener(ws, path, true, allowedOrigins);
|
|
244
|
-
/** Bind a server's `upgrade` events, tracked so `close()` detaches them. */
|
|
245
|
-
const attachments = /* @__PURE__ */ new Set();
|
|
246
|
-
function attachTo(target, listener) {
|
|
247
|
-
target.on("upgrade", listener);
|
|
248
|
-
const detachOne = () => {
|
|
249
|
-
target.off("upgrade", listener);
|
|
250
|
-
attachments.delete(detachOne);
|
|
251
|
-
};
|
|
252
|
-
attachments.add(detachOne);
|
|
253
|
-
return detachOne;
|
|
254
|
-
}
|
|
255
|
-
let ready = Promise.resolve();
|
|
256
|
-
let ownedServer;
|
|
257
|
-
if (unbound) {} else if (server) attachTo(server, sharedUpgradeListener);
|
|
258
|
-
else if (https) {
|
|
259
|
-
ownedServer = createServer$1(https);
|
|
260
|
-
attachTo(ownedServer, ownedUpgradeListener);
|
|
261
|
-
ready = listen(ownedServer, port ?? 0, host);
|
|
262
|
-
} else {
|
|
263
|
-
ownedServer = createServer((_req, res) => {
|
|
264
|
-
res.writeHead(426, { "content-type": "text/plain" });
|
|
265
|
-
res.end("Upgrade Required");
|
|
266
|
-
});
|
|
267
|
-
attachTo(ownedServer, ownedUpgradeListener);
|
|
268
|
-
ready = listen(ownedServer, port ?? 0, host);
|
|
269
|
-
}
|
|
270
|
-
const activeServer = server ?? ownedServer;
|
|
271
|
-
function detachAll() {
|
|
272
|
-
for (const detachOne of [...attachments]) detachOne();
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
ws,
|
|
276
|
-
ready,
|
|
277
|
-
address: () => activeServer?.address() ?? null,
|
|
278
|
-
handleUpgrade: sharedUpgradeListener,
|
|
279
|
-
attach: (target) => attachTo(target, sharedUpgradeListener),
|
|
280
|
-
detach: detachAll,
|
|
281
|
-
async close() {
|
|
282
|
-
detachAll();
|
|
283
|
-
ws.closeAll(void 0, void 0, true);
|
|
284
|
-
if (ownedServer) {
|
|
285
|
-
const srv = ownedServer;
|
|
286
|
-
await ready.catch(() => {});
|
|
287
|
-
if (!srv.listening) return;
|
|
288
|
-
await new Promise((r) => srv.close(() => r()));
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
//#endregion
|
|
294
|
-
export { isLoopbackHostname as a, isAllowedOrigin as i, createWsOriginRegistry as n, createRpcSessionMeta as o, createWsRpcPeerHooks as r, attachWsRpcTransport as t };
|