devframe 0.9.7 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/{_shared-BM3PdYli.mjs → _shared-C08SdQRl.mjs} +15 -4
  2. package/dist/{_shared-BJ6AmwTu.d.mts → _shared-CK3czkH4.d.mts} +25 -2
  3. package/dist/adapters/build.d.mts +6 -6
  4. package/dist/adapters/build.mjs +32 -22
  5. package/dist/adapters/cac.d.mts +16 -1
  6. package/dist/adapters/cac.mjs +8 -7
  7. package/dist/adapters/dev.d.mts +13 -13
  8. package/dist/adapters/dev.mjs +2 -2
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +28 -26
  11. package/dist/adapters/initiate.mjs +1 -1
  12. package/dist/adapters/mcp.d.mts +28 -14
  13. package/dist/adapters/mcp.mjs +75 -39
  14. package/dist/{agent-tool-name-EgfoFO8C.mjs → agent-tool-name-DGzeuWcO.mjs} +2 -2
  15. package/dist/cli/main.d.mts +1 -1
  16. package/dist/cli/main.mjs +41 -17
  17. package/dist/client/index.d.mts +36 -36
  18. package/dist/client/index.mjs +83 -51
  19. package/dist/client-assets-DNdhagGm.mjs +16 -0
  20. package/dist/constants.d.mts +8 -7
  21. package/dist/constants.mjs +7 -6
  22. package/dist/{context-BhBzOXVa.d.mts → context-4AIVRLYF.d.mts} +173 -122
  23. package/dist/{context-omlma_1n.mjs → context-CwPUinjn.mjs} +126 -88
  24. package/dist/{context-KUqAfawQ.mjs → context-DIUvJW4D.mjs} +3 -3
  25. package/dist/{context-HOnG-WvG.d.mts → context-rgBSPFHS.d.mts} +5 -5
  26. package/dist/{crypto-token-XCqTSMg9.mjs → crypto-token-TVbGGFuj.mjs} +1 -1
  27. package/dist/{dev-Czit5IP4.mjs → dev-Eqq5PX0k.mjs} +37 -18
  28. package/dist/{diagnostics-BXWW3VK-.mjs → diagnostics-BMfN8mb1.mjs} +30 -17
  29. package/dist/{diagnostics-CD8nlgll.mjs → diagnostics-D0EVm5M6.mjs} +2 -2
  30. package/dist/{events-4daw0uK9.mjs → events-BV4Dj59a.mjs} +2 -2
  31. package/dist/{host-h3-fRbF9yor.mjs → host-h3-BJ4siyz7.mjs} +1 -1
  32. package/dist/in-page-channel/index.d.mts +59 -22
  33. package/dist/in-page-channel/index.mjs +71 -56
  34. package/dist/{index-BzyopqxV.d.mts → index-pIVt92jP.d.mts} +9 -9
  35. package/dist/{index-DcKxIMoI.d.mts → index-pKl67H6w.d.mts} +4 -4
  36. package/dist/index.d.mts +11 -13
  37. package/dist/index.mjs +6 -7
  38. package/dist/{instance-registry-BjlMQbFB.mjs → instance-registry-C7-41RSp.mjs} +8 -8
  39. package/dist/{instance-shell-Bh4l9Vz_.d.mts → instance-shell-7Z52PE4_.d.mts} +18 -18
  40. package/dist/{instance-shell-CpVW4zG0.mjs → instance-shell-cdVETpfz.mjs} +227 -58
  41. package/dist/internal/index.d.mts +51 -21
  42. package/dist/internal/index.mjs +10 -9
  43. package/dist/node/auth.d.mts +2 -2
  44. package/dist/node/auth.mjs +2 -2
  45. package/dist/node/hub-internals.d.mts +2 -2
  46. package/dist/node/hub-internals.mjs +2 -2
  47. package/dist/node/index.d.mts +5 -5
  48. package/dist/node/index.mjs +2 -2
  49. package/dist/{nostics-SPGDgHEP.d.mts → nostics-0sKe5HIj.d.mts} +2 -2
  50. package/dist/{nostics-CzECRXpE.mjs → nostics-D0PvLZsn.mjs} +1 -1
  51. package/dist/origin-DGDH8BI9.d.mts +45 -0
  52. package/dist/origin-DZit9g29.mjs +80 -0
  53. package/dist/recipes/common-rpc-functions.d.mts +5 -5
  54. package/dist/recipes/common-rpc-functions.mjs +3 -3
  55. package/dist/recipes/interactive-auth.d.mts +6 -6
  56. package/dist/recipes/interactive-auth.mjs +6 -6
  57. package/dist/{remote-assets-DezQmPQU.mjs → remote-assets-BIFWOlBW.mjs} +26 -6
  58. package/dist/{remote-assets-B13_vRkJ.d.mts → remote-assets-eBvSKZMS.d.mts} +7 -7
  59. package/dist/{revoke-COLW0cOi.mjs → revoke-cqztiCX4.mjs} +1 -1
  60. package/dist/rpc/dump.d.mts +2 -11
  61. package/dist/rpc/dump.mjs +1 -1
  62. package/dist/rpc/index.d.mts +2 -2
  63. package/dist/rpc/index.mjs +3 -3
  64. package/dist/rpc/transports/sse-client.d.mts +1 -1
  65. package/dist/rpc/transports/sse-client.mjs +30 -14
  66. package/dist/rpc/transports/sse-server.d.mts +4 -4
  67. package/dist/rpc/transports/sse-server.mjs +7 -7
  68. package/dist/rpc/transports/ws-bun.d.mts +5 -5
  69. package/dist/rpc/transports/ws-bun.mjs +8 -2
  70. package/dist/rpc/transports/ws-client.d.mts +1 -1
  71. package/dist/rpc/transports/ws-client.mjs +2 -2
  72. package/dist/rpc/transports/ws-deno.d.mts +4 -4
  73. package/dist/rpc/transports/ws-deno.mjs +8 -2
  74. package/dist/rpc/transports/ws-server.d.mts +2 -1
  75. package/dist/rpc/transports/ws-server.mjs +232 -1
  76. package/dist/{rpc-core-BHUsDl7s.d.mts → rpc-core-Ceu6AUz8.d.mts} +4 -4
  77. package/dist/{rpc-core-DlHd276T.mjs → rpc-core-DVQ7xi89.mjs} +14 -2
  78. package/dist/{serialization-BGzEwAdr.mjs → serialization-DTZnPQ1-.mjs} +20 -18
  79. package/dist/{services-install-CqqQVls5.mjs → services-install-P_DV7VYL.mjs} +32 -21
  80. package/dist/session-DPfj6zQG.mjs +16 -0
  81. package/dist/{shared-state-DoXutg_U.mjs → shared-state-CaxB1q0h.mjs} +4 -3
  82. package/dist/{simple-schema-DQPZrAaZ.mjs → simple-schema-Bi40l-P6.mjs} +2 -2
  83. package/dist/{sse-client-DwX021ST.d.mts → sse-client-BQ4jS3eO.d.mts} +4 -4
  84. package/dist/{state-CK9LjrnT.mjs → state-CeQQWzM-.mjs} +4 -4
  85. package/dist/{static-DV_qUSRS.mjs → static-DZ8P2Kn7.mjs} +130 -135
  86. package/dist/{storage-BXNVhKyR.mjs → storage-Dccf_IyD.mjs} +1 -1
  87. package/dist/types/index.d.mts +6 -6
  88. package/dist/{types-CMdPYhOx.d.mts → types-Dq4i156u.d.mts} +17 -17
  89. package/dist/utils/agent-tool-name.d.mts +2 -2
  90. package/dist/utils/agent-tool-name.mjs +2 -2
  91. package/dist/utils/colors.d.mts +1 -1
  92. package/dist/utils/crypto-token.d.mts +1 -1
  93. package/dist/utils/crypto-token.mjs +1 -1
  94. package/dist/utils/events.d.mts +1 -1
  95. package/dist/utils/nostics.d.mts +1 -1
  96. package/dist/utils/nostics.mjs +1 -1
  97. package/dist/utils/open.mjs +1 -1
  98. package/dist/utils/origin.d.mts +2 -0
  99. package/dist/utils/origin.mjs +80 -0
  100. package/dist/utils/remote-assets.d.mts +2 -2
  101. package/dist/utils/remote-assets.mjs +1 -1
  102. package/dist/utils/serve-static.d.mts +4 -4
  103. package/dist/utils/serve-static.mjs +56 -19
  104. package/dist/utils/shared-state.d.mts +1 -1
  105. package/dist/utils/shared-state.mjs +1 -1
  106. package/dist/utils/simple-schema.d.mts +5 -5
  107. package/dist/utils/simple-schema.mjs +2 -2
  108. package/dist/utils/streaming-channel.d.mts +1 -1
  109. package/dist/utils/streaming-channel.mjs +2 -2
  110. package/dist/utils/when.d.mts +5 -5
  111. package/dist/{validation-YrZH6atx.mjs → validation-BOy8IoFZ.mjs} +2 -2
  112. package/dist/{wire-codec-0K-o5MYW.mjs → wire-codec-dcCeXcSo.mjs} +3 -3
  113. package/dist/{ws-client-7_lZi-B9.d.mts → ws-client-Xpxt0oPA.d.mts} +3 -3
  114. package/dist/{ws-server-Di2oqr4q.d.mts → ws-server-D2nv68Hg.d.mts} +13 -22
  115. package/package.json +6 -5
  116. package/dist/ws-server-BdSLrhxE.mjs +0 -267
@@ -1,6 +1,6 @@
1
- import "../index-BzyopqxV.mjs";
2
- import { v as RpcFunctionDefinitionAny } from "../types-CMdPYhOx.mjs";
3
- import { k as SharedState, l as RpcFunctionsHost, o as DevframeNodeContext, yt as DevframeHost } from "../context-BhBzOXVa.mjs";
1
+ import "../index-pIVt92jP.mjs";
2
+ import { v as RpcFunctionDefinitionAny } from "../types-Dq4i156u.mjs";
3
+ import { bt as DevframeHost, k as SharedState, l as RpcFunctionsHost, o as DevframeNodeContext } from "../context-4AIVRLYF.mjs";
4
4
  import { BirpcGroup } from "birpc";
5
5
  //#region src/node/context.d.ts
6
6
  interface CreateHostContextOptions {
@@ -13,7 +13,7 @@ interface CreateHostContextOptions {
13
13
  * serves (from `DevframeDefinition.importMetaUrl`). Supplies the default
14
14
  * `resolveFrom` base for remote {@link DevframeViewHost.hostStatic} sources
15
15
  * that don't set one, so a locally installed copy of an assets package is
16
- * served with zero network. An internal plumbing detail — it isn't part of
16
+ * served with zero network. An internal plumbing detail; it isn't part of
17
17
  * the public {@link DevframeNodeContext} surface.
18
18
  */
19
19
  importMetaUrl?: string;
@@ -28,7 +28,7 @@ interface CreateHostContextOptions {
28
28
  * Framework- and build-tool-agnostic core of the Devframe node context.
29
29
  * Wires the RPC host, view (HTTP file-serving) host, diagnostics, and
30
30
  * agent subsystems. Host adapters can wrap this to augment `ctx` with
31
- * extra surfaces — for example, `@vitejs/devtools-kit`'s
31
+ * extra surfaces; for example, `@vitejs/devtools-kit`'s
32
32
  * `createKitContext` attaches `docks`, `terminals`, `messages`, and
33
33
  * `commands` when mounted into Vite DevTools.
34
34
  */
@@ -1,3 +1,3 @@
1
- import { t as createHostContext } from "../context-omlma_1n.mjs";
2
- import { t as createStorage } from "../storage-BXNVhKyR.mjs";
1
+ import { t as createHostContext } from "../context-CwPUinjn.mjs";
2
+ import { t as createStorage } from "../storage-Dccf_IyD.mjs";
3
3
  export { createHostContext, createStorage };
@@ -10,7 +10,7 @@ declare function devframeReporter(d: Diagnostic, { method }?: {
10
10
  method?: 'log' | 'warn' | 'error';
11
11
  }): void;
12
12
  /**
13
- * Options accepted by {@link defineDiagnostics} — identical to `nostics`'s
13
+ * Options accepted by {@link defineDiagnostics}, identical to `nostics`'s
14
14
  * own `DefineDiagnosticsOptions`, minus the reporter devframe already
15
15
  * prepends.
16
16
  */
@@ -20,7 +20,7 @@ type DevframeDefineDiagnosticsOptions<Codes extends Record<string, DiagnosticDef
20
20
  * ANSI console reporter pre-wired ahead of any `reporters` passed in. Every
21
21
  * `diagnostics.ts` in devframe core, `@devframes/hub`, `@devframes/json-render`,
22
22
  * and the built-in plugins defines its codes through this instead of
23
- * `nostics`'s own `defineDiagnostics` — the reporter registration lives
23
+ * `nostics`'s own `defineDiagnostics`; the reporter registration lives
24
24
  * here, once, so none of them need to build their own reporter (`colors`,
25
25
  * `ansiFormatter`) or take a direct dependency on `nostics` themselves.
26
26
  */
@@ -45,7 +45,7 @@ function devframeReporter(d, { method = "warn" } = {}) {
45
45
  * ANSI console reporter pre-wired ahead of any `reporters` passed in. Every
46
46
  * `diagnostics.ts` in devframe core, `@devframes/hub`, `@devframes/json-render`,
47
47
  * and the built-in plugins defines its codes through this instead of
48
- * `nostics`'s own `defineDiagnostics` — the reporter registration lives
48
+ * `nostics`'s own `defineDiagnostics`; the reporter registration lives
49
49
  * here, once, so none of them need to build their own reporter (`colors`,
50
50
  * `ansiFormatter`) or take a direct dependency on `nostics` themselves.
51
51
  */
@@ -0,0 +1,45 @@
1
+ //#region src/utils/origin.d.ts
2
+ /**
3
+ * Origin and hostname predicates shared by the RPC transports (the WS upgrade,
4
+ * SSE, and MCP origin gates) and the instance shell's authentication-link
5
+ * origin validation. Kept dependency-free and runtime-agnostic so any consumer
6
+ * can pull in a single check without dragging in a transport's `crossws`
7
+ * import.
8
+ */
9
+ /**
10
+ * Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
11
+ * subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
12
+ * `127.0.0.0/8` loopback block.
13
+ *
14
+ * The IPv4 case is matched **structurally**: the whole hostname must be a
15
+ * canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
16
+ * `startsWith('127.')` prefix check would also accept an attacker-controlled
17
+ * DNS name that merely *begins* with `127.` (`127.attacker.example`,
18
+ * `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
19
+ * the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
20
+ * cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
21
+ * genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
22
+ * those DNS names.
23
+ */
24
+ declare function isLoopbackHostname(hostname: string): boolean;
25
+ /**
26
+ * Default origin policy for a localhost dev tool: allow requests with no
27
+ * `Origin` header (native, non-browser clients), allow any loopback origin
28
+ * (so cross-port localhost dev setups keep working), and allow explicitly
29
+ * configured origins. Everything else, such as a real remote page in the dev's
30
+ * browser, is rejected.
31
+ */
32
+ declare function isAllowedOrigin(origin: string | undefined, allowedOrigins: readonly string[]): boolean;
33
+ /**
34
+ * Decide whether a request-derived origin candidate may back a devframe's
35
+ * advertised public origin, the destination of the OTP magic link. Stricter
36
+ * than {@link isAllowedOrigin}: it rejects credentials, a path, a query, a
37
+ * fragment, a malformed port, and non-HTTP(S) schemes, and adopts a candidate
38
+ * only when its hostname is loopback or its canonical origin exactly matches
39
+ * an `allowedOrigins` entry (a caller with no static list passes none, so only
40
+ * loopback qualifies). Returns the canonical origin to adopt, or `undefined`
41
+ * to reject. Forwarded headers are never consulted.
42
+ */
43
+ declare function validateOriginCandidate(candidate: string, allowedOrigins?: readonly string[]): string | undefined;
44
+ //#endregion
45
+ export { isLoopbackHostname as n, validateOriginCandidate as r, isAllowedOrigin as t };
@@ -0,0 +1,80 @@
1
+ //#region src/utils/origin.ts
2
+ /**
3
+ * Origin and hostname predicates shared by the RPC transports (the WS upgrade,
4
+ * SSE, and MCP origin gates) and the instance shell's authentication-link
5
+ * origin validation. Kept dependency-free and runtime-agnostic so any consumer
6
+ * can pull in a single check without dragging in a transport's `crossws`
7
+ * import.
8
+ */
9
+ /**
10
+ * Whether `hostname` names a loopback host: `localhost` (or any `*.localhost`
11
+ * subdomain), the IPv6 loopback `::1`, or an IPv4 literal inside the
12
+ * `127.0.0.0/8` loopback block.
13
+ *
14
+ * The IPv4 case is matched **structurally**: the whole hostname must be a
15
+ * canonical dotted-decimal IPv4 literal whose first octet is `127`. A bare
16
+ * `startsWith('127.')` prefix check would also accept an attacker-controlled
17
+ * DNS name that merely *begins* with `127.` (`127.attacker.example`,
18
+ * `127.0.0.1.attacker.example`), letting a cross-origin browser page defeat
19
+ * the loopback origin gate that guards the RPC/MCP surface (a DNS-rebinding /
20
+ * cross-site WebSocket-hijacking bypass). Requiring a real IPv4 literal keeps
21
+ * genuine loopback addresses (`127.0.0.1`, `127.5.5.5`) allowed while rejecting
22
+ * those DNS names.
23
+ */
24
+ function isLoopbackHostname(hostname) {
25
+ const h = hostname.replace(/^\[|\]$/g, "");
26
+ if (h === "localhost" || h.endsWith(".localhost") || h === "::1") return true;
27
+ return isLoopbackIPv4(h);
28
+ }
29
+ /** A canonical dotted-decimal IPv4 literal in `127.0.0.0/8`. */
30
+ function isLoopbackIPv4(hostname) {
31
+ const octets = hostname.split(".");
32
+ if (octets.length !== 4 || !octets.every(isDecimalOctet)) return false;
33
+ return Number(octets[0]) === 127;
34
+ }
35
+ /** A single canonical IPv4 octet: 1–3 digits, no leading zero, value 0–255. */
36
+ function isDecimalOctet(part) {
37
+ if (!/^\d{1,3}$/.test(part) || part.length > 1 && part[0] === "0") return false;
38
+ return Number(part) <= 255;
39
+ }
40
+ /**
41
+ * Default origin policy for a localhost dev tool: allow requests with no
42
+ * `Origin` header (native, non-browser clients), allow any loopback origin
43
+ * (so cross-port localhost dev setups keep working), and allow explicitly
44
+ * configured origins. Everything else, such as a real remote page in the dev's
45
+ * browser, is rejected.
46
+ */
47
+ function isAllowedOrigin(origin, allowedOrigins) {
48
+ if (!origin) return true;
49
+ if (allowedOrigins.includes(origin)) return true;
50
+ try {
51
+ return isLoopbackHostname(new URL(origin).hostname);
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Decide whether a request-derived origin candidate may back a devframe's
58
+ * advertised public origin, the destination of the OTP magic link. Stricter
59
+ * than {@link isAllowedOrigin}: it rejects credentials, a path, a query, a
60
+ * fragment, a malformed port, and non-HTTP(S) schemes, and adopts a candidate
61
+ * only when its hostname is loopback or its canonical origin exactly matches
62
+ * an `allowedOrigins` entry (a caller with no static list passes none, so only
63
+ * loopback qualifies). Returns the canonical origin to adopt, or `undefined`
64
+ * to reject. Forwarded headers are never consulted.
65
+ */
66
+ function validateOriginCandidate(candidate, allowedOrigins) {
67
+ let url;
68
+ try {
69
+ url = new URL(candidate);
70
+ } catch {
71
+ return;
72
+ }
73
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
74
+ if (url.username || url.password || url.search || url.hash || url.pathname !== "/" && url.pathname !== "") return void 0;
75
+ const canonical = url.origin;
76
+ if (canonical === "null") return void 0;
77
+ if (isLoopbackHostname(url.hostname) || allowedOrigins?.includes(canonical)) return canonical;
78
+ }
79
+ //#endregion
80
+ export { isLoopbackHostname as n, validateOriginCandidate as r, isAllowedOrigin as t };
@@ -1,6 +1,6 @@
1
- import "../index-BzyopqxV.mjs";
2
- import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-CMdPYhOx.mjs";
3
- import "../context-BhBzOXVa.mjs";
1
+ import "../index-pIVt92jP.mjs";
2
+ import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-Dq4i156u.mjs";
3
+ import "../context-4AIVRLYF.mjs";
4
4
  import { SimpleSchema } from "../utils/simple-schema.mjs";
5
5
  //#region src/recipes/common-rpc-functions.d.ts
6
6
  /**
@@ -34,7 +34,7 @@ declare const KNOWN_EDITORS: KnownEditor[];
34
34
  * })
35
35
  * ```
36
36
  *
37
- * @deprecated Use the `@devframes/service-open` wire service instead — one
37
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
38
38
  * host-level installation shared by every plugin and feature-detectable from
39
39
  * clients, with workspace-root path containment on top of the editor gating.
40
40
  */
@@ -64,7 +64,7 @@ declare const openInEditor: {
64
64
  * ctx.rpc.register(openInFinder)
65
65
  * ```
66
66
  *
67
- * @deprecated Use the `@devframes/service-open` wire service instead — one
67
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
68
68
  * host-level installation shared by every plugin and feature-detectable from
69
69
  * clients, with workspace-root path containment.
70
70
  */
@@ -1,5 +1,5 @@
1
1
  import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs";
2
- import { t as s } from "../simple-schema-DQPZrAaZ.mjs";
2
+ import { t as s } from "../simple-schema-Bi40l-P6.mjs";
3
3
  //#region src/recipes/common-rpc-functions.ts
4
4
  /** Runtime list of every {@link KnownEditor}. */
5
5
  const KNOWN_EDITORS = [
@@ -57,7 +57,7 @@ const KNOWN_EDITORS = [
57
57
  * })
58
58
  * ```
59
59
  *
60
- * @deprecated Use the `@devframes/service-open` wire service instead — one
60
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
61
61
  * host-level installation shared by every plugin and feature-detectable from
62
62
  * clients, with workspace-root path containment on top of the editor gating.
63
63
  */
@@ -83,7 +83,7 @@ const openInEditor = defineRpcFunction({
83
83
  * ctx.rpc.register(openInFinder)
84
84
  * ```
85
85
  *
86
- * @deprecated Use the `@devframes/service-open` wire service instead — one
86
+ * @deprecated Use the `@devframes/service-open` wire service instead: one
87
87
  * host-level installation shared by every plugin and feature-detectable from
88
88
  * clients, with workspace-root path containment.
89
89
  */
@@ -1,9 +1,9 @@
1
- import { Ct as DevframeAuthHandler, o as DevframeNodeContext, s as DevframeNodeRpcSession } from "../context-BhBzOXVa.mjs";
2
- import "../index-DcKxIMoI.mjs";
1
+ import { o as DevframeNodeContext, s as DevframeNodeRpcSession, wt as DevframeAuthHandler } from "../context-4AIVRLYF.mjs";
2
+ import "../index-pKl67H6w.mjs";
3
3
  //#region src/recipes/interactive-auth.d.ts
4
4
  interface CreateInteractiveAuthOptions {
5
5
  /**
6
- * Static, pre-shared bearer tokens that are always trusted — for CI runs
6
+ * Static, pre-shared bearer tokens that are always trusted, for CI runs
7
7
  * or shared machines where the interactive code prompt would only get in
8
8
  * the way. Checked in both the handshake handler and the connect-time
9
9
  * hook, alongside tokens minted by a real code exchange.
@@ -11,7 +11,7 @@ interface CreateInteractiveAuthOptions {
11
11
  clientAuthTokens?: string[];
12
12
  /**
13
13
  * Print the current code + magic-link URL. Devframe stays headless, so
14
- * there is no default banner printed automatically — call
14
+ * there is no default banner printed automatically; call
15
15
  * `auth.printBanner()` yourself once the server is listening. Override
16
16
  * this to customize the format; defaults to a small boxed message on
17
17
  * stdout.
@@ -41,10 +41,10 @@ interface CreateInteractiveAuthOptions {
41
41
  * Package the interactive OTP auth protocol devframe's primitives
42
42
  * (`exchangeTempAuthCode`, `verifyAuthToken`, `revokeAuthToken`,
43
43
  * `getTempAuthCode`, `buildOtpAuthUrl`) implement into a ready-made
44
- * {@link DevframeAuthHandler} — the handshake RPC functions, the resolver
44
+ * {@link DevframeAuthHandler}: the handshake RPC functions, the resolver
45
45
  * gate, the connect-time trust hook, and the startup banner.
46
46
  *
47
- * The auth storage stays internal to this handler — callers never reach into
47
+ * The auth storage stays internal to this handler; callers never reach into
48
48
  * `devframe/node/hub-internals` themselves.
49
49
  *
50
50
  * ```ts
@@ -1,9 +1,9 @@
1
- import { s as colors } from "../nostics-CzECRXpE.mjs";
1
+ import { s as colors } from "../nostics-D0PvLZsn.mjs";
2
2
  import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs";
3
3
  import { isAnonymousRpcMethod } from "../constants.mjs";
4
- import { a as verifyAuthToken, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CK9LjrnT.mjs";
5
- import { t as getInternalContext } from "../context-KUqAfawQ.mjs";
6
- import { t as s } from "../simple-schema-DQPZrAaZ.mjs";
4
+ import { a as verifyAuthToken, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-CeQQWzM-.mjs";
5
+ import { t as getInternalContext } from "../context-DIUvJW4D.mjs";
6
+ import { t as s } from "../simple-schema-Bi40l-P6.mjs";
7
7
  //#region src/recipes/interactive-auth.ts
8
8
  function defaultBanner(info) {
9
9
  console.log(`\n ${colors.dim("devframe auth code")} ${colors.bold(info.code)}\n ${colors.dim("or open")} ${colors.cyan(info.url)}\n`);
@@ -12,10 +12,10 @@ function defaultBanner(info) {
12
12
  * Package the interactive OTP auth protocol devframe's primitives
13
13
  * (`exchangeTempAuthCode`, `verifyAuthToken`, `revokeAuthToken`,
14
14
  * `getTempAuthCode`, `buildOtpAuthUrl`) implement into a ready-made
15
- * {@link DevframeAuthHandler} — the handshake RPC functions, the resolver
15
+ * {@link DevframeAuthHandler}: the handshake RPC functions, the resolver
16
16
  * gate, the connect-time trust hook, and the startup banner.
17
17
  *
18
- * The auth storage stays internal to this handler — callers never reach into
18
+ * The auth storage stays internal to this handler; callers never reach into
19
19
  * `devframe/node/hub-internals` themselves.
20
20
  *
21
21
  * ```ts
@@ -1,8 +1,8 @@
1
- import { t as diagnostics } from "./diagnostics-BXWW3VK-.mjs";
1
+ import { t as diagnostics } from "./diagnostics-BMfN8mb1.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { isatty } from "node:tty";
4
4
  import { formatWithOptions, inspect } from "node:util";
5
- import { dirname, extname, join, normalize, sep } from "pathe";
5
+ import { dirname, extname, isAbsolute, join, normalize, resolve, sep } from "pathe";
6
6
  import { createReadStream, existsSync } from "node:fs";
7
7
  import { Buffer } from "node:buffer";
8
8
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -302,7 +302,7 @@ const MANIFEST_FILENAME = ".manifest.json";
302
302
  * list is dropped, because it describes the *provider's* transfer rather than
303
303
  * the file: hop-by-hop and encoding headers no longer match the body `fetch`
304
304
  * already decoded, and a CDN's policy headers (`set-cookie`, `cache-control`,
305
- * framing/CSP) belong to its origin — replaying them under the dev server's
305
+ * framing/CSP) belong to its origin, so replaying them under the dev server's
306
306
  * origin could just as well break the iframe these assets render in.
307
307
  */
308
308
  const PROXIED_HEADERS = [
@@ -436,6 +436,24 @@ function candidatePaths(prefix, cleaned) {
436
436
  if (!/\.[a-z0-9]+$/i.test(cleaned) && !candidates.includes(`${prefix}index.html`)) candidates.push(`${prefix}index.html`);
437
437
  return candidates;
438
438
  }
439
+ /**
440
+ * Resolve the safe destination for a provider-listed `filePath` beneath
441
+ * `prefix`, materializing into the already-resolved `root`, or `null` when
442
+ * the entry is unsafe or lies outside the selected `prefix`. A compromised
443
+ * provider is an untrusted boundary even though the built-in jsDelivr/unpkg
444
+ * listings never emit any of this: reject an absolute path, a backslash
445
+ * (never normalized into a separator; Windows-style traversal stays rejected
446
+ * on every platform), and any suffix whose resolved destination would land
447
+ * outside `root`. `target === root` is deliberately unsafe too: it names the
448
+ * directory itself, never a writable file.
449
+ */
450
+ function materializeTarget(filePath, prefix, root) {
451
+ if (filePath.includes("\\") || isAbsolute(filePath) || !filePath.startsWith(prefix)) return null;
452
+ const suffix = filePath.slice(prefix.length);
453
+ if (!suffix || isAbsolute(suffix)) return null;
454
+ const target = resolve(root, suffix);
455
+ return target === root || !target.startsWith(root + sep) ? null : target;
456
+ }
439
457
  function createStore(assets, cacheDir) {
440
458
  const normalized = {
441
459
  ...assets,
@@ -582,8 +600,10 @@ function createStore(assets, cacheDir) {
582
600
  } catch (error) {
583
601
  return fail(errText(error), error);
584
602
  }
585
- for (const filePath of files.filter((f) => f.startsWith(prefix))) {
586
- const target = join(targetDir, filePath.slice(prefix.length));
603
+ const root = resolve(targetDir);
604
+ for (const filePath of files) {
605
+ const target = materializeTarget(filePath, prefix, root);
606
+ if (target == null) continue;
587
607
  const url = provider.fileUrl(normalized.package, normalized.version, filePath);
588
608
  let res;
589
609
  try {
@@ -625,7 +645,7 @@ function assertValidRemoteAssets(assets) {
625
645
  * {@link RemoteAssetsStore} back-proxy. Remote caches live under
626
646
  * `<projectStorageDir>/.remote-assets/<package>@<version>/`.
627
647
  *
628
- * A remote source's `package`/`version` are validated first (`DF0065`) — both
648
+ * A remote source's `package`/`version` are validated first (`DF0065`); both
629
649
  * are interpolated into CDN URLs and the cache path.
630
650
  *
631
651
  * `defaultResolveFrom` (typically the declaring devframe's `importMetaUrl`)
@@ -6,16 +6,16 @@
6
6
  *
7
7
  * Resolution order at serve time:
8
8
  *
9
- * 1. The package installed locally (resolved from {@link resolveFrom})
10
- * — the zero-network / air-gap path. Version skew warns; a major
9
+ * 1. The package installed locally (resolved from {@link resolveFrom}),
10
+ * the zero-network / air-gap path. Version skew warns; a major
11
11
  * version mismatch throws.
12
12
  * 2. The per-file cache under
13
13
  * `<storageDir project>/.remote-assets/<package>@<version>/`.
14
- * 3. The CDN {@link provider} — each requested file streams through to
14
+ * 3. The CDN {@link provider}: each requested file streams through to
15
15
  * the browser while being written into the cache.
16
16
  *
17
17
  * Anywhere a static mount accepts a dist directory (`clientAssets`,
18
- * `hostStatic`, `mountStatic`) it also accepts this object — see
18
+ * `hostStatic`, `mountStatic`) it also accepts this object; see
19
19
  * {@link StaticAssetsSource}.
20
20
  */
21
21
  interface RemoteAssets {
@@ -39,7 +39,7 @@ interface RemoteAssets {
39
39
  * `import.meta.url` of the declaring module. When set, a locally
40
40
  * installed copy of {@link package} is resolved from this module's own
41
41
  * dependency graph first (works under pnpm's strict layout) and served
42
- * with zero network. Omitting it skips the installed-package step —
42
+ * with zero network. Omitting it skips the installed-package step;
43
43
  * cache + CDN still work.
44
44
  */
45
45
  resolveFrom?: string | null;
@@ -54,7 +54,7 @@ interface RemoteAssets {
54
54
  offline?: boolean;
55
55
  }
56
56
  /**
57
- * Built-in CDN providers (`'jsdelivr'` — default, `'unpkg'`) or a custom
57
+ * Built-in CDN providers (`'jsdelivr'`, the default, or `'unpkg'`) or a custom
58
58
  * provider for corp mirrors.
59
59
  */
60
60
  type RemoteAssetsProvider = 'jsdelivr' | 'unpkg' | RemoteAssetsProviderCustom;
@@ -97,7 +97,7 @@ interface RemoteAssetsErrorMessage {
97
97
  reason: string;
98
98
  }
99
99
  /**
100
- * A resolved, servable handle over a {@link RemoteAssets} declaration —
100
+ * A resolved, servable handle over a {@link RemoteAssets} declaration,
101
101
  * produced by `resolveStaticAssetsSource()` (`devframe/utils/remote-assets`)
102
102
  * and consumed by the static-serving engine (`devframe/utils/serve-static`).
103
103
  */
@@ -1,4 +1,4 @@
1
- import { t as DEVFRAME_EVENTS } from "./events-4daw0uK9.mjs";
1
+ import { t as DEVFRAME_EVENTS } from "./events-BV4Dj59a.mjs";
2
2
  //#region src/node/auth/revoke.ts
3
3
  /**
4
4
  * Flip `isTrusted` to false on any live WS clients connected with `token`
@@ -1,14 +1,5 @@
1
- import { h as RpcDumpStore, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny } from "../types-CMdPYhOx.mjs";
1
+ import { h as RpcDumpStore, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny } from "../types-Dq4i156u.mjs";
2
2
  //#region src/rpc/dump/collect.d.ts
3
- /**
4
- * Collects pre-computed dumps by executing functions with their defined input combinations.
5
- * Static functions without dump config automatically get `{ inputs: [[]] }`.
6
- *
7
- * @example
8
- * ```ts
9
- * const store = await dumpFunctions([greet], context, { concurrency: 10 })
10
- * ```
11
- */
12
3
  declare function dumpFunctions<T extends readonly RpcFunctionDefinitionAny[]>(definitions: T, context?: any, options?: RpcDumpCollectionOptions): Promise<RpcDumpStore<RpcDefinitionsToFunctions<T>>>;
13
4
  /**
14
5
  * Creates a client that serves pre-computed results from a dump store.
@@ -64,7 +55,7 @@ type StaticRpcDumpManifest = Record<string, StaticRpcDumpManifestValue>;
64
55
  interface StaticRpcDumpFile {
65
56
  /** Whether this file was written via `JSON.stringify` or `structured-clone-es.stringify`. */
66
57
  serialization: StaticRpcDumpSerialization;
67
- /** Function name the file belongs to — used to scope `DF0019` errors during write. */
58
+ /** Function name the file belongs to, used to scope `DF0019` errors during write. */
68
59
  fnName: string;
69
60
  /** Payload to encode. */
70
61
  data: unknown;
package/dist/rpc/dump.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as reviveDumpError, i as getDefinitionsWithDumps, n as createClientFromDump, o as serializeDumpError, r as dumpFunctions, t as collectStaticRpcDump } from "../static-DV_qUSRS.mjs";
1
+ import { a as reviveDumpError, i as getDefinitionsWithDumps, n as createClientFromDump, o as serializeDumpError, r as dumpFunctions, t as collectStaticRpcDump } from "../static-DZ8P2Kn7.mjs";
2
2
  export { collectStaticRpcDump, createClientFromDump, dumpFunctions, getDefinitionsWithDumps, reviveDumpError, serializeDumpError };
@@ -1,3 +1,3 @@
1
- import { a as STRUCTURED_CLONE_PREFIX, c as getRpcResolvedSetupResult, d as RpcFunctionsCollectorBase, f as RpcCacheManager, i as validateRpcReturn, l as createDefineWrapperWithContext, n as validateDefinitions, o as strictJsonStringify, p as RpcCacheOptions, r as validateRpcArgs, s as getRpcHandler, t as validateDefinition, u as defineRpcFunction } from "../index-BzyopqxV.mjs";
2
- import { C as RpcFunctionType, E as Thenable, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, a as RpcDefinitionsFilter, b as RpcFunctionDefinitionBase, c as RpcDump, d as RpcDumpDefinition, f as RpcDumpGetter, g as RpcFunctionAgentOptions, h as RpcDumpStore, i as RpcArgsSchema, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, p as RpcDumpRecord, r as EntriesToObject, s as RpcDefinitionsToFunctionsWithNamespace, t as BirpcFn, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector, x as RpcFunctionDefinitionToFunction, y as RpcFunctionDefinitionAnyWithContext } from "../types-CMdPYhOx.mjs";
1
+ import { a as STRUCTURED_CLONE_PREFIX, c as getRpcResolvedSetupResult, d as RpcFunctionsCollectorBase, f as RpcCacheManager, i as validateRpcReturn, l as createDefineWrapperWithContext, n as validateDefinitions, o as strictJsonStringify, p as RpcCacheOptions, r as validateRpcArgs, s as getRpcHandler, t as validateDefinition, u as defineRpcFunction } from "../index-pIVt92jP.mjs";
2
+ import { C as RpcFunctionType, E as Thenable, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, a as RpcDefinitionsFilter, b as RpcFunctionDefinitionBase, c as RpcDump, d as RpcDumpDefinition, f as RpcDumpGetter, g as RpcFunctionAgentOptions, h as RpcDumpStore, i as RpcArgsSchema, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, p as RpcDumpRecord, r as EntriesToObject, s as RpcDefinitionsToFunctionsWithNamespace, t as BirpcFn, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector, x as RpcFunctionDefinitionToFunction, y as RpcFunctionDefinitionAnyWithContext } from "../types-Dq4i156u.mjs";
3
3
  export { type BirpcFn, type BirpcReturn, EntriesToObject, RpcArgsSchema, RpcCacheManager, RpcCacheOptions, RpcDefinitionsFilter, RpcDefinitionsToFunctions, RpcDefinitionsToFunctionsWithNamespace, RpcDump, RpcDumpClientOptions, RpcDumpCollectionOptions, RpcDumpDefinition, RpcDumpGetter, RpcDumpRecord, RpcDumpRecordError, RpcDumpStore, RpcFunctionAgentOptions, RpcFunctionDefinition, RpcFunctionDefinitionAny, RpcFunctionDefinitionAnyWithContext, RpcFunctionDefinitionBase, RpcFunctionDefinitionToFunction, RpcFunctionSetupResult, RpcFunctionType, RpcFunctionsCollector, RpcFunctionsCollectorBase, RpcReturnSchema, STRUCTURED_CLONE_PREFIX, Thenable, createDefineWrapperWithContext, defineRpcFunction, getRpcHandler, getRpcResolvedSetupResult, strictJsonStringify, validateDefinition, validateDefinitions, validateRpcArgs, validateRpcReturn };
@@ -1,7 +1,7 @@
1
- import { a as validateRpcArgs, i as getRpcResolvedSetupResult, n as validateDefinitions, o as validateRpcReturn, r as getRpcHandler, s as hash, t as validateDefinition } from "../validation-YrZH6atx.mjs";
2
- import { t as diagnostics } from "../diagnostics-CD8nlgll.mjs";
1
+ import { a as validateRpcArgs, i as getRpcResolvedSetupResult, n as validateDefinitions, o as validateRpcReturn, r as getRpcHandler, s as hash, t as validateDefinition } from "../validation-BOy8IoFZ.mjs";
2
+ import { t as diagnostics } from "../diagnostics-D0EVm5M6.mjs";
3
3
  import { n as defineRpcFunction, t as createDefineWrapperWithContext } from "../define-BLWPsH6y.mjs";
4
- import { n as strictJsonStringify, t as STRUCTURED_CLONE_PREFIX } from "../serialization-BGzEwAdr.mjs";
4
+ import { n as strictJsonStringify, t as STRUCTURED_CLONE_PREFIX } from "../serialization-DTZnPQ1-.mjs";
5
5
  //#region src/rpc/cache.ts
6
6
  /**
7
7
  * @experimental API is expected to change.
@@ -1,2 +1,2 @@
1
- import { n as createSseRpcChannel, t as SseRpcChannelOptions } from "../../sse-client-DwX021ST.mjs";
1
+ import { n as createSseRpcChannel, t as SseRpcChannelOptions } from "../../sse-client-BQ4jS3eO.mjs";
2
2
  export { SseRpcChannelOptions, createSseRpcChannel };
@@ -1,10 +1,33 @@
1
1
  import { DEVFRAME_AUTH_TOKEN_QUERY_PARAM, DEVFRAME_SSE_SESSION_HEADER } from "../../constants.mjs";
2
- import { t as createRpcWireCodec } from "../../wire-codec-0K-o5MYW.mjs";
2
+ import { t as createRpcWireCodec } from "../../wire-codec-dcCeXcSo.mjs";
3
3
  //#region src/rpc/transports/sse-client.ts
4
4
  function NOOP() {}
5
+ /** Split the next complete SSE frame (up to a blank line) off the buffer. */
6
+ function takeFrame(buffer) {
7
+ const boundary = buffer.search(/\n\n|\r\n\r\n/);
8
+ if (boundary < 0) return void 0;
9
+ return {
10
+ frame: buffer.slice(0, boundary),
11
+ rest: buffer.slice(boundary + (buffer[boundary] === "\r" ? 4 : 2))
12
+ };
13
+ }
14
+ /** Parse one SSE frame's lines into its event name and data lines. */
15
+ function parseFrame(frame) {
16
+ let event = "message";
17
+ const data = [];
18
+ for (const rawLine of frame.split(/\r?\n/)) {
19
+ if (rawLine.startsWith(":")) continue;
20
+ if (rawLine.startsWith("event:")) event = rawLine.slice(6).trimStart();
21
+ else if (rawLine.startsWith("data:")) data.push(rawLine.slice(5).replace(/^ /, ""));
22
+ }
23
+ return {
24
+ event,
25
+ data
26
+ };
27
+ }
5
28
  /**
6
29
  * Build a birpc `ChannelOptions` object backed by an SSE stream (server →
7
- * client) and HTTP `POST` (client → server) — the WebSocket-free counterpart
30
+ * client) and HTTP `POST` (client → server): the WebSocket-free counterpart
8
31
  * to `createWsRpcChannel`, wire-compatible with `attachSseRpcTransport`.
9
32
  *
10
33
  * The stream is consumed via `fetch` streaming (not `EventSource`), so it
@@ -12,7 +35,7 @@ function NOOP() {}
12
35
  * (`event: session`) carries the session id; every `POST` echoes it in the
13
36
  * `x-birpc-session` header. A response to a client-initiated request comes
14
37
  * back in the `POST`'s own body and is re-injected into the channel; a
15
- * dropped stream terminates the channel — there is no reconnect, matching
38
+ * dropped stream terminates the channel; there is no reconnect, matching
16
39
  * the WS channel's closed-is-done semantics.
17
40
  */
18
41
  function createSseRpcChannel(options) {
@@ -63,17 +86,10 @@ function createSseRpcChannel(options) {
63
86
  if (done) break;
64
87
  buffer += decoder.decode(value, { stream: true });
65
88
  for (;;) {
66
- const boundary = buffer.search(/\n\n|\r\n\r\n/);
67
- if (boundary < 0) break;
68
- const frame = buffer.slice(0, boundary);
69
- buffer = buffer.slice(boundary + (buffer[boundary] === "\r" ? 4 : 2));
70
- let event = "message";
71
- const data = [];
72
- for (const rawLine of frame.split(/\r?\n/)) {
73
- if (rawLine.startsWith(":")) continue;
74
- if (rawLine.startsWith("event:")) event = rawLine.slice(6).trimStart();
75
- else if (rawLine.startsWith("data:")) data.push(rawLine.slice(5).replace(/^ /, ""));
76
- }
89
+ const taken = takeFrame(buffer);
90
+ if (!taken) break;
91
+ buffer = taken.rest;
92
+ const { event, data } = parseFrame(taken.frame);
77
93
  if (data.length > 0) dispatch(event, data.join("\n"));
78
94
  }
79
95
  }
@@ -1,5 +1,5 @@
1
- import { v as RpcFunctionDefinitionAny } from "../../types-CMdPYhOx.mjs";
2
- import { d as DevframeRpcConnection, n as WsOriginRegistry, u as DevframeNodeRpcSessionMeta } from "../../ws-server-Di2oqr4q.mjs";
1
+ import { v as RpcFunctionDefinitionAny } from "../../types-Dq4i156u.mjs";
2
+ import { c as DevframeNodeRpcSessionMeta, l as DevframeRpcConnection, n as WsOriginRegistry } from "../../ws-server-D2nv68Hg.mjs";
3
3
  import { BirpcGroup } from "birpc";
4
4
  //#region src/rpc/transports/sse-server.d.ts
5
5
  interface SseRpcTransportOptions {
@@ -14,7 +14,7 @@ interface SseRpcTransportOptions {
14
14
  * RPC function definitions, used by the per-call wire serializer to
15
15
  * dispatch between strict-JSON and structured-clone encoding based on
16
16
  * each function's `jsonSerializable` flag. When omitted, all messages
17
- * fall back to structured-clone — same contract as the WS transport.
17
+ * fall back to structured-clone, the same contract as the WS transport.
18
18
  */
19
19
  definitions?: ReadonlyMap<string, Pick<RpcFunctionDefinitionAny, 'jsonSerializable'>>;
20
20
  onConnected?: (connection: DevframeRpcConnection, meta: DevframeNodeRpcSessionMeta) => void;
@@ -42,7 +42,7 @@ interface SseRpcTransport {
42
42
  close: () => void;
43
43
  }
44
44
  /**
45
- * Attach an SSE + HTTP POST transport to an existing RPC group — the
45
+ * Attach an SSE + HTTP POST transport to an existing RPC group: the
46
46
  * WebSocket-free counterpart to `attachWsRpcTransport`, for hosts and
47
47
  * proxies where the upgrade isn't available. Speaks the same birpc wire
48
48
  * protocol (one channel per session, per-method `jsonSerializable`
@@ -1,15 +1,17 @@
1
1
  import { DEVFRAME_SSE_SESSION_HEADER } from "../../constants.mjs";
2
- import { n as peekRpcWireFrame, t as createRpcWireCodec } from "../../wire-codec-0K-o5MYW.mjs";
3
- import { i as isAllowedOrigin, o as createRpcSessionMeta } from "../../ws-server-BdSLrhxE.mjs";
2
+ import { n as peekRpcWireFrame, t as createRpcWireCodec } from "../../wire-codec-dcCeXcSo.mjs";
3
+ import { t as isAllowedOrigin } from "../../origin-DZit9g29.mjs";
4
+ import { t as createRpcSessionMeta } from "../../session-DPfj6zQG.mjs";
4
5
  //#region src/rpc/transports/sse-server.ts
5
6
  const SSE_STREAM_HEADERS = {
6
7
  "content-type": "text/event-stream",
7
8
  "cache-control": "no-cache, no-transform",
9
+ /** Tell buffering reverse proxies (nginx) to pass frames through as-is. */
8
10
  "x-accel-buffering": "no"
9
11
  };
10
12
  function NOOP() {}
11
13
  /**
12
- * Attach an SSE + HTTP POST transport to an existing RPC group — the
14
+ * Attach an SSE + HTTP POST transport to an existing RPC group: the
13
15
  * WebSocket-free counterpart to `attachWsRpcTransport`, for hosts and
14
16
  * proxies where the upgrade isn't available. Speaks the same birpc wire
15
17
  * protocol (one channel per session, per-method `jsonSerializable`
@@ -33,7 +35,7 @@ function attachSseRpcTransport(rpcGroup, options = {}) {
33
35
  return allowedOrigins && !Array.isArray(allowedOrigins) ? allowedOrigins.isAllowed(origin) : isAllowedOrigin(origin, allowedOrigins ?? []);
34
36
  }
35
37
  /**
36
- * CORS headers for a browser on another (allowed) origin — the side-car /
38
+ * CORS headers for a browser on another (allowed) origin: the side-car /
37
39
  * registered-viewer case. Same-origin requests carry no `Origin` (or their
38
40
  * own), where these headers are inert.
39
41
  */
@@ -65,8 +67,6 @@ function attachSseRpcTransport(rpcGroup, options = {}) {
65
67
  const session = {
66
68
  id,
67
69
  meta,
68
- connection: void 0,
69
- channel: void 0,
70
70
  parked: /* @__PURE__ */ new Map(),
71
71
  closed: false,
72
72
  close: () => {
@@ -80,7 +80,7 @@ function attachSseRpcTransport(rpcGroup, options = {}) {
80
80
  controller?.close();
81
81
  } catch {}
82
82
  rpcGroup.updateChannels((channels) => {
83
- const index = channels.indexOf(session.channel);
83
+ const index = session.channel ? channels.indexOf(session.channel) : -1;
84
84
  if (index >= 0) channels.splice(index, 1);
85
85
  });
86
86
  onDisconnected(session.connection, meta);