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.
Files changed (103) hide show
  1. package/dist/_shared-CttmCMBi.mjs +70 -0
  2. package/dist/_shared-DmpWW-HH.d.mts +43 -0
  3. package/dist/adapters/build.d.mts +1 -1
  4. package/dist/adapters/build.mjs +6 -5
  5. package/dist/adapters/cac.d.mts +1 -1
  6. package/dist/adapters/cac.mjs +157 -1
  7. package/dist/adapters/dev.d.mts +25 -34
  8. package/dist/adapters/dev.mjs +2 -1
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +223 -0
  11. package/dist/adapters/initiate.mjs +2 -0
  12. package/dist/adapters/mcp.d.mts +26 -2
  13. package/dist/adapters/mcp.mjs +2 -2
  14. package/dist/cli/main.mjs +2 -2
  15. package/dist/client/index.d.mts +70 -6
  16. package/dist/client/index.mjs +743 -408
  17. package/dist/constants.d.mts +19 -6
  18. package/dist/constants.mjs +19 -6
  19. package/dist/{context-CQefP2jR.mjs → context-C33rR7n0.mjs} +1 -1
  20. package/dist/{context-DFzmxCLa.d.mts → context-CSCwoABx.d.mts} +1 -1
  21. package/dist/{host-h3-Kz7t5Xab.mjs → context-Du11TLcO.mjs} +5 -255
  22. package/dist/dev-BEveeA5H.mjs +233 -0
  23. package/dist/{devframe-qgCKL683.d.mts → devframe-Bdd9YXTy.d.mts} +88 -25
  24. package/dist/{diagnostics-B5-qHeqD.mjs → diagnostics-DLYH5oD3.mjs} +20 -0
  25. package/dist/dist-D8jAMwxU.mjs +227 -0
  26. package/dist/helpers/vite.d.mts +43 -39
  27. package/dist/helpers/vite.mjs +26 -38
  28. package/dist/host-agent-CpbAoqBx.mjs +230 -0
  29. package/dist/host-h3-CzCZwtuV.mjs +26 -0
  30. package/dist/{fetch-CK0S253E.mjs → http-DLr_cJZ7.mjs} +42 -4
  31. package/dist/{index-B7RgLw--.d.mts → index-CZRd2K1C.d.mts} +2 -2
  32. package/dist/{index-Dbw1p5ch.d.mts → index-DSCq4M4q.d.mts} +2 -31
  33. package/dist/index.d.mts +9 -4
  34. package/dist/index.mjs +8 -1
  35. package/dist/{instance-registry-D6fxYu36.mjs → instance-registry-BQqGoDO9.mjs} +9 -2
  36. package/dist/instance-shell-DBTXTSjN.d.mts +264 -0
  37. package/dist/instance-shell-KRdee1QF.mjs +485 -0
  38. package/dist/internal/index.d.mts +150 -0
  39. package/dist/internal/index.mjs +7 -0
  40. package/dist/node/auth.d.mts +2 -2
  41. package/dist/node/hub-internals.d.mts +2 -14
  42. package/dist/node/hub-internals.mjs +2 -2
  43. package/dist/node/index.d.mts +3 -267
  44. package/dist/node/index.mjs +3 -5
  45. package/dist/recipes/common-rpc-functions.d.mts +3 -3
  46. package/dist/recipes/interactive-auth.d.mts +3 -3
  47. package/dist/recipes/interactive-auth.mjs +6 -6
  48. package/dist/rolldown-runtime-JspESFgx.mjs +35 -0
  49. package/dist/rpc/dump.d.mts +77 -1
  50. package/dist/rpc/dump.mjs +1 -1
  51. package/dist/rpc/index.d.mts +2 -2
  52. package/dist/rpc/index.mjs +3 -17
  53. package/dist/rpc/transports/sse-client.d.mts +2 -0
  54. package/dist/rpc/transports/sse-client.mjs +142 -0
  55. package/dist/rpc/transports/sse-server.d.mts +61 -0
  56. package/dist/rpc/transports/sse-server.mjs +209 -0
  57. package/dist/rpc/transports/ws-bun.d.mts +35 -0
  58. package/dist/rpc/transports/ws-bun.mjs +31 -0
  59. package/dist/rpc/transports/ws-client.d.mts +1 -1
  60. package/dist/rpc/transports/ws-client.mjs +10 -18
  61. package/dist/rpc/transports/ws-server.d.mts +2 -2
  62. package/dist/rpc/transports/ws-server.mjs +2 -214
  63. package/dist/rpc-core-CGctXToO.d.mts +48 -0
  64. package/dist/rpc-core-CqcJkAu9.mjs +81 -0
  65. package/dist/{serialization-C8Mnw9hK.mjs → serialization-BHY8M5NQ.mjs} +1 -1
  66. package/dist/{shared-state-6kHolYZy.mjs → shared-state-fRRbRUtD.mjs} +1 -1
  67. package/dist/sse-client-BsIK3hMD.d.mts +37 -0
  68. package/dist/{dump-CgZShDRB.mjs → static-CvjkO8QE.mjs} +2 -265
  69. package/dist/{storage-Dzoc3NVC.mjs → storage-BcmVEJRc.mjs} +2 -2
  70. package/dist/types/index.d.mts +3 -3
  71. package/dist/types/index.mjs +1 -6
  72. package/dist/utils/events.d.mts +1 -1
  73. package/dist/utils/launch-editor.mjs +1 -25
  74. package/dist/utils/open.mjs +1 -1
  75. package/dist/utils/serve-static.mjs +1 -1
  76. package/dist/utils/shared-state.d.mts +1 -1
  77. package/dist/utils/shared-state.mjs +1 -1
  78. package/dist/utils/simple-schema.d.mts +101 -1
  79. package/dist/utils/streaming-channel.d.mts +1 -1
  80. package/dist/validation-BiuDXTKW.mjs +266 -0
  81. package/dist/wire-codec-9VhIKnyp.mjs +58 -0
  82. package/dist/{ws-client-B6Tnr0ic.d.mts → ws-client-CdNuATYa.d.mts} +6 -1
  83. package/dist/ws-server-Bk1hOG3X.mjs +267 -0
  84. package/dist/{ws-server-J-zkiOyp.d.mts → ws-server-Ces08fjP.d.mts} +102 -13
  85. package/package.json +10 -9
  86. package/skills/devframe/SKILL.md +84 -85
  87. package/dist/_shared-bWRzeSa0.mjs +0 -19
  88. package/dist/adapters/cli.d.mts +0 -11
  89. package/dist/adapters/cli.mjs +0 -6
  90. package/dist/cac-B1LM3zit.mjs +0 -157
  91. package/dist/dev-BSHFZGZr.mjs +0 -437
  92. package/dist/http-Dvgxujcu.mjs +0 -38
  93. package/dist/index-vAX6bYuc.d.mts +0 -78
  94. package/dist/recipes/open-helpers.d.mts +0 -6
  95. package/dist/recipes/open-helpers.mjs +0 -6
  96. package/dist/server-CXaDDUl0.mjs +0 -148
  97. package/dist/server-E9z4ZWbd.d.mts +0 -132
  98. package/dist/simple-schema-BDzLeJDk.d.mts +0 -102
  99. package/dist/utils/promise.d.mts +0 -8
  100. package/dist/utils/promise.mjs +0 -15
  101. package/dist/utils/scope.d.mts +0 -11
  102. package/dist/utils/scope.mjs +0 -15
  103. package/dist/{open-Deb5xmIT.mjs → open-Dz4V4irZ.mjs} +1 -1
@@ -1,157 +0,0 @@
1
- import { n as colors } from "./diagnostics-reporter-CsIG85Q5.mjs";
2
- import { createBuild } from "./adapters/build.mjs";
3
- import { n as resolveDevServerPort, t as createDevServer } from "./dev-BSHFZGZr.mjs";
4
- import process from "node:process";
5
- import cac$1 from "cac";
6
- //#region src/adapters/flags.ts
7
- /**
8
- * Identity helper that preserves the literal schema-map type — use this
9
- * so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
10
- *
11
- * ```ts
12
- * const appFlags = defineCliFlags({
13
- * depth: v.pipe(v.number(), v.integer()),
14
- * config: v.optional(v.string()),
15
- * })
16
- *
17
- * defineDevframe({
18
- * cli: { flags: appFlags },
19
- * setup(ctx, info) {
20
- * const flags = info.flags as InferCliFlags<typeof appFlags>
21
- * flags.depth // number
22
- * flags.config // string | undefined
23
- * },
24
- * })
25
- * ```
26
- */
27
- function defineCliFlags(flags) {
28
- return flags;
29
- }
30
- /**
31
- * Best-effort, dependency-free probe of a schema to decide whether the
32
- * corresponding CAC option takes a value. Duck-types the `type` /
33
- * `wrapped` / `inner` / `pipe` fields exposed by valibot and by devframe's
34
- * built-in `s` builder, unwrapping `optional` / `nullable` / `nullish` /
35
- * `pipe` wrappers then matching on the inner kind. Validators that don't
36
- * expose these fields (e.g. zod) fall through to a value-taking option.
37
- */
38
- function getSchemaKind(schema) {
39
- let current = schema;
40
- while (current) {
41
- const kind = current.type;
42
- if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") {
43
- current = current.wrapped ?? current.inner;
44
- continue;
45
- }
46
- if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) {
47
- current = current.pipe[0];
48
- continue;
49
- }
50
- return kind ?? "unknown";
51
- }
52
- return "unknown";
53
- }
54
- /** Whether the CAC option for this schema should be a boolean flag. */
55
- function isBooleanFlag(schema) {
56
- return getSchemaKind(schema) === "boolean";
57
- }
58
- /** Validate the raw cac-parsed bag against a {@link CliFlagsSchema}. */
59
- function parseCliFlags(schema, raw) {
60
- const flags = {};
61
- const issues = [];
62
- for (const [key, fieldSchema] of Object.entries(schema)) {
63
- const result = fieldSchema["~standard"].validate(raw[key]);
64
- if (result instanceof Promise) {
65
- issues.push(`--${toKebab(key)}: async flag validation is not supported`);
66
- continue;
67
- }
68
- if (result.issues) issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`);
69
- else flags[key] = result.value;
70
- }
71
- for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value;
72
- return issues.length ? {
73
- flags,
74
- issues
75
- } : { flags };
76
- }
77
- function toKebab(camel) {
78
- return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
79
- }
80
- /** Kebab-case a schema key for CAC option registration. */
81
- function flagKeyToOption(camel) {
82
- return toKebab(camel);
83
- }
84
- //#endregion
85
- //#region src/adapters/cac.ts
86
- /**
87
- * Wrap a {@link DevframeDefinition} in a `cac`-powered command-line
88
- * interface exposing `dev` / `build` / `mcp` subcommands.
89
- *
90
- * Requires the optional `cac` peer dependency.
91
- */
92
- function createCac(d, options = {}) {
93
- const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999;
94
- const defaultHost = d.cli?.host ?? "localhost";
95
- const cli = cac$1(d.cli?.command ?? d.id);
96
- const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser").option("--no-auth", "Disable the interactive authentication gate").option("--mcp", "Expose an MCP server over HTTP at /__mcp (use --no-mcp to disable) [experimental]");
97
- if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) {
98
- const optionName = flagKeyToOption(key);
99
- const description = schema.description ?? "";
100
- if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description);
101
- else devCommand.option(`--${optionName} <value>`, description);
102
- }
103
- devCommand.action(async (_args, rawFlags) => {
104
- const flags = resolveTypedFlags(d, rawFlags);
105
- const host = flags.host ?? defaultHost;
106
- const port = flags.port ?? await resolveDevServerPort(d, {
107
- host,
108
- defaultPort
109
- });
110
- const mcp = flags.mcp;
111
- await createDevServer(d, {
112
- host,
113
- port,
114
- flags,
115
- mcp,
116
- onReady: options.onReady
117
- });
118
- });
119
- if (d.capabilities?.build !== false) cli.command("build", "Build a self-contained static deploy of the devframe").option("--out-dir <outDir>", "Output directory", { default: "dist-static" }).option("--base <base>", "URL base", { default: "/" }).option("--pretty", "Pretty-print dump JSON (larger on disk)").action(async (flags) => {
120
- await createBuild(d, {
121
- outDir: flags.outDir,
122
- base: flags.base,
123
- pretty: flags.pretty
124
- });
125
- });
126
- cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => {
127
- const { createMcpServer } = await import("./adapters/mcp.mjs");
128
- await createMcpServer(d, {
129
- transport: "stdio",
130
- onReady: ({ transport }) => {
131
- console.error(`[devframe] "${d.id}" MCP server ready (${transport})`);
132
- }
133
- });
134
- });
135
- d.cli?.configure?.(cli);
136
- options.configureCli?.(cli);
137
- cli.help();
138
- cli.version("0.0.0");
139
- return {
140
- cli,
141
- async parse(argv = process.argv) {
142
- cli.parse(argv, { run: false });
143
- await cli.runMatchedCommand();
144
- }
145
- };
146
- }
147
- function resolveTypedFlags(d, raw) {
148
- if (!d.cli?.flags) return raw;
149
- const { flags, issues } = parseCliFlags(d.cli.flags, raw);
150
- if (issues?.length) {
151
- for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`);
152
- process.exit(1);
153
- }
154
- return flags;
155
- }
156
- //#endregion
157
- export { defineCliFlags as n, parseCliFlags as r, createCac as t };
@@ -1,437 +0,0 @@
1
- import { DEVFRAME_CONNECTION_META_FILENAME } from "./constants.mjs";
2
- import { n as createHostContext, t as createH3DevframeHost } from "./host-h3-Kz7t5Xab.mjs";
3
- import { t as diagnostics } from "./diagnostics-B5-qHeqD.mjs";
4
- import { r as registerDevframeInstance } from "./instance-registry-D6fxYu36.mjs";
5
- import { i as normalizeHttpServerUrl, t as startHttpAndWs } from "./server-CXaDDUl0.mjs";
6
- import { n as resolveBasePath, t as normalizeBasePath } from "./_shared-bWRzeSa0.mjs";
7
- import { t as open } from "./open-Deb5xmIT.mjs";
8
- import { mountStaticHandler } from "./utils/serve-static.mjs";
9
- import { createInteractiveAuth } from "./recipes/interactive-auth.mjs";
10
- import { resolve } from "pathe";
11
- import process$1 from "node:process";
12
- import { networkInterfaces } from "node:os";
13
- import { H3 } from "h3";
14
- import { createServer } from "node:net";
15
- import { joinURL, withBase, withLeadingSlash, withoutLeadingSlash } from "ufo";
16
- //#region ../../node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs
17
- const unsafePorts = /* @__PURE__ */ new Set([
18
- 1,
19
- 7,
20
- 9,
21
- 11,
22
- 13,
23
- 15,
24
- 17,
25
- 19,
26
- 20,
27
- 21,
28
- 22,
29
- 23,
30
- 25,
31
- 37,
32
- 42,
33
- 43,
34
- 53,
35
- 69,
36
- 77,
37
- 79,
38
- 87,
39
- 95,
40
- 101,
41
- 102,
42
- 103,
43
- 104,
44
- 109,
45
- 110,
46
- 111,
47
- 113,
48
- 115,
49
- 117,
50
- 119,
51
- 123,
52
- 135,
53
- 137,
54
- 139,
55
- 143,
56
- 161,
57
- 179,
58
- 389,
59
- 427,
60
- 465,
61
- 512,
62
- 513,
63
- 514,
64
- 515,
65
- 526,
66
- 530,
67
- 531,
68
- 532,
69
- 540,
70
- 548,
71
- 554,
72
- 556,
73
- 563,
74
- 587,
75
- 601,
76
- 636,
77
- 989,
78
- 990,
79
- 993,
80
- 995,
81
- 1719,
82
- 1720,
83
- 1723,
84
- 2049,
85
- 3659,
86
- 4045,
87
- 5060,
88
- 5061,
89
- 6e3,
90
- 6566,
91
- 6665,
92
- 6666,
93
- 6667,
94
- 6668,
95
- 6669,
96
- 6697,
97
- 10080
98
- ]);
99
- function isUnsafePort(port) {
100
- return unsafePorts.has(port);
101
- }
102
- function isSafePort(port) {
103
- return !isUnsafePort(port);
104
- }
105
- var GetPortError = class extends Error {
106
- constructor(message, opts) {
107
- super(message, opts);
108
- this.message = message;
109
- }
110
- name = "GetPortError";
111
- };
112
- function _log(verbose, message) {
113
- if (verbose) console.log(`[get-port] ${message}`);
114
- }
115
- function _generateRange(from, to) {
116
- if (to < from) return [];
117
- const r = [];
118
- for (let index = from; index <= to; index++) r.push(index);
119
- return r;
120
- }
121
- function _tryPort(port, host) {
122
- return new Promise((resolve) => {
123
- const server = createServer();
124
- server.unref();
125
- server.on("error", () => {
126
- resolve(false);
127
- });
128
- server.listen({
129
- port,
130
- host
131
- }, () => {
132
- const { port: port2 } = server.address();
133
- server.close(() => {
134
- resolve(isSafePort(port2) && port2);
135
- });
136
- });
137
- });
138
- }
139
- function _getLocalHosts(additional) {
140
- const hosts = new Set(additional);
141
- for (const _interface of Object.values(networkInterfaces())) for (const config of _interface || []) if (config.address && !config.internal && !config.address.startsWith("fe80::") && !config.address.startsWith("169.254")) hosts.add(config.address);
142
- return [...hosts];
143
- }
144
- async function _findPort(ports, host) {
145
- for (const port of ports) {
146
- const r = await _tryPort(port, host);
147
- if (r) return r;
148
- }
149
- }
150
- function _fmtOnHost(hostname) {
151
- return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host";
152
- }
153
- const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(?<!-)$/;
154
- function _validateHostname(hostname, _public, verbose) {
155
- if (hostname && !HOSTNAME_RE.test(hostname)) {
156
- const fallbackHost = _public ? "0.0.0.0" : "127.0.0.1";
157
- _log(verbose, `Invalid hostname: ${JSON.stringify(hostname)}. Using ${JSON.stringify(fallbackHost)} as fallback.`);
158
- return fallbackHost;
159
- }
160
- return hostname;
161
- }
162
- async function getPort(_userOptions = {}) {
163
- if (typeof _userOptions === "number" || typeof _userOptions === "string") _userOptions = { port: Number.parseInt(_userOptions + "") || 0 };
164
- const _port = Number(_userOptions.port ?? process.env.PORT);
165
- const _userSpecifiedAnyPort = Boolean(_userOptions.port || _userOptions.ports?.length || _userOptions.portRange?.length);
166
- const options = {
167
- random: _port === 0,
168
- ports: [],
169
- portRange: [],
170
- alternativePortRange: _userSpecifiedAnyPort ? [] : [3e3, 3100],
171
- verbose: false,
172
- ..._userOptions,
173
- port: _port,
174
- host: _validateHostname(_userOptions.host ?? process.env.HOST, _userOptions.public, _userOptions.verbose)
175
- };
176
- if (options.random && !_userSpecifiedAnyPort) return getRandomPort(options.host);
177
- const portsToCheck = [
178
- options.port,
179
- ...options.ports,
180
- ..._generateRange(...options.portRange)
181
- ].filter((port) => {
182
- if (!port) return false;
183
- if (!isSafePort(port)) {
184
- _log(options.verbose, `Ignoring unsafe port: ${port}`);
185
- return false;
186
- }
187
- return true;
188
- });
189
- if (portsToCheck.length === 0) portsToCheck.push(3e3);
190
- let availablePort = await _findPort(portsToCheck, options.host);
191
- if (!availablePort && options.alternativePortRange.length > 0) {
192
- availablePort = await _findPort(_generateRange(...options.alternativePortRange), options.host);
193
- if (portsToCheck.length > 0) {
194
- let message = `Unable to find an available port (tried ${portsToCheck.join("-")} ${_fmtOnHost(options.host)}).`;
195
- if (availablePort) message += ` Using alternative port ${availablePort}.`;
196
- _log(options.verbose, message);
197
- }
198
- }
199
- if (!availablePort && _userOptions.random !== false) {
200
- availablePort = await getRandomPort(options.host);
201
- if (availablePort) _log(options.verbose, `Using random port ${availablePort}`);
202
- }
203
- if (!availablePort) {
204
- const triedRanges = [
205
- options.port,
206
- options.portRange.join("-"),
207
- options.alternativePortRange.join("-")
208
- ].filter(Boolean).join(", ");
209
- throw new GetPortError(`Unable to find an available port ${_fmtOnHost(options.host)} (tried ${triedRanges})`);
210
- }
211
- return availablePort;
212
- }
213
- async function getRandomPort(host) {
214
- const port = await checkPort(0, host);
215
- if (port === false) throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`);
216
- return port;
217
- }
218
- async function checkPort(port, host = process.env.HOST, verbose) {
219
- if (!host) host = _getLocalHosts([void 0, "0.0.0.0"]);
220
- if (!Array.isArray(host)) return _tryPort(port, host);
221
- for (const _host of host) {
222
- const _port = await _tryPort(port, _host);
223
- if (_port === false) {
224
- if (port < 1024 && verbose) _log(verbose, `Unable to listen to the privileged port ${port} ${_fmtOnHost(_host)}`);
225
- return false;
226
- }
227
- if (port === 0 && _port !== 0) port = _port;
228
- }
229
- return port;
230
- }
231
- //#endregion
232
- //#region src/adapters/dev.ts
233
- const DEFAULT_PORT = 9999;
234
- /**
235
- * Resolve the listening port for {@link createDevServer}, honoring the
236
- * definition's `cli.port` / `cli.portRange` / `cli.random` settings.
237
- * Exposed separately so authors who run their own argv parsing can
238
- * resolve a port up-front (to print it, log it, etc.) before starting
239
- * the server.
240
- */
241
- async function resolveDevServerPort(def, options = {}) {
242
- const host = options.host ?? def.cli?.host ?? "localhost";
243
- const portOptions = {
244
- port: options.defaultPort ?? def.cli?.port ?? DEFAULT_PORT,
245
- host
246
- };
247
- if (def.cli?.portRange) portOptions.portRange = def.cli.portRange;
248
- if (def.cli?.random) portOptions.random = def.cli.random;
249
- return getPort(portOptions);
250
- }
251
- /**
252
- * Start a devframe dev server for a {@link DevframeDefinition} —
253
- * h3 + WebSocket RPC + (optionally) the author's SPA mounted at the
254
- * resolved base path.
255
- *
256
- * When `distDir` is omitted (and `def.cli?.distDir` is unset) the
257
- * server runs in **bridge mode**: only `__connection.json` and the WS
258
- * endpoint are mounted, with no SPA mount. The SPA is expected to be
259
- * hosted elsewhere (e.g. by a parent Vite/Nuxt dev server) — see
260
- * `viteDevBridge({ devMiddleware })`.
261
- *
262
- * Returns the underlying {@link StartedServer} handle so callers can
263
- * close it gracefully (SIGINT, hot-reload, test teardown).
264
- *
265
- * Use this directly when integrating devframe into an existing CLI
266
- * framework (commander, yargs, hand-rolled CAC). For the all-in-one
267
- * `dev` / `build` / `mcp` shell, reach for {@link createCac} instead.
268
- */
269
- async function createDevServer(def, options = {}) {
270
- const distDir = options.distDir ?? def.cli?.distDir;
271
- const host = options.host ?? def.cli?.host ?? "localhost";
272
- const port = options.port ?? await resolveDevServerPort(def, { host });
273
- const flags = options.flags ?? {};
274
- const basePath = options.basePath ? normalizeBasePath(options.basePath) : resolveBasePath(def, "standalone");
275
- const app = options.app ?? new H3();
276
- const h3Host = createH3DevframeHost({
277
- origin: normalizeHttpServerUrl(host, port),
278
- appName: def.id,
279
- mount: (base, dir) => {
280
- mountStaticHandler(app, base, dir);
281
- }
282
- });
283
- const ctx = await createHostContext({
284
- cwd: process$1.cwd(),
285
- mode: "dev",
286
- host: h3Host
287
- });
288
- const setupInfo = { flags };
289
- await def.setup(ctx, setupInfo);
290
- const mcpConfig = resolveMcpConfig(options.mcp ?? def.cli?.mcp);
291
- let mcpDispose;
292
- let mcpMeta;
293
- if (mcpConfig) {
294
- const mcpRoute = withoutLeadingSlash(mcpConfig.path ?? "__mcp");
295
- const mcpPath = joinURL(basePath, mcpRoute);
296
- let mountMcpHttp;
297
- try {
298
- ({mountMcpHttp} = await import("./http-Dvgxujcu.mjs"));
299
- } catch (error) {
300
- const reason = error instanceof Error ? error.message : String(error);
301
- throw diagnostics.DF0017({
302
- transport: "http",
303
- reason,
304
- cause: error
305
- });
306
- }
307
- mcpDispose = mountMcpHttp(app, ctx, mcpPath, {
308
- serverName: `${def.id} (devframe)`,
309
- serverVersion: def.version ?? "0.0.0",
310
- exposeSharedState: true,
311
- allowedOrigins: mcpConfig.allowedOrigins
312
- }).dispose;
313
- mcpMeta = { path: mcpRoute };
314
- }
315
- const { bindPath, wsPort, meta } = resolveWsConnection(def, options, basePath);
316
- const connectionMetaPath = joinURL(basePath, DEVFRAME_CONNECTION_META_FILENAME);
317
- app.use(connectionMetaPath, () => ({
318
- backend: "websocket",
319
- websocket: meta,
320
- ...mcpMeta ? { mcp: mcpMeta } : {}
321
- }));
322
- if (distDir) mountStaticHandler(app, basePath, resolve(distDir));
323
- const authOption = flags.auth === false ? false : options.auth !== void 0 ? options.auth : def.cli?.auth;
324
- let authHandler;
325
- let resolvedAuth;
326
- if (authOption === false) resolvedAuth = false;
327
- else if (typeof authOption === "object") {
328
- authHandler = authOption;
329
- resolvedAuth = authOption;
330
- } else {
331
- authHandler = createInteractiveAuth(ctx);
332
- resolvedAuth = authHandler;
333
- }
334
- const started = await startHttpAndWs({
335
- context: ctx,
336
- host,
337
- port,
338
- app,
339
- path: bindPath,
340
- wsPort,
341
- auth: resolvedAuth,
342
- onReady: async (info) => {
343
- authHandler?.printBanner();
344
- await options.onReady?.(info);
345
- await maybeOpenBrowser(def, flags, `${info.origin}${basePath}`, options.openBrowser, authHandler);
346
- }
347
- });
348
- const registration = registerDevframeInstance({
349
- pid: process$1.pid,
350
- port: started.port,
351
- origin: normalizeHttpServerUrl(host, started.port),
352
- basePath,
353
- id: def.id,
354
- name: def.name,
355
- rootDir: process$1.cwd(),
356
- mcp: mcpConfig ? { path: joinURL(basePath, withoutLeadingSlash(mcpConfig.path ?? "__mcp")) } : null,
357
- startedAt: Date.now()
358
- });
359
- const closeServer = started.close;
360
- started.close = async () => {
361
- registration.unregister();
362
- await mcpDispose?.();
363
- await closeServer();
364
- };
365
- return started;
366
- }
367
- /**
368
- * Normalize the `cli.mcp` / `mcp` option (`boolean | McpRouteOptions`) into
369
- * concrete options, or `undefined` when the MCP route is disabled.
370
- */
371
- function resolveMcpConfig(mcp) {
372
- if (!mcp) return void 0;
373
- return mcp === true ? {} : mcp;
374
- }
375
- /**
376
- * Resolve the `mcp` entry a `__connection.json` should advertise for a dev
377
- * server started with the given `mcp` option (falling back to `def.cli?.mcp`,
378
- * exactly like {@link createDevServer}), or `undefined` when the route is
379
- * disabled.
380
- *
381
- * Hosted bridges that hand-roll their connection meta (`viteDevBridge`,
382
- * `@devframes/next`'s handler) pass the side-car `port`: the advertised path
383
- * becomes absolute (the side-car mounts at `/`) and the client dials
384
- * `<page-host>:<port><path>`. Without `port` the path stays relative, resolved
385
- * against `__connection.json`'s own location (the same-server default).
386
- *
387
- * @experimental
388
- */
389
- function resolveMcpConnectionMeta(def, mcp, port) {
390
- const config = resolveMcpConfig(mcp ?? def.cli?.mcp);
391
- if (!config) return void 0;
392
- const route = withoutLeadingSlash(config.path ?? "__mcp");
393
- return port != null ? {
394
- path: withLeadingSlash(route),
395
- port
396
- } : { path: route };
397
- }
398
- /**
399
- * Resolve the three WS connection scenarios from the definition / call-site
400
- * config into a concrete server bind path, optional dedicated port, and the
401
- * `__connection.json` descriptor the browser resolves.
402
- */
403
- function resolveWsConnection(def, options, basePath) {
404
- const ws = options.ws ?? def.cli?.ws ?? {};
405
- const route = withoutLeadingSlash(ws.route ?? "__devframe_ws");
406
- if (ws.url) return {
407
- bindPath: joinURL(basePath, route),
408
- wsPort: void 0,
409
- meta: ws.url
410
- };
411
- if (ws.port != null) return {
412
- bindPath: withLeadingSlash(route),
413
- wsPort: ws.port,
414
- meta: {
415
- port: ws.port,
416
- path: route
417
- }
418
- };
419
- return {
420
- bindPath: joinURL(basePath, route),
421
- wsPort: void 0,
422
- meta: { path: route }
423
- };
424
- }
425
- async function maybeOpenBrowser(def, flags, origin, override, authHandler) {
426
- const flagsOpen = flags.open;
427
- const cliOpen = def.cli?.open;
428
- const resolved = override ?? flagsOpen ?? cliOpen;
429
- if (resolved === void 0 || resolved === false) return;
430
- const target = typeof resolved === "string" ? withBase(resolved, origin) : origin;
431
- const authorizedTarget = authHandler?.buildOpenUrl?.(target) ?? target;
432
- try {
433
- await open(authorizedTarget);
434
- } catch {}
435
- }
436
- //#endregion
437
- export { resolveDevServerPort as n, resolveMcpConnectionMeta as r, createDevServer as t };
@@ -1,38 +0,0 @@
1
- import { t as createMcpFetchHandler } from "./fetch-CK0S253E.mjs";
2
- import { defineHandler } from "h3";
3
- //#region src/adapters/mcp/http.ts
4
- /**
5
- * Mount an MCP Streamable-HTTP endpoint on an h3 app at `path` — the h3
6
- * binding over {@link createMcpFetchHandler}, which owns the sessions, the
7
- * origin gate, and the transport plumbing.
8
- *
9
- * The handler is web-standard — it takes the h3 event's web `Request` and
10
- * returns a web `Response` (an SSE `ReadableStream` body for the
11
- * server→client stream). We copy that response onto `event.res` and return
12
- * its body rather than returning the `Response` object directly, so a
13
- * legitimate MCP 404 (unknown session) isn't swallowed by h3's
14
- * "Response-with-404 falls through to the next handler" rule (which would
15
- * otherwise hand the request to the SPA static catch-all).
16
- *
17
- * @experimental
18
- */
19
- function mountMcpHttp(app, ctx, path, options) {
20
- const handler = createMcpFetchHandler(ctx, options);
21
- app.use(path, defineHandler(async (event) => respond(event, await handler.fetch(event.req))));
22
- return { dispose: handler.dispose };
23
- }
24
- /**
25
- * Copy a web `Response` from the MCP transport onto the h3 event's response
26
- * and return its body. Returning the body (a `ReadableStream` or `null`)
27
- * rather than the `Response` object avoids h3's 404-fall-through behavior.
28
- */
29
- function respond(event, response) {
30
- event.res.status = response.status;
31
- event.res.statusText = response.statusText;
32
- response.headers.forEach((value, key) => {
33
- event.res.headers.set(key, value);
34
- });
35
- return response.body ?? "";
36
- }
37
- //#endregion
38
- export { mountMcpHttp };