| import { a as diagnostics } from "./storage-D_Xy9v1l.mjs"; | ||
| import { n as createHostContext } from "./host-h3-SjwRTwkE.mjs"; | ||
| import { Diagnostic } from "nostics"; | ||
| import { join } from "pathe"; | ||
| import process from "node:process"; | ||
| import { homedir } from "node:os"; | ||
| import { Server } from "@modelcontextprotocol/sdk/server/index.js"; | ||
| import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js"; | ||
| import { toJsonSchema } from "@valibot/to-json-schema"; | ||
| //#region src/adapters/mcp/stringify.ts | ||
| /** | ||
| * JSON-coercing serializer for MCP text payloads. | ||
| * | ||
| * MCP carries tool results and resource reads as plain text over a | ||
| * JSON-RPC transport, so we cannot use the `s:`-prefixed structured-clone | ||
| * format the WS RPC transport falls back to for non-JSON values. Instead, | ||
| * we coerce common non-JSON types into JSON-friendly forms so the LLM | ||
| * client sees something useful instead of `[object Object]`. | ||
| * | ||
| * Coercions: | ||
| * - `BigInt` → `"123n"` | ||
| * - `Date` → ISO string (via the native `toJSON`) | ||
| * - `Map` → `{ __type: 'Map', entries: [[k, v], …] }` | ||
| * - `Set` → `{ __type: 'Set', entries: [v, …] }` | ||
| * - `Error` → `{ name, message, stack, cause? }` (cause recurses) | ||
| * - `Function` → `"[Function: name]"` | ||
| * - `Symbol` → `value.toString()` | ||
| * - cycles → `"[Circular]"` | ||
| */ | ||
| function stringifyForMcp(value) { | ||
| if (value === void 0) return "undefined"; | ||
| if (typeof value === "string") return value; | ||
| const seen = /* @__PURE__ */ new WeakSet(); | ||
| return JSON.stringify(value, (_key, val) => { | ||
| if (typeof val === "bigint") return `${val}n`; | ||
| if (val instanceof Error) { | ||
| const out = { | ||
| name: val.name, | ||
| message: val.message, | ||
| stack: val.stack | ||
| }; | ||
| if (val.cause !== void 0) out.cause = val.cause; | ||
| return out; | ||
| } | ||
| if (val instanceof Map) return { | ||
| __type: "Map", | ||
| entries: [...val.entries()] | ||
| }; | ||
| if (val instanceof Set) return { | ||
| __type: "Set", | ||
| entries: [...val] | ||
| }; | ||
| if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`; | ||
| if (typeof val === "symbol") return val.toString(); | ||
| if (val !== null && typeof val === "object") { | ||
| if (seen.has(val)) return "[Circular]"; | ||
| seen.add(val); | ||
| } | ||
| return val; | ||
| }, 2); | ||
| } | ||
| /** | ||
| * Format a thrown value for an MCP `isError` text payload. | ||
| * | ||
| * A nostics `Diagnostic` (every coded devframe error) becomes structured | ||
| * JSON — `{ error: { code, message, fix?, docs? } }` — so an agent receives | ||
| * the actionable next step (`fix`) and the docs URL instead of a bare | ||
| * message string. Other errors surface `Error.name`/`message`, plus one | ||
| * level of `cause.message` so context isn't dropped silently. | ||
| */ | ||
| function formatMcpError(error) { | ||
| if (error instanceof Diagnostic) return JSON.stringify({ error: { | ||
| code: error.code, | ||
| message: error.message, | ||
| ...error.fix ? { fix: error.fix } : {}, | ||
| ...error.docs ? { docs: error.docs } : {} | ||
| } }, null, 2); | ||
| if (!(error instanceof Error)) return String(error); | ||
| const cause = error.cause; | ||
| const causeText = cause instanceof Error ? ` (cause: ${cause.message})` : cause !== void 0 ? ` (cause: ${String(cause)})` : ""; | ||
| return `${error.name}: ${error.message}${causeText}`; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/mcp/to-json-schema.ts | ||
| const FALLBACK_OBJECT_SCHEMA = Object.freeze({ | ||
| type: "object", | ||
| additionalProperties: true | ||
| }); | ||
| /** | ||
| * Convert a valibot return schema to JSON Schema. | ||
| * @internal | ||
| */ | ||
| function valibotReturnToJsonSchema(schema) { | ||
| if (!schema) return void 0; | ||
| try { | ||
| return toJsonSchema(schema); | ||
| } catch { | ||
| return FALLBACK_OBJECT_SCHEMA; | ||
| } | ||
| } | ||
| /** | ||
| * Convert positional RPC args schemas to a single MCP-friendly object | ||
| * schema. When the RPC declares `args: [v.object(...)]`, unwrap the | ||
| * single-object schema directly (nicer agent UX than `{ arg0: {...} }`). | ||
| * | ||
| * Returns `undefined` when there are no args (the MCP SDK treats this | ||
| * as `{ type: 'object', properties: {} }`). | ||
| * @internal | ||
| */ | ||
| function valibotArgsToJsonSchema(args) { | ||
| if (!args || args.length === 0) return { | ||
| schema: { | ||
| type: "object", | ||
| properties: {} | ||
| }, | ||
| unwrapped: false | ||
| }; | ||
| if (args.length === 1) { | ||
| const inner = safeToJsonSchema(args[0]); | ||
| if (isObjectJsonSchema(inner)) return { | ||
| schema: inner, | ||
| unwrapped: true | ||
| }; | ||
| } | ||
| const properties = {}; | ||
| const required = []; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const key = `arg${i}`; | ||
| properties[key] = safeToJsonSchema(args[i]); | ||
| required.push(key); | ||
| } | ||
| return { | ||
| schema: { | ||
| type: "object", | ||
| properties, | ||
| required, | ||
| additionalProperties: false | ||
| }, | ||
| unwrapped: false | ||
| }; | ||
| } | ||
| function safeToJsonSchema(schema) { | ||
| try { | ||
| return toJsonSchema(schema); | ||
| } catch { | ||
| return FALLBACK_OBJECT_SCHEMA; | ||
| } | ||
| } | ||
| function isObjectJsonSchema(value) { | ||
| return !!value && typeof value === "object" && value.type === "object"; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/mcp/build-server.ts | ||
| /** | ||
| * Wire an MCP {@link Server} to a devframe context. Returns the server | ||
| * plus a disposal function for the subscriptions it sets up. The | ||
| * transport is the caller's responsibility — `createMcpServer` connects | ||
| * stdio; tests can connect an {@link InMemoryTransport} instead. | ||
| * | ||
| * @internal | ||
| */ | ||
| function buildMcpServerFromContext(ctx, options) { | ||
| const server = new Server({ | ||
| name: options.serverName, | ||
| version: options.serverVersion | ||
| }, { capabilities: { | ||
| tools: { listChanged: true }, | ||
| resources: { listChanged: true } | ||
| } }); | ||
| registerToolHandlers(server, ctx); | ||
| registerResourceHandlers(server, ctx, options.exposeSharedState); | ||
| const notify = (method) => { | ||
| server.notification({ method }).catch(() => {}); | ||
| }; | ||
| const offManifest = ctx.agent.events.on("agent:manifest:changed", () => { | ||
| notify("notifications/tools/list_changed"); | ||
| notify("notifications/resources/list_changed"); | ||
| }); | ||
| const offKeyAdded = ctx.rpc.sharedState.onKeyAdded(() => { | ||
| notify("notifications/resources/list_changed"); | ||
| }); | ||
| return { | ||
| server, | ||
| dispose: () => { | ||
| offManifest(); | ||
| offKeyAdded(); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Build an MCP server over the agent surface of a devframe definition. | ||
| * Currently supports `stdio` transport only. | ||
| * | ||
| * @experimental The agent-native surface is experimental and may change | ||
| * without a major version bump until it stabilizes. | ||
| */ | ||
| async function createMcpServer(definition, options = {}) { | ||
| const transport = options.transport ?? "stdio"; | ||
| if (transport !== "stdio") throw diagnostics.DF0017({ | ||
| transport, | ||
| reason: "Only stdio transport is supported in this release." | ||
| }); | ||
| const ctx = await createHostContext({ | ||
| cwd: process.cwd(), | ||
| mode: "dev", | ||
| host: { | ||
| mountStatic: () => {}, | ||
| resolveOrigin: () => "mcp://devframe", | ||
| getStorageDir: (scope) => { | ||
| if (scope === "workspace") return join(process.cwd(), ".devframe"); | ||
| if (scope === "project") return join(process.cwd(), `node_modules/.${definition.id}/devframe`); | ||
| return join(homedir(), `.${definition.id}/devframe`); | ||
| } | ||
| } | ||
| }); | ||
| await definition.setup(ctx); | ||
| const { server, dispose } = buildMcpServerFromContext(ctx, { | ||
| serverName: options.serverName ?? `${definition.id} (devframe)`, | ||
| serverVersion: options.serverVersion ?? definition.version ?? "0.0.0", | ||
| exposeSharedState: options.exposeSharedState ?? true | ||
| }); | ||
| const { startStdioTransport } = await import("./transports-BmDVn4SF.mjs"); | ||
| let stop; | ||
| try { | ||
| stop = await startStdioTransport(server); | ||
| } catch (error) { | ||
| const reason = error instanceof Error ? error.message : String(error); | ||
| throw diagnostics.DF0017({ | ||
| transport, | ||
| reason, | ||
| cause: error | ||
| }); | ||
| } | ||
| options.onReady?.({ transport: "stdio" }); | ||
| return { async stop() { | ||
| dispose(); | ||
| await stop(); | ||
| } }; | ||
| } | ||
| function registerToolHandlers(server, ctx) { | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => { | ||
| return { tools: ctx.agent.list().tools.map((tool) => projectTool(tool, ctx)) }; | ||
| }); | ||
| server.setRequestHandler(CallToolRequestSchema, async (request) => { | ||
| const { name, arguments: args } = request.params; | ||
| try { | ||
| const tool = ctx.agent.getTool(name); | ||
| const outputSchema = tool ? tool.outputSchema ?? computeOutputSchema(tool, ctx) : void 0; | ||
| const result = await ctx.agent.invoke(name, args ?? {}); | ||
| return { | ||
| content: [{ | ||
| type: "text", | ||
| text: stringifyForMcp(result) | ||
| }], | ||
| ...outputSchema ? { structuredContent: result } : {} | ||
| }; | ||
| } catch (error) { | ||
| return { | ||
| isError: true, | ||
| content: [{ | ||
| type: "text", | ||
| text: `Error invoking "${name}": ${formatMcpError(error)}` | ||
| }] | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| function registerResourceHandlers(server, ctx, exposeSharedState) { | ||
| server.setRequestHandler(ListResourcesRequestSchema, async () => { | ||
| const resources = ctx.agent.list().resources.map((resource) => ({ | ||
| uri: resource.uri, | ||
| name: resource.name, | ||
| description: resource.description, | ||
| mimeType: resource.mimeType | ||
| })); | ||
| if (exposeSharedState !== false) { | ||
| const filter = typeof exposeSharedState === "function" ? exposeSharedState : () => true; | ||
| for (const key of ctx.rpc.sharedState.keys()) { | ||
| if (!filter(key)) continue; | ||
| resources.push({ | ||
| uri: `devframe://state/${encodeURIComponent(key)}`, | ||
| name: key, | ||
| description: `Shared state: ${key}`, | ||
| mimeType: "application/json" | ||
| }); | ||
| } | ||
| } | ||
| return { resources }; | ||
| }); | ||
| server.setRequestHandler(ReadResourceRequestSchema, async (request) => { | ||
| const { uri } = request.params; | ||
| const parsed = parseResourceUri(uri); | ||
| if (parsed.kind === "resource") { | ||
| const content = await ctx.agent.read(parsed.id); | ||
| return { contents: [{ | ||
| uri, | ||
| mimeType: content.mimeType ?? "application/json", | ||
| text: content.text ?? stringifyForMcp(content.json) | ||
| }] }; | ||
| } | ||
| if (parsed.kind === "state") return { contents: [{ | ||
| uri, | ||
| mimeType: "application/json", | ||
| text: stringifyForMcp((await ctx.rpc.sharedState.get(parsed.key)).value()) | ||
| }] }; | ||
| throw new Error(`[devframe/mcp] unknown resource URI "${uri}"`); | ||
| }); | ||
| } | ||
| function projectTool(tool, ctx) { | ||
| const inputSchema = tool.inputSchema ?? computeInputSchema(tool, ctx); | ||
| const outputSchema = tool.outputSchema ?? computeOutputSchema(tool, ctx); | ||
| return { | ||
| name: tool.id, | ||
| title: tool.title, | ||
| description: tool.description, | ||
| inputSchema, | ||
| ...outputSchema ? { outputSchema } : {}, | ||
| annotations: { | ||
| title: tool.title, | ||
| readOnlyHint: tool.safety === "read", | ||
| destructiveHint: tool.safety === "destructive" | ||
| } | ||
| }; | ||
| } | ||
| function computeInputSchema(tool, ctx) { | ||
| if (tool.kind !== "rpc" || !tool.rpcName) return { | ||
| type: "object", | ||
| properties: {} | ||
| }; | ||
| const def = ctx.rpc.definitions.get(tool.rpcName); | ||
| if (!def) return { | ||
| type: "object", | ||
| properties: {} | ||
| }; | ||
| const args = def.args; | ||
| return valibotArgsToJsonSchema(args).schema; | ||
| } | ||
| function computeOutputSchema(tool, ctx) { | ||
| if (tool.kind !== "rpc" || !tool.rpcName) return void 0; | ||
| const def = ctx.rpc.definitions.get(tool.rpcName); | ||
| if (!def) return void 0; | ||
| return valibotReturnToJsonSchema(def.returns); | ||
| } | ||
| function parseResourceUri(uri) { | ||
| const match = uri.match(/^devframe:\/\/(resource|state)\/(.+)$/); | ||
| if (!match) return { kind: "unknown" }; | ||
| const [, kind, rest] = match; | ||
| const decoded = decodeURIComponent(rest); | ||
| if (kind === "resource") return { | ||
| kind: "resource", | ||
| id: decoded | ||
| }; | ||
| return { | ||
| kind: "state", | ||
| key: decoded | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { createMcpServer as n, buildMcpServerFromContext as t }; |
| import { n as colors } from "./diagnostics-reporter-CsIG85Q5.mjs"; | ||
| import { createBuild } from "./adapters/build.mjs"; | ||
| import { n as resolveDevServerPort, t as createDevServer } from "./dev-OJFr4rx8.mjs"; | ||
| import process from "node:process"; | ||
| import cac from "cac"; | ||
| import { safeParse } from "valibot"; | ||
| //#region src/adapters/flags.ts | ||
| /** | ||
| * Identity helper that preserves the literal schema-map type — use this | ||
| * so `InferCliFlags<typeof myFlags>` resolves to the right object shape. | ||
| * | ||
| * ```ts | ||
| * const appFlags = defineCliFlags({ | ||
| * depth: v.pipe(v.number(), v.integer()), | ||
| * config: v.optional(v.string()), | ||
| * }) | ||
| * | ||
| * defineDevframe({ | ||
| * cli: { flags: appFlags }, | ||
| * setup(ctx, info) { | ||
| * const flags = info.flags as InferCliFlags<typeof appFlags> | ||
| * flags.depth // number | ||
| * flags.config // string | undefined | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| function defineCliFlags(flags) { | ||
| return flags; | ||
| } | ||
| /** | ||
| * Best-effort probe of a valibot schema to decide whether the | ||
| * corresponding CAC option takes a value. Unwraps `optional` / `nullable` | ||
| * / `nullish` / `default` / `pipe` wrappers then matches on the inner | ||
| * type's kind. | ||
| */ | ||
| function getSchemaKind(schema) { | ||
| let current = schema; | ||
| while (current) { | ||
| const kind = current.type; | ||
| if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") { | ||
| current = current.wrapped ?? current.inner; | ||
| continue; | ||
| } | ||
| if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) { | ||
| current = current.pipe[0]; | ||
| continue; | ||
| } | ||
| return kind; | ||
| } | ||
| return "unknown"; | ||
| } | ||
| /** Whether the CAC option for this schema should be a boolean flag. */ | ||
| function isBooleanFlag(schema) { | ||
| return getSchemaKind(schema) === "boolean"; | ||
| } | ||
| /** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */ | ||
| function parseCliFlags(schema, raw) { | ||
| const flags = {}; | ||
| const issues = []; | ||
| for (const [key, fieldSchema] of Object.entries(schema)) { | ||
| const result = safeParse(fieldSchema, raw[key]); | ||
| if (result.success) flags[key] = result.output; | ||
| else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`); | ||
| } | ||
| for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value; | ||
| return issues.length ? { | ||
| flags, | ||
| issues | ||
| } : { flags }; | ||
| } | ||
| function toKebab(camel) { | ||
| return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
| } | ||
| /** Kebab-case a schema key for CAC option registration. */ | ||
| function flagKeyToOption(camel) { | ||
| return toKebab(camel); | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/cac.ts | ||
| /** | ||
| * Wrap a {@link DevframeDefinition} in a `cac`-powered command-line | ||
| * interface exposing `dev` / `build` / `mcp` subcommands. | ||
| * | ||
| * Requires the optional `cac` peer dependency. | ||
| */ | ||
| function createCac(d, options = {}) { | ||
| const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999; | ||
| const defaultHost = d.cli?.host ?? "localhost"; | ||
| const cli = cac(d.cli?.command ?? d.id); | ||
| 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]"); | ||
| if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) { | ||
| const optionName = flagKeyToOption(key); | ||
| const description = schema.description ?? ""; | ||
| if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description); | ||
| else devCommand.option(`--${optionName} <value>`, description); | ||
| } | ||
| devCommand.action(async (_args, rawFlags) => { | ||
| const flags = resolveTypedFlags(d, rawFlags); | ||
| const host = flags.host ?? defaultHost; | ||
| const port = flags.port ?? await resolveDevServerPort(d, { | ||
| host, | ||
| defaultPort | ||
| }); | ||
| const mcp = flags.mcp; | ||
| await createDevServer(d, { | ||
| host, | ||
| port, | ||
| flags, | ||
| mcp, | ||
| onReady: options.onReady | ||
| }); | ||
| }); | ||
| 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) => { | ||
| await createBuild(d, { | ||
| outDir: flags.outDir, | ||
| base: flags.base, | ||
| pretty: flags.pretty | ||
| }); | ||
| }); | ||
| cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => { | ||
| const { createMcpServer } = await import("./adapters/mcp.mjs"); | ||
| await createMcpServer(d, { | ||
| transport: "stdio", | ||
| onReady: ({ transport }) => { | ||
| console.error(`[devframe] "${d.id}" MCP server ready (${transport})`); | ||
| } | ||
| }); | ||
| }); | ||
| d.cli?.configure?.(cli); | ||
| options.configureCli?.(cli); | ||
| cli.help(); | ||
| cli.version("0.0.0"); | ||
| return { | ||
| cli, | ||
| async parse(argv = process.argv) { | ||
| cli.parse(argv, { run: false }); | ||
| await cli.runMatchedCommand(); | ||
| } | ||
| }; | ||
| } | ||
| function resolveTypedFlags(d, raw) { | ||
| if (!d.cli?.flags) return raw; | ||
| const { flags, issues } = parseCliFlags(d.cli.flags, raw); | ||
| if (issues?.length) { | ||
| for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`); | ||
| process.exit(1); | ||
| } | ||
| return flags; | ||
| } | ||
| //#endregion | ||
| export { defineCliFlags as n, parseCliFlags as r, createCac as t }; |
| import { b as DevframeNodeContext, ht as SharedState } from "./devframe-BADsX91-.mjs"; | ||
| //#region src/node/hub-internals/context.d.ts | ||
| interface InternalAnonymousAuthStorage { | ||
| trusted: Record<string, { | ||
| authToken: string; | ||
| ua: string; | ||
| origin: string; | ||
| timestamp: number; | ||
| } | undefined>; | ||
| } | ||
| interface RemoteTokenRecord { | ||
| dockId: string; | ||
| /** Dock URL origin — matched against WS handshake `Origin` header when `originLock` is on. */ | ||
| origin: string; | ||
| originLock: boolean; | ||
| } | ||
| interface DevframeInternalContext { | ||
| storage: { | ||
| auth: SharedState<InternalAnonymousAuthStorage>; | ||
| }; | ||
| /** | ||
| * Revoke an auth token: remove from storage and notify all connected clients | ||
| * using this token that they are no longer trusted. | ||
| */ | ||
| revokeAuthToken: (token: string) => Promise<void>; | ||
| /** | ||
| * Session-only tokens issued to remote-UI iframe docks. Not persisted — | ||
| * regenerated on every dev-server restart. | ||
| */ | ||
| remoteTokens: Map<string, RemoteTokenRecord>; | ||
| allocateRemoteToken: (dockId: string, origin: string, originLock: boolean) => string; | ||
| revokeRemoteToken: (token: string) => void; | ||
| revokeRemoteTokensForDock: (dockId: string) => void; | ||
| /** | ||
| * Returns true if `token` is a valid remote token and, when `originLock` is | ||
| * on, `requestOrigin` matches the recorded dock origin. | ||
| */ | ||
| isRemoteTokenTrusted: (token: string, requestOrigin?: string) => boolean; | ||
| /** | ||
| * Populated by `createWsServer` once the WS port is bound. Consumed by the | ||
| * docks host when enriching remote iframe URLs with a connection descriptor. | ||
| */ | ||
| wsEndpoint?: { | ||
| /** Full `ws://` or `wss://` URL with host and port. */ | ||
| url: string; | ||
| }; | ||
| } | ||
| declare const internalContextMap: WeakMap<DevframeNodeContext, DevframeInternalContext>; | ||
| declare function getInternalContext(context: DevframeNodeContext): DevframeInternalContext; | ||
| //#endregion | ||
| export { internalContextMap as a, getInternalContext as i, InternalAnonymousAuthStorage as n, RemoteTokenRecord as r, DevframeInternalContext as t }; |
| import { DEVFRAME_CONNECTION_META_FILENAME } from "./constants.mjs"; | ||
| import { a as diagnostics } from "./storage-D_Xy9v1l.mjs"; | ||
| import { n as createHostContext, t as createH3DevframeHost } from "./host-h3-SjwRTwkE.mjs"; | ||
| import { i as normalizeHttpServerUrl, t as startHttpAndWs } from "./server-BFsuZI9e.mjs"; | ||
| import { n as resolveBasePath, t as normalizeBasePath } from "./_shared-bWRzeSa0.mjs"; | ||
| import { t as open } from "./open-Deb5xmIT.mjs"; | ||
| import { mountStaticHandler } from "./utils/serve-static.mjs"; | ||
| import { createInteractiveAuth } from "./recipes/interactive-auth.mjs"; | ||
| import { resolve } from "pathe"; | ||
| import process$1 from "node:process"; | ||
| import { networkInterfaces } from "node:os"; | ||
| import { H3 } from "h3"; | ||
| import { createServer } from "node:net"; | ||
| import { joinURL, withBase, withLeadingSlash, withoutLeadingSlash } from "ufo"; | ||
| //#region ../../node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs | ||
| const unsafePorts = /* @__PURE__ */ new Set([ | ||
| 1, | ||
| 7, | ||
| 9, | ||
| 11, | ||
| 13, | ||
| 15, | ||
| 17, | ||
| 19, | ||
| 20, | ||
| 21, | ||
| 22, | ||
| 23, | ||
| 25, | ||
| 37, | ||
| 42, | ||
| 43, | ||
| 53, | ||
| 69, | ||
| 77, | ||
| 79, | ||
| 87, | ||
| 95, | ||
| 101, | ||
| 102, | ||
| 103, | ||
| 104, | ||
| 109, | ||
| 110, | ||
| 111, | ||
| 113, | ||
| 115, | ||
| 117, | ||
| 119, | ||
| 123, | ||
| 135, | ||
| 137, | ||
| 139, | ||
| 143, | ||
| 161, | ||
| 179, | ||
| 389, | ||
| 427, | ||
| 465, | ||
| 512, | ||
| 513, | ||
| 514, | ||
| 515, | ||
| 526, | ||
| 530, | ||
| 531, | ||
| 532, | ||
| 540, | ||
| 548, | ||
| 554, | ||
| 556, | ||
| 563, | ||
| 587, | ||
| 601, | ||
| 636, | ||
| 989, | ||
| 990, | ||
| 993, | ||
| 995, | ||
| 1719, | ||
| 1720, | ||
| 1723, | ||
| 2049, | ||
| 3659, | ||
| 4045, | ||
| 5060, | ||
| 5061, | ||
| 6e3, | ||
| 6566, | ||
| 6665, | ||
| 6666, | ||
| 6667, | ||
| 6668, | ||
| 6669, | ||
| 6697, | ||
| 10080 | ||
| ]); | ||
| function isUnsafePort(port) { | ||
| return unsafePorts.has(port); | ||
| } | ||
| function isSafePort(port) { | ||
| return !isUnsafePort(port); | ||
| } | ||
| var GetPortError = class extends Error { | ||
| constructor(message, opts) { | ||
| super(message, opts); | ||
| this.message = message; | ||
| } | ||
| name = "GetPortError"; | ||
| }; | ||
| function _log(verbose, message) { | ||
| if (verbose) console.log(`[get-port] ${message}`); | ||
| } | ||
| function _generateRange(from, to) { | ||
| if (to < from) return []; | ||
| const r = []; | ||
| for (let index = from; index <= to; index++) r.push(index); | ||
| return r; | ||
| } | ||
| function _tryPort(port, host) { | ||
| return new Promise((resolve) => { | ||
| const server = createServer(); | ||
| server.unref(); | ||
| server.on("error", () => { | ||
| resolve(false); | ||
| }); | ||
| server.listen({ | ||
| port, | ||
| host | ||
| }, () => { | ||
| const { port: port2 } = server.address(); | ||
| server.close(() => { | ||
| resolve(isSafePort(port2) && port2); | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
| function _getLocalHosts(additional) { | ||
| const hosts = new Set(additional); | ||
| 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); | ||
| return [...hosts]; | ||
| } | ||
| async function _findPort(ports, host) { | ||
| for (const port of ports) { | ||
| const r = await _tryPort(port, host); | ||
| if (r) return r; | ||
| } | ||
| } | ||
| function _fmtOnHost(hostname) { | ||
| return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host"; | ||
| } | ||
| const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(?<!-)$/; | ||
| function _validateHostname(hostname, _public, verbose) { | ||
| if (hostname && !HOSTNAME_RE.test(hostname)) { | ||
| const fallbackHost = _public ? "0.0.0.0" : "127.0.0.1"; | ||
| _log(verbose, `Invalid hostname: ${JSON.stringify(hostname)}. Using ${JSON.stringify(fallbackHost)} as fallback.`); | ||
| return fallbackHost; | ||
| } | ||
| return hostname; | ||
| } | ||
| async function getPort(_userOptions = {}) { | ||
| if (typeof _userOptions === "number" || typeof _userOptions === "string") _userOptions = { port: Number.parseInt(_userOptions + "") || 0 }; | ||
| const _port = Number(_userOptions.port ?? process.env.PORT); | ||
| const _userSpecifiedAnyPort = Boolean(_userOptions.port || _userOptions.ports?.length || _userOptions.portRange?.length); | ||
| const options = { | ||
| random: _port === 0, | ||
| ports: [], | ||
| portRange: [], | ||
| alternativePortRange: _userSpecifiedAnyPort ? [] : [3e3, 3100], | ||
| verbose: false, | ||
| ..._userOptions, | ||
| port: _port, | ||
| host: _validateHostname(_userOptions.host ?? process.env.HOST, _userOptions.public, _userOptions.verbose) | ||
| }; | ||
| if (options.random && !_userSpecifiedAnyPort) return getRandomPort(options.host); | ||
| const portsToCheck = [ | ||
| options.port, | ||
| ...options.ports, | ||
| ..._generateRange(...options.portRange) | ||
| ].filter((port) => { | ||
| if (!port) return false; | ||
| if (!isSafePort(port)) { | ||
| _log(options.verbose, `Ignoring unsafe port: ${port}`); | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| if (portsToCheck.length === 0) portsToCheck.push(3e3); | ||
| let availablePort = await _findPort(portsToCheck, options.host); | ||
| if (!availablePort && options.alternativePortRange.length > 0) { | ||
| availablePort = await _findPort(_generateRange(...options.alternativePortRange), options.host); | ||
| if (portsToCheck.length > 0) { | ||
| let message = `Unable to find an available port (tried ${portsToCheck.join("-")} ${_fmtOnHost(options.host)}).`; | ||
| if (availablePort) message += ` Using alternative port ${availablePort}.`; | ||
| _log(options.verbose, message); | ||
| } | ||
| } | ||
| if (!availablePort && _userOptions.random !== false) { | ||
| availablePort = await getRandomPort(options.host); | ||
| if (availablePort) _log(options.verbose, `Using random port ${availablePort}`); | ||
| } | ||
| if (!availablePort) { | ||
| const triedRanges = [ | ||
| options.port, | ||
| options.portRange.join("-"), | ||
| options.alternativePortRange.join("-") | ||
| ].filter(Boolean).join(", "); | ||
| throw new GetPortError(`Unable to find an available port ${_fmtOnHost(options.host)} (tried ${triedRanges})`); | ||
| } | ||
| return availablePort; | ||
| } | ||
| async function getRandomPort(host) { | ||
| const port = await checkPort(0, host); | ||
| if (port === false) throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`); | ||
| return port; | ||
| } | ||
| async function checkPort(port, host = process.env.HOST, verbose) { | ||
| if (!host) host = _getLocalHosts([void 0, "0.0.0.0"]); | ||
| if (!Array.isArray(host)) return _tryPort(port, host); | ||
| for (const _host of host) { | ||
| const _port = await _tryPort(port, _host); | ||
| if (_port === false) { | ||
| if (port < 1024 && verbose) _log(verbose, `Unable to listen to the privileged port ${port} ${_fmtOnHost(_host)}`); | ||
| return false; | ||
| } | ||
| if (port === 0 && _port !== 0) port = _port; | ||
| } | ||
| return port; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/dev.ts | ||
| const DEFAULT_PORT = 9999; | ||
| /** | ||
| * Resolve the listening port for {@link createDevServer}, honoring the | ||
| * definition's `cli.port` / `cli.portRange` / `cli.random` settings. | ||
| * Exposed separately so authors who run their own argv parsing can | ||
| * resolve a port up-front (to print it, log it, etc.) before starting | ||
| * the server. | ||
| */ | ||
| async function resolveDevServerPort(def, options = {}) { | ||
| const host = options.host ?? def.cli?.host ?? "localhost"; | ||
| const portOptions = { | ||
| port: options.defaultPort ?? def.cli?.port ?? DEFAULT_PORT, | ||
| host | ||
| }; | ||
| if (def.cli?.portRange) portOptions.portRange = def.cli.portRange; | ||
| if (def.cli?.random) portOptions.random = def.cli.random; | ||
| return getPort(portOptions); | ||
| } | ||
| /** | ||
| * Start a devframe dev server for a {@link DevframeDefinition} — | ||
| * h3 + WebSocket RPC + (optionally) the author's SPA mounted at the | ||
| * resolved base path. | ||
| * | ||
| * When `distDir` is omitted (and `def.cli?.distDir` is unset) the | ||
| * server runs in **bridge mode**: only `__connection.json` and the WS | ||
| * endpoint are mounted, with no SPA mount. The SPA is expected to be | ||
| * hosted elsewhere (e.g. by a parent Vite/Nuxt dev server) — see | ||
| * `viteDevBridge({ devMiddleware })`. | ||
| * | ||
| * Returns the underlying {@link StartedServer} handle so callers can | ||
| * close it gracefully (SIGINT, hot-reload, test teardown). | ||
| * | ||
| * Use this directly when integrating devframe into an existing CLI | ||
| * framework (commander, yargs, hand-rolled CAC). For the all-in-one | ||
| * `dev` / `build` / `mcp` shell, reach for {@link createCac} instead. | ||
| */ | ||
| async function createDevServer(def, options = {}) { | ||
| const distDir = options.distDir ?? def.cli?.distDir; | ||
| const host = options.host ?? def.cli?.host ?? "localhost"; | ||
| const port = options.port ?? await resolveDevServerPort(def, { host }); | ||
| const flags = options.flags ?? {}; | ||
| const basePath = options.basePath ? normalizeBasePath(options.basePath) : resolveBasePath(def, "standalone"); | ||
| const app = options.app ?? new H3(); | ||
| const h3Host = createH3DevframeHost({ | ||
| origin: normalizeHttpServerUrl(host, port), | ||
| appName: def.id, | ||
| mount: (base, dir) => { | ||
| mountStaticHandler(app, base, dir); | ||
| } | ||
| }); | ||
| const ctx = await createHostContext({ | ||
| cwd: process$1.cwd(), | ||
| mode: "dev", | ||
| host: h3Host | ||
| }); | ||
| const setupInfo = { flags }; | ||
| await def.setup(ctx, setupInfo); | ||
| const mcpConfig = resolveMcpConfig(options.mcp ?? def.cli?.mcp); | ||
| let mcpDispose; | ||
| let mcpMeta; | ||
| if (mcpConfig) { | ||
| const mcpRoute = withoutLeadingSlash(mcpConfig.path ?? "__mcp"); | ||
| const mcpPath = joinURL(basePath, mcpRoute); | ||
| let mountMcpHttp; | ||
| try { | ||
| ({mountMcpHttp} = await import("./http-B2P55ZXg.mjs")); | ||
| } catch (error) { | ||
| const reason = error instanceof Error ? error.message : String(error); | ||
| throw diagnostics.DF0017({ | ||
| transport: "http", | ||
| reason, | ||
| cause: error | ||
| }); | ||
| } | ||
| mcpDispose = mountMcpHttp(app, ctx, mcpPath, { | ||
| serverName: `${def.id} (devframe)`, | ||
| serverVersion: def.version ?? "0.0.0", | ||
| exposeSharedState: true, | ||
| allowedOrigins: mcpConfig.allowedOrigins | ||
| }).dispose; | ||
| mcpMeta = { path: mcpRoute }; | ||
| } | ||
| const { bindPath, wsPort, meta } = resolveWsConnection(def, options, basePath); | ||
| const connectionMetaPath = joinURL(basePath, DEVFRAME_CONNECTION_META_FILENAME); | ||
| app.use(connectionMetaPath, () => ({ | ||
| backend: "websocket", | ||
| websocket: meta, | ||
| ...mcpMeta ? { mcp: mcpMeta } : {} | ||
| })); | ||
| if (distDir) mountStaticHandler(app, basePath, resolve(distDir)); | ||
| const authOption = flags.auth === false ? false : options.auth !== void 0 ? options.auth : def.cli?.auth; | ||
| let authHandler; | ||
| let resolvedAuth; | ||
| if (authOption === false) resolvedAuth = false; | ||
| else if (typeof authOption === "object") { | ||
| authHandler = authOption; | ||
| resolvedAuth = authOption; | ||
| } else { | ||
| authHandler = createInteractiveAuth(ctx); | ||
| resolvedAuth = authHandler; | ||
| } | ||
| const started = await startHttpAndWs({ | ||
| context: ctx, | ||
| host, | ||
| port, | ||
| app, | ||
| path: bindPath, | ||
| wsPort, | ||
| auth: resolvedAuth, | ||
| onReady: async (info) => { | ||
| authHandler?.printBanner(); | ||
| await options.onReady?.(info); | ||
| await maybeOpenBrowser(def, flags, `${info.origin}${basePath}`, options.openBrowser, authHandler); | ||
| } | ||
| }); | ||
| if (mcpDispose) { | ||
| const closeServer = started.close; | ||
| started.close = async () => { | ||
| await mcpDispose(); | ||
| await closeServer(); | ||
| }; | ||
| } | ||
| return started; | ||
| } | ||
| /** | ||
| * Normalize the `cli.mcp` / `mcp` option (`boolean | McpRouteOptions`) into | ||
| * concrete options, or `undefined` when the MCP route is disabled. | ||
| */ | ||
| function resolveMcpConfig(mcp) { | ||
| if (!mcp) return void 0; | ||
| return mcp === true ? {} : mcp; | ||
| } | ||
| /** | ||
| * Resolve the `mcp` entry a `__connection.json` should advertise for a dev | ||
| * server started with the given `mcp` option (falling back to `def.cli?.mcp`, | ||
| * exactly like {@link createDevServer}), or `undefined` when the route is | ||
| * disabled. | ||
| * | ||
| * Hosted bridges that hand-roll their connection meta (`viteDevBridge`, | ||
| * `@devframes/next`'s handler) pass the side-car `port`: the advertised path | ||
| * becomes absolute (the side-car mounts at `/`) and the client dials | ||
| * `<page-host>:<port><path>`. Without `port` the path stays relative, resolved | ||
| * against `__connection.json`'s own location (the same-server default). | ||
| * | ||
| * @experimental | ||
| */ | ||
| function resolveMcpConnectionMeta(def, mcp, port) { | ||
| const config = resolveMcpConfig(mcp ?? def.cli?.mcp); | ||
| if (!config) return void 0; | ||
| const route = withoutLeadingSlash(config.path ?? "__mcp"); | ||
| return port != null ? { | ||
| path: withLeadingSlash(route), | ||
| port | ||
| } : { path: route }; | ||
| } | ||
| /** | ||
| * Resolve the three WS connection scenarios from the definition / call-site | ||
| * config into a concrete server bind path, optional dedicated port, and the | ||
| * `__connection.json` descriptor the browser resolves. | ||
| */ | ||
| function resolveWsConnection(def, options, basePath) { | ||
| const ws = options.ws ?? def.cli?.ws ?? {}; | ||
| const route = withoutLeadingSlash(ws.route ?? "__devframe_ws"); | ||
| if (ws.url) return { | ||
| bindPath: joinURL(basePath, route), | ||
| wsPort: void 0, | ||
| meta: ws.url | ||
| }; | ||
| if (ws.port != null) return { | ||
| bindPath: withLeadingSlash(route), | ||
| wsPort: ws.port, | ||
| meta: { | ||
| port: ws.port, | ||
| path: route | ||
| } | ||
| }; | ||
| return { | ||
| bindPath: joinURL(basePath, route), | ||
| wsPort: void 0, | ||
| meta: { path: route } | ||
| }; | ||
| } | ||
| async function maybeOpenBrowser(def, flags, origin, override, authHandler) { | ||
| const flagsOpen = flags.open; | ||
| const cliOpen = def.cli?.open; | ||
| const resolved = override ?? flagsOpen ?? cliOpen; | ||
| if (resolved === void 0 || resolved === false) return; | ||
| const target = typeof resolved === "string" ? withBase(resolved, origin) : origin; | ||
| const authorizedTarget = authHandler?.buildOpenUrl?.(target) ?? target; | ||
| try { | ||
| await open(authorizedTarget); | ||
| } catch {} | ||
| } | ||
| //#endregion | ||
| export { resolveDevServerPort as n, resolveMcpConnectionMeta as r, createDevServer as t }; |
Sorry, the diff of this file is too big to display
| import { isAllowedOrigin } from "./rpc/transports/ws-server.mjs"; | ||
| import { t as buildMcpServerFromContext } from "./build-server-cANnMwg0.mjs"; | ||
| import { randomUUID } from "node:crypto"; | ||
| import { defineHandler } from "h3"; | ||
| import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"; | ||
| import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; | ||
| //#region src/adapters/mcp/http.ts | ||
| /** | ||
| * Mount an MCP Streamable-HTTP endpoint on an h3 app at `path`. | ||
| * | ||
| * Each MCP session gets its own {@link WebStandardStreamableHTTPServerTransport} | ||
| * and MCP server (built from the shared, live `ctx` via | ||
| * `buildMcpServerFromContext`), correlated by the `Mcp-Session-Id` header: | ||
| * an `initialize` POST spins up a session; later requests route to it; a | ||
| * `DELETE` (or client disconnect) tears it down. | ||
| * | ||
| * The transport is web-standard — its `handleRequest` takes the h3 event's | ||
| * web `Request` and returns a web `Response` (an SSE `ReadableStream` body | ||
| * for the server→client stream). We copy that response onto `event.res` and | ||
| * return its body rather than returning the `Response` object directly, so a | ||
| * legitimate MCP 404 (unknown session) isn't swallowed by h3's | ||
| * "Response-with-404 falls through to the next handler" rule (which would | ||
| * otherwise hand the request to the SPA static catch-all). | ||
| * | ||
| * @experimental | ||
| */ | ||
| function mountMcpHttp(app, ctx, path, options) { | ||
| const sessions = /* @__PURE__ */ new Map(); | ||
| const allowedOrigins = options.allowedOrigins; | ||
| function drop(sessionId) { | ||
| const session = sessions.get(sessionId); | ||
| if (!session) return; | ||
| sessions.delete(sessionId); | ||
| session.dispose(); | ||
| } | ||
| async function createSession() { | ||
| let session; | ||
| const transport = new WebStandardStreamableHTTPServerTransport({ | ||
| sessionIdGenerator: () => randomUUID(), | ||
| onsessioninitialized: (id) => { | ||
| sessions.set(id, session); | ||
| }, | ||
| onsessionclosed: (id) => { | ||
| drop(id); | ||
| } | ||
| }); | ||
| const { server, dispose } = buildMcpServerFromContext(ctx, { | ||
| serverName: options.serverName, | ||
| serverVersion: options.serverVersion, | ||
| exposeSharedState: options.exposeSharedState | ||
| }); | ||
| session = { | ||
| transport, | ||
| dispose: async () => { | ||
| dispose(); | ||
| await server.close(); | ||
| } | ||
| }; | ||
| transport.onclose = () => { | ||
| if (transport.sessionId) drop(transport.sessionId); | ||
| }; | ||
| await server.connect(transport); | ||
| return session; | ||
| } | ||
| app.use(path, defineHandler(async (event) => { | ||
| const req = event.req; | ||
| const origin = req.headers.get("origin") ?? void 0; | ||
| if (allowedOrigins !== false && !isAllowedOrigin(origin, allowedOrigins ?? [])) { | ||
| event.res.status = 403; | ||
| return "Forbidden: origin not allowed"; | ||
| } | ||
| const sessionId = req.headers.get("mcp-session-id") ?? void 0; | ||
| let session = sessionId ? sessions.get(sessionId) : void 0; | ||
| if (!session && req.method === "POST") { | ||
| let body; | ||
| try { | ||
| body = await req.json(); | ||
| } catch { | ||
| body = void 0; | ||
| } | ||
| if (!sessionId && isInitializeRequest(body)) session = await createSession(); | ||
| else { | ||
| event.res.status = sessionId ? 404 : 400; | ||
| return sessionId ? "Not Found: unknown MCP session" : "Bad Request: no valid session ID and not an initialize request"; | ||
| } | ||
| return respond(event, await session.transport.handleRequest(req, { parsedBody: body })); | ||
| } | ||
| if (!session) { | ||
| event.res.status = sessionId ? 404 : 400; | ||
| return sessionId ? "Not Found: unknown MCP session" : "Bad Request: missing MCP session ID"; | ||
| } | ||
| return respond(event, await session.transport.handleRequest(req)); | ||
| })); | ||
| return { dispose: async () => { | ||
| const live = [...sessions.values()]; | ||
| sessions.clear(); | ||
| await Promise.all(live.map((session) => session.dispose())); | ||
| } }; | ||
| } | ||
| /** | ||
| * Copy a web `Response` from the MCP transport onto the h3 event's response | ||
| * and return its body. Returning the body (a `ReadableStream` or `null`) | ||
| * rather than the `Response` object avoids h3's 404-fall-through behavior. | ||
| */ | ||
| function respond(event, response) { | ||
| event.res.status = response.status; | ||
| event.res.statusText = response.statusText; | ||
| response.headers.forEach((value, key) => { | ||
| event.res.headers.set(key, value); | ||
| }); | ||
| return response.body ?? ""; | ||
| } | ||
| //#endregion | ||
| export { mountMcpHttp }; |
| import { W as DevframeNodeRpcSession, b as DevframeNodeContext, ht as SharedState } from "./devframe-BADsX91-.mjs"; | ||
| import { n as InternalAnonymousAuthStorage } from "./context-C_bqRR0i.mjs"; | ||
| //#region src/node/auth/revoke.d.ts | ||
| /** | ||
| * Flip `isTrusted` to false on any live WS clients connected with `token` | ||
| * and broadcast the `auth:revoked` event so they can react. | ||
| * | ||
| * Shared between persisted-auth revocation and remote-dock token revocation. | ||
| */ | ||
| declare function revokeActiveConnectionsForToken(context: DevframeNodeContext, token: string): Promise<void>; | ||
| /** | ||
| * Revoke an auth token: remove from storage and notify all connected clients | ||
| * using this token that they are no longer trusted. | ||
| */ | ||
| declare function revokeAuthToken(context: DevframeNodeContext, storage: SharedState<InternalAnonymousAuthStorage>, token: string): Promise<void>; | ||
| //#endregion | ||
| //#region src/node/auth/state.d.ts | ||
| /** | ||
| * The current one-time authentication code. Display this to the user (e.g. in | ||
| * the dev-server terminal) so they can type it into the browser to authenticate. | ||
| */ | ||
| declare function getTempAuthCode(): string; | ||
| /** | ||
| * Rotate the authentication code, resetting its expiry window and failed-attempt | ||
| * counter. Call this when a new authentication flow begins (e.g. when an | ||
| * untrusted client starts authenticating) so the displayed code is freshly | ||
| * valid for its full TTL. | ||
| */ | ||
| declare function refreshTempAuthCode(): string; | ||
| /** | ||
| * Build a "magic link" authentication URL that embeds a one-time code (OTP) as | ||
| * a query parameter. Opening it authenticates the client without typing — print | ||
| * it on startup (devframe stays headless, so the host prints its own banner). | ||
| * Defaults to the current code; the link is subject to the same TTL. | ||
| */ | ||
| declare function buildOtpAuthUrl(baseUrl: string, code?: string): string; | ||
| /** | ||
| * Re-authenticate a connection that presents a previously-issued bearer token. | ||
| * Returns `true` and marks the session trusted when the token is known. | ||
| * | ||
| * Used by the `anonymous:devframe:auth` handler so a client that already | ||
| * authenticated (token persisted in the browser) is trusted on reconnect | ||
| * without entering the code again. | ||
| */ | ||
| declare function verifyAuthToken(token: string, session: DevframeNodeRpcSession, storage: SharedState<InternalAnonymousAuthStorage>): boolean; | ||
| /** | ||
| * Exchange a one-time authentication code for a fresh, node-issued bearer token. | ||
| * | ||
| * On success this mints a high-entropy token, records it in the trusted store, | ||
| * marks the calling session trusted, rotates the code, and returns the token | ||
| * for the client to persist. Returns `null` on any failure. | ||
| * | ||
| * Because the code is short and human-typed, verification is hardened against | ||
| * brute force: it enforces a time-to-live, compares in constant time, and | ||
| * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an | ||
| * attacker cannot keep guessing against the same code. | ||
| */ | ||
| declare function exchangeTempAuthCode(code: string, session: DevframeNodeRpcSession, info: { | ||
| ua: string; | ||
| origin: string; | ||
| }, storage: SharedState<InternalAnonymousAuthStorage>): string | null; | ||
| //#endregion | ||
| export { verifyAuthToken as a, refreshTempAuthCode as i, exchangeTempAuthCode as n, revokeActiveConnectionsForToken as o, getTempAuthCode as r, revokeAuthToken as s, buildOtpAuthUrl as t }; |
| import "../devframe-BADsX91-.mjs"; | ||
| import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-CrzNxXKq.mjs"; | ||
| import "../index-DgsLFhZg.mjs"; | ||
| import * as v from "valibot"; | ||
| //#region src/recipes/common-rpc-functions.d.ts | ||
| /** | ||
| * Editor commands that `launch-editor` (the library behind | ||
| * `devframe/utils/launch-editor`) recognizes with a tailored | ||
| * `file:line:column` invocation. `openInEditor`'s optional second argument | ||
| * is restricted to this union, so the RPC surface can't be used to spawn an | ||
| * arbitrary command. | ||
| */ | ||
| type KnownEditor = 'atom' | 'subl' | 'sublime' | 'sublime_text' | 'wstorm' | 'charm' | 'zed' | 'notepad++' | 'vim' | 'mvim' | 'joe' | 'gvim' | 'emacs' | 'emacsclient' | 'rmate' | 'mate' | 'code' | 'code-insiders' | 'codium' | 'vscodium' | 'trae' | 'antigravity' | 'cursor' | 'appcode' | 'clion' | 'idea' | 'phpstorm' | 'pycharm' | 'rubymine' | 'webstorm' | 'goland' | 'rider'; | ||
| /** Runtime list of every {@link KnownEditor}, in the order `v.picklist` reports them. */ | ||
| declare const KNOWN_EDITORS: KnownEditor[]; | ||
| /** | ||
| * Prebuilt RPC action that opens a file in the user's configured editor. | ||
| * | ||
| * Registered name: `devframe:open-in-editor`. | ||
| * | ||
| * The optional second argument picks the editor command explicitly (must be | ||
| * one of {@link KNOWN_EDITORS}); otherwise it's auto-detected per | ||
| * `devframe/utils/launch-editor`. | ||
| * | ||
| * ```ts | ||
| * import { openInEditor } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * defineDevframe({ | ||
| * id: 'my-tool', | ||
| * name: 'My Tool', | ||
| * setup(ctx) { | ||
| * ctx.rpc.register(openInEditor) | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| declare const openInEditor: { | ||
| name: "devframe:open-in-editor"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>, v.OptionalSchema<v.PicklistSchema<KnownEditor[], undefined>, undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>>) | undefined; | ||
| handler?: ((args_0: string, args_1: KnownEditor | undefined) => void) | undefined; | ||
| dump?: RpcDump<[string, KnownEditor | undefined], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>> | undefined; | ||
| }; | ||
| /** | ||
| * Prebuilt RPC action that reveals a path in the OS file explorer. | ||
| * | ||
| * Registered name: `devframe:open-in-finder`. | ||
| * | ||
| * ```ts | ||
| * import { openInFinder } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * ctx.rpc.register(openInFinder) | ||
| * ``` | ||
| */ | ||
| declare const openInFinder: { | ||
| name: "devframe:open-in-finder"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }; | ||
| /** | ||
| * Convenience array bundling both helpers so callers can register them | ||
| * in a single `forEach`. | ||
| * | ||
| * ```ts | ||
| * import { commonRpcFunctions } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * commonRpcFunctions.forEach(fn => ctx.rpc.register(fn)) | ||
| * ``` | ||
| */ | ||
| declare const commonRpcFunctions: readonly [{ | ||
| name: "devframe:open-in-editor"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>, v.OptionalSchema<v.PicklistSchema<KnownEditor[], undefined>, undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>>) | undefined; | ||
| handler?: ((args_0: string, args_1: KnownEditor | undefined) => void) | undefined; | ||
| dump?: RpcDump<[string, KnownEditor | undefined], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string, KnownEditor | undefined], void>> | undefined; | ||
| }, { | ||
| name: "devframe:open-in-finder"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }]; | ||
| //#endregion | ||
| export { KNOWN_EDITORS, KnownEditor, commonRpcFunctions, openInEditor, openInFinder }; |
| import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs"; | ||
| import * as v from "valibot"; | ||
| //#region src/recipes/common-rpc-functions.ts | ||
| /** Runtime list of every {@link KnownEditor}, in the order `v.picklist` reports them. */ | ||
| const KNOWN_EDITORS = [ | ||
| "atom", | ||
| "subl", | ||
| "sublime", | ||
| "sublime_text", | ||
| "wstorm", | ||
| "charm", | ||
| "zed", | ||
| "notepad++", | ||
| "vim", | ||
| "mvim", | ||
| "joe", | ||
| "gvim", | ||
| "emacs", | ||
| "emacsclient", | ||
| "rmate", | ||
| "mate", | ||
| "code", | ||
| "code-insiders", | ||
| "codium", | ||
| "vscodium", | ||
| "trae", | ||
| "antigravity", | ||
| "cursor", | ||
| "appcode", | ||
| "clion", | ||
| "idea", | ||
| "phpstorm", | ||
| "pycharm", | ||
| "rubymine", | ||
| "webstorm", | ||
| "goland", | ||
| "rider" | ||
| ]; | ||
| /** | ||
| * Prebuilt RPC action that opens a file in the user's configured editor. | ||
| * | ||
| * Registered name: `devframe:open-in-editor`. | ||
| * | ||
| * The optional second argument picks the editor command explicitly (must be | ||
| * one of {@link KNOWN_EDITORS}); otherwise it's auto-detected per | ||
| * `devframe/utils/launch-editor`. | ||
| * | ||
| * ```ts | ||
| * import { openInEditor } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * defineDevframe({ | ||
| * id: 'my-tool', | ||
| * name: 'My Tool', | ||
| * setup(ctx) { | ||
| * ctx.rpc.register(openInEditor) | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| const openInEditor = defineRpcFunction({ | ||
| name: "devframe:open-in-editor", | ||
| type: "action", | ||
| jsonSerializable: true, | ||
| args: [v.string(), v.optional(v.picklist(KNOWN_EDITORS))], | ||
| returns: v.void(), | ||
| async handler(filename, editor) { | ||
| const { launchEditor } = await import("../utils/launch-editor.mjs"); | ||
| launchEditor(filename, editor); | ||
| } | ||
| }); | ||
| /** | ||
| * Prebuilt RPC action that reveals a path in the OS file explorer. | ||
| * | ||
| * Registered name: `devframe:open-in-finder`. | ||
| * | ||
| * ```ts | ||
| * import { openInFinder } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * ctx.rpc.register(openInFinder) | ||
| * ``` | ||
| */ | ||
| const openInFinder = defineRpcFunction({ | ||
| name: "devframe:open-in-finder", | ||
| type: "action", | ||
| jsonSerializable: true, | ||
| args: [v.string()], | ||
| returns: v.void(), | ||
| async handler(path) { | ||
| const { open } = await import("../utils/open.mjs"); | ||
| await open(path); | ||
| } | ||
| }); | ||
| /** | ||
| * Convenience array bundling both helpers so callers can register them | ||
| * in a single `forEach`. | ||
| * | ||
| * ```ts | ||
| * import { commonRpcFunctions } from 'devframe/recipes/common-rpc-functions' | ||
| * | ||
| * commonRpcFunctions.forEach(fn => ctx.rpc.register(fn)) | ||
| * ``` | ||
| */ | ||
| const commonRpcFunctions = [openInEditor, openInFinder]; | ||
| //#endregion | ||
| export { KNOWN_EDITORS, commonRpcFunctions, openInEditor, openInFinder }; |
| import { $ as DevframeRpcServerFunctions, Q as DevframeRpcClientFunctions, W as DevframeNodeRpcSession, _ as ConnectionMeta, b as DevframeNodeContext, p as DevframeAuthHandler } from "./devframe-BADsX91-.mjs"; | ||
| import "./index-Brcd2V4t.mjs"; | ||
| import { Peer } from "crossws"; | ||
| import { BirpcGroup, EventOptions } from "birpc"; | ||
| import { NodeAdapter } from "crossws/adapters/node"; | ||
| import { Server } from "node:http"; | ||
| import { H3 } from "h3"; | ||
| //#region src/node/server.d.ts | ||
| interface StartHttpAndWsOptions { | ||
| context: DevframeNodeContext; | ||
| host?: string; | ||
| port: number; | ||
| /** | ||
| * Optional h3 app to mount on. When omitted a fresh one is created; | ||
| * when provided, callers can add their own routes (static handlers, | ||
| * auth middleware, etc.) first. | ||
| */ | ||
| app?: H3; | ||
| /** | ||
| * Bind the WS endpoint to a single upgrade route (e.g. `/__devframe_ws`) instead of | ||
| * claiming every upgrade on the port. This lets the socket share a server | ||
| * with other upgrade handlers (Vite HMR, a host framework's own sockets) | ||
| * and is what the SPA's `__connection.json` points at. When omitted, the WS | ||
| * server handles every upgrade on the port (legacy behaviour). | ||
| */ | ||
| path?: string; | ||
| /** | ||
| * Bind the WS endpoint on its own port instead of sharing the HTTP server's. | ||
| * The HTTP/SPA server still listens on `port`; the socket gets a dedicated | ||
| * `ws` server on `wsPort` (same `host`). Use this for the "different port" | ||
| * connection scenario. Ignored when a `server` is supplied. | ||
| */ | ||
| wsPort?: number; | ||
| /** | ||
| * Mount the WS endpoint onto an existing HTTP server, sharing its port, | ||
| * rather than creating and listening on a fresh one. Use this to embed | ||
| * devframe's RPC socket inside a host server (e.g. a Vite dev server) — pair | ||
| * it with `path` so it coexists with the host's routes. The caller owns the | ||
| * server's lifecycle: {@link StartedServer.close} detaches devframe's upgrade | ||
| * listener but leaves the host server running. When set, `host`/`port` are | ||
| * only used to report the resolved origin. | ||
| */ | ||
| server?: Server; | ||
| /** | ||
| * Authentication for the server: | ||
| * | ||
| * - `true` (default) — no gate; every registered method is callable | ||
| * regardless of trust (today's behavior, unchanged). | ||
| * - `false` — the RPC server is started without a trust handshake. | ||
| * Intended for single-user localhost tools where an auth round-trip | ||
| * would only get in the way. A noop `anonymous:devframe:auth` handler | ||
| * is registered so the browser client's unconditional handshake call | ||
| * succeeds and auto-trusts. | ||
| * - A {@link DevframeAuthHandler} (e.g. from | ||
| * `devframe/recipes/interactive-auth`'s `createInteractiveAuth`) — | ||
| * registers its `rpcFunctions`, wires its `authorize` as the resolver | ||
| * gate, and wires its `onConnect` on every new peer. This is the | ||
| * fully-authenticated server: an untrusted caller can only reach | ||
| * `anonymous:`-prefixed methods (see `isAnonymousRpcMethod`). | ||
| */ | ||
| auth?: boolean | DevframeAuthHandler; | ||
| /** | ||
| * Lower-level escape hatch: gate individual RPC calls by method name and | ||
| * session without a full {@link DevframeAuthHandler}. Ignored when `auth` | ||
| * is a handler object (its own `authorize` is used); combine with `auth: | ||
| * true` to layer a custom policy on top of an otherwise ungated server. | ||
| */ | ||
| authorize?: (methodName: string, session: DevframeNodeRpcSession) => boolean; | ||
| /** | ||
| * Called once per new WS connection, right after its session is created | ||
| * (before any RPC call is dispatched). Runs after the auth handler's own | ||
| * `onConnect` (when `auth` is a {@link DevframeAuthHandler}), so it can | ||
| * observe — but not override — the connect-time trust decision. | ||
| */ | ||
| onPeerConnect?: (peer: Peer, session: DevframeNodeRpcSession) => void; | ||
| /** | ||
| * Forwarded verbatim to the internal `createRpcServer`'s birpc | ||
| * `rpcOptions`, alongside the resolver `startHttpAndWs` installs for | ||
| * auth/session wiring. Use this so a host that owns its own structured | ||
| * diagnostics (e.g. a coded error reporter) keeps seeing RPC failures | ||
| * instead of them being silently absorbed by delegating to | ||
| * `startHttpAndWs`. Returning `true` from either callback suppresses | ||
| * birpc's own error response to the caller — see birpc's | ||
| * `EventOptions` for the full contract. | ||
| */ | ||
| rpcOptions?: Pick<EventOptions<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>, 'onFunctionError' | 'onGeneralError'>; | ||
| /** | ||
| * Extra origins to accept on the WS upgrade beyond the loopback default | ||
| * (`localhost`/`127.0.0.1`/`::1` and any `Origin`-less request from a | ||
| * native client). Add your LAN/tunnel origin here when reaching the tool | ||
| * from another host. Pass `false` to disable origin checking entirely | ||
| * (not recommended). Default: loopback-only. | ||
| */ | ||
| allowedOrigins?: readonly string[] | false; | ||
| /** | ||
| * Called once the WS server is bound so callers can mount static | ||
| * handlers whose origin depends on the resolved port, or print their | ||
| * own startup banner. Devframe does not print one itself. | ||
| */ | ||
| onReady?: (info: { | ||
| origin: string; | ||
| port: number; | ||
| app: H3; | ||
| }) => void | Promise<void>; | ||
| } | ||
| interface StartedServer { | ||
| /** Listening origin, e.g. `http://localhost:9999`. */ | ||
| origin: string; | ||
| port: number; | ||
| app: H3; | ||
| /** The crossws node adapter driving the RPC socket (connected peers, pub/sub). */ | ||
| ws: NodeAdapter; | ||
| rpcGroup: BirpcGroup<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>; | ||
| /** | ||
| * The {@link ConnectionMeta} descriptor for this server — the same shape | ||
| * a `__connection.json` route should serve so a devframe client's | ||
| * `resolveWsUrl` can dial back in. Reflects the `path` / `wsPort` this | ||
| * server was started with and the `jsonSerializable` methods currently | ||
| * registered on `context.rpc`. | ||
| */ | ||
| connectionMeta: () => ConnectionMeta; | ||
| close: () => Promise<void>; | ||
| } | ||
| /** | ||
| * Compose an h3 + WebSocket server for a devframe context. The RPC | ||
| * group is bound to `context.rpc.functions`; the WS endpoint lives on | ||
| * the same port as the HTTP server. | ||
| */ | ||
| declare function startHttpAndWs(options: StartHttpAndWsOptions): Promise<StartedServer>; | ||
| //#endregion | ||
| export { StartedServer as n, startHttpAndWs as r, StartHttpAndWsOptions as t }; |
| //#region ../../node_modules/.pnpm/structured-clone-es@2.0.1/node_modules/structured-clone-es/dist/index.mjs | ||
| const env = typeof self === "object" ? self : globalThis; | ||
| const SAFE_ERROR_NAMES = /* @__PURE__ */ new Set([ | ||
| "Error", | ||
| "EvalError", | ||
| "RangeError", | ||
| "ReferenceError", | ||
| "SyntaxError", | ||
| "TypeError", | ||
| "URIError", | ||
| "AggregateError" | ||
| ]); | ||
| const SAFE_CONSTRUCTOR_NAMES = /* @__PURE__ */ new Set([ | ||
| "Boolean", | ||
| "Number", | ||
| "String", | ||
| "Int8Array", | ||
| "Uint8Array", | ||
| "Uint8ClampedArray", | ||
| "Int16Array", | ||
| "Uint16Array", | ||
| "Int32Array", | ||
| "Uint32Array", | ||
| "Float16Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "BigInt64Array", | ||
| "BigUint64Array" | ||
| ]); | ||
| function deserializer($, _) { | ||
| const as = (out, index) => { | ||
| $.set(index, out); | ||
| return out; | ||
| }; | ||
| const unpair = (index) => { | ||
| if ($.has(index)) return $.get(index); | ||
| const [type, value] = _[index]; | ||
| switch (type) { | ||
| case 0: | ||
| case -1: return as(value, index); | ||
| case 1: { | ||
| const arr = as([], index); | ||
| for (const index of value) arr.push(unpair(index)); | ||
| return arr; | ||
| } | ||
| case 2: { | ||
| const object = as({}, index); | ||
| for (const [key, index] of value) object[unpair(key)] = unpair(index); | ||
| return object; | ||
| } | ||
| case 3: return as(new Date(value), index); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as(new RegExp(source, flags), index); | ||
| } | ||
| case 5: { | ||
| const map = as(/* @__PURE__ */ new Map(), index); | ||
| for (const [key, index] of value) map.set(unpair(key), unpair(index)); | ||
| return map; | ||
| } | ||
| case 6: { | ||
| const set = as(/* @__PURE__ */ new Set(), index); | ||
| for (const index of value) set.add(unpair(index)); | ||
| return set; | ||
| } | ||
| case 7: { | ||
| const { name, message } = value; | ||
| const Ctor = SAFE_ERROR_NAMES.has(name) ? env[name] : void 0; | ||
| return as(new (Ctor ?? env.Error)(message), index); | ||
| } | ||
| case 8: return as(BigInt(value), index); | ||
| case "BigInt": return as(Object(BigInt(value)), index); | ||
| case "ArrayBuffer": return as(new Uint8Array(value).buffer, value); | ||
| case "DataView": { | ||
| const { buffer } = new Uint8Array(value); | ||
| return as(new DataView(buffer), value); | ||
| } | ||
| } | ||
| if (typeof type === "string" && SAFE_CONSTRUCTOR_NAMES.has(type)) return as(new env[type](value), index); | ||
| throw new TypeError(`unable to deserialize unsafe or unknown type: ${String(type)}`); | ||
| }; | ||
| return unpair; | ||
| } | ||
| /** | ||
| * Returns a deserialized value from a serialized array of Records. | ||
| * @param serialized a previously serialized value. | ||
| */ | ||
| function deserialize(serialized) { | ||
| return deserializer(/* @__PURE__ */ new Map(), serialized)(0); | ||
| } | ||
| const EMPTY = ""; | ||
| const { toString } = {}; | ||
| const { keys } = Object; | ||
| function typeOf(value) { | ||
| const type = typeof value; | ||
| if (type !== "object" || !value) return [0, type]; | ||
| const asString = toString.call(value).slice(8, -1); | ||
| switch (asString) { | ||
| case "Array": return [1, EMPTY]; | ||
| case "Object": return [2, EMPTY]; | ||
| case "Date": return [3, EMPTY]; | ||
| case "RegExp": return [4, EMPTY]; | ||
| case "Map": return [5, EMPTY]; | ||
| case "Set": return [6, EMPTY]; | ||
| case "DataView": return [1, asString]; | ||
| } | ||
| if (asString.includes("Array")) return [1, asString]; | ||
| if (asString.includes("Error")) return [7, asString]; | ||
| return [2, asString]; | ||
| } | ||
| function shouldSkip([TYPE, type]) { | ||
| return TYPE === 0 && (type === "function" || type === "symbol"); | ||
| } | ||
| function serializer(strict, json, $, _) { | ||
| const as = (out, value) => { | ||
| const index = _.push(out) - 1; | ||
| $.set(value, index); | ||
| return index; | ||
| }; | ||
| const pair = (value) => { | ||
| if ($.has(value)) return $.get(value); | ||
| let [TYPE, type] = typeOf(value); | ||
| switch (TYPE) { | ||
| case 0: { | ||
| let entry = value; | ||
| switch (type) { | ||
| case "bigint": | ||
| TYPE = 8; | ||
| entry = value.toString(); | ||
| break; | ||
| case "function": | ||
| case "symbol": | ||
| if (strict) throw new TypeError(`unable to serialize ${type}`); | ||
| entry = null; | ||
| break; | ||
| case "undefined": return as([-1], value); | ||
| } | ||
| return as([TYPE, entry], value); | ||
| } | ||
| case 1: { | ||
| if (type) { | ||
| let spread = value; | ||
| if (type === "DataView") spread = new Uint8Array(value.buffer); | ||
| else if (type === "ArrayBuffer") spread = new Uint8Array(value); | ||
| return as([type, [...spread]], value); | ||
| } | ||
| const arr = []; | ||
| const index = as([TYPE, arr], value); | ||
| for (const entry of value) arr.push(pair(entry)); | ||
| return index; | ||
| } | ||
| case 2: { | ||
| if (type) switch (type) { | ||
| case "BigInt": return as([type, value.toString()], value); | ||
| case "Boolean": | ||
| case "Number": | ||
| case "String": return as([type, value.valueOf()], value); | ||
| } | ||
| if (json && "toJSON" in value) return pair(value.toJSON()); | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const key of keys(value)) if (strict || !shouldSkip(typeOf(value[key]))) entries.push([pair(key), pair(value[key])]); | ||
| return index; | ||
| } | ||
| case 3: return as([TYPE, value.toISOString()], value); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as([TYPE, { | ||
| source, | ||
| flags | ||
| }], value); | ||
| } | ||
| case 5: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const [key, entry] of value) if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry)))) entries.push([pair(key), pair(entry)]); | ||
| return index; | ||
| } | ||
| case 6: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const entry of value) if (strict || !shouldSkip(typeOf(entry))) entries.push(pair(entry)); | ||
| return index; | ||
| } | ||
| } | ||
| const { message } = value; | ||
| return as([TYPE, { | ||
| name: type, | ||
| message | ||
| }], value); | ||
| }; | ||
| return pair; | ||
| } | ||
| /** | ||
| * Returns an array of serialized Records. | ||
| */ | ||
| function serialize(value, options = {}) { | ||
| const _ = []; | ||
| serializer(!(options.json || options.lossy), !!options.json, /* @__PURE__ */ new Map(), _)(value); | ||
| return _; | ||
| } | ||
| const { parse: $parse, stringify: $stringify } = JSON; | ||
| const options = { | ||
| json: true, | ||
| lossy: true | ||
| }; | ||
| /** | ||
| * Revive a previously stringified structured clone. | ||
| * @param str previously stringified data as string. | ||
| */ | ||
| function parse(str) { | ||
| return deserialize($parse(str)); | ||
| } | ||
| /** | ||
| * Represent a structured clone value as string. | ||
| * @param any some clone-able value to stringify. | ||
| */ | ||
| function stringify(any) { | ||
| return $stringify(serialize(any, options)); | ||
| } | ||
| //#endregion | ||
| //#region src/utils/structured-clone.ts | ||
| /** | ||
| * Serialize a structured-cloneable value to a single string. Equivalent | ||
| * to `JSON.stringify(structuredCloneSerialize(value))`. | ||
| */ | ||
| function structuredCloneStringify(value) { | ||
| return stringify(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneStringify}. | ||
| */ | ||
| function structuredCloneParse(value) { | ||
| return parse(value); | ||
| } | ||
| //#endregion | ||
| export { structuredCloneStringify as n, structuredCloneParse as t }; |
| //#region ../../node_modules/.pnpm/structured-clone-es@2.0.1/node_modules/structured-clone-es/dist/index.mjs | ||
| const env = typeof self === "object" ? self : globalThis; | ||
| const SAFE_ERROR_NAMES = /* @__PURE__ */ new Set([ | ||
| "Error", | ||
| "EvalError", | ||
| "RangeError", | ||
| "ReferenceError", | ||
| "SyntaxError", | ||
| "TypeError", | ||
| "URIError", | ||
| "AggregateError" | ||
| ]); | ||
| const SAFE_CONSTRUCTOR_NAMES = /* @__PURE__ */ new Set([ | ||
| "Boolean", | ||
| "Number", | ||
| "String", | ||
| "Int8Array", | ||
| "Uint8Array", | ||
| "Uint8ClampedArray", | ||
| "Int16Array", | ||
| "Uint16Array", | ||
| "Int32Array", | ||
| "Uint32Array", | ||
| "Float16Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "BigInt64Array", | ||
| "BigUint64Array" | ||
| ]); | ||
| function deserializer($, _) { | ||
| const as = (out, index) => { | ||
| $.set(index, out); | ||
| return out; | ||
| }; | ||
| const unpair = (index) => { | ||
| if ($.has(index)) return $.get(index); | ||
| const [type, value] = _[index]; | ||
| switch (type) { | ||
| case 0: | ||
| case -1: return as(value, index); | ||
| case 1: { | ||
| const arr = as([], index); | ||
| for (const index of value) arr.push(unpair(index)); | ||
| return arr; | ||
| } | ||
| case 2: { | ||
| const object = as({}, index); | ||
| for (const [key, index] of value) object[unpair(key)] = unpair(index); | ||
| return object; | ||
| } | ||
| case 3: return as(new Date(value), index); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as(new RegExp(source, flags), index); | ||
| } | ||
| case 5: { | ||
| const map = as(/* @__PURE__ */ new Map(), index); | ||
| for (const [key, index] of value) map.set(unpair(key), unpair(index)); | ||
| return map; | ||
| } | ||
| case 6: { | ||
| const set = as(/* @__PURE__ */ new Set(), index); | ||
| for (const index of value) set.add(unpair(index)); | ||
| return set; | ||
| } | ||
| case 7: { | ||
| const { name, message } = value; | ||
| const Ctor = SAFE_ERROR_NAMES.has(name) ? env[name] : void 0; | ||
| return as(new (Ctor ?? env.Error)(message), index); | ||
| } | ||
| case 8: return as(BigInt(value), index); | ||
| case "BigInt": return as(Object(BigInt(value)), index); | ||
| case "ArrayBuffer": return as(new Uint8Array(value).buffer, value); | ||
| case "DataView": { | ||
| const { buffer } = new Uint8Array(value); | ||
| return as(new DataView(buffer), value); | ||
| } | ||
| } | ||
| if (typeof type === "string" && SAFE_CONSTRUCTOR_NAMES.has(type)) return as(new env[type](value), index); | ||
| throw new TypeError(`unable to deserialize unsafe or unknown type: ${String(type)}`); | ||
| }; | ||
| return unpair; | ||
| } | ||
| /** | ||
| * Returns a deserialized value from a serialized array of Records. | ||
| * @param serialized a previously serialized value. | ||
| */ | ||
| function deserialize(serialized) { | ||
| return deserializer(/* @__PURE__ */ new Map(), serialized)(0); | ||
| } | ||
| const EMPTY = ""; | ||
| const { toString } = {}; | ||
| const { keys } = Object; | ||
| function typeOf(value) { | ||
| const type = typeof value; | ||
| if (type !== "object" || !value) return [0, type]; | ||
| const asString = toString.call(value).slice(8, -1); | ||
| switch (asString) { | ||
| case "Array": return [1, EMPTY]; | ||
| case "Object": return [2, EMPTY]; | ||
| case "Date": return [3, EMPTY]; | ||
| case "RegExp": return [4, EMPTY]; | ||
| case "Map": return [5, EMPTY]; | ||
| case "Set": return [6, EMPTY]; | ||
| case "DataView": return [1, asString]; | ||
| } | ||
| if (asString.includes("Array")) return [1, asString]; | ||
| if (asString.includes("Error")) return [7, asString]; | ||
| return [2, asString]; | ||
| } | ||
| function shouldSkip([TYPE, type]) { | ||
| return TYPE === 0 && (type === "function" || type === "symbol"); | ||
| } | ||
| function serializer(strict, json, $, _) { | ||
| const as = (out, value) => { | ||
| const index = _.push(out) - 1; | ||
| $.set(value, index); | ||
| return index; | ||
| }; | ||
| const pair = (value) => { | ||
| if ($.has(value)) return $.get(value); | ||
| let [TYPE, type] = typeOf(value); | ||
| switch (TYPE) { | ||
| case 0: { | ||
| let entry = value; | ||
| switch (type) { | ||
| case "bigint": | ||
| TYPE = 8; | ||
| entry = value.toString(); | ||
| break; | ||
| case "function": | ||
| case "symbol": | ||
| if (strict) throw new TypeError(`unable to serialize ${type}`); | ||
| entry = null; | ||
| break; | ||
| case "undefined": return as([-1], value); | ||
| } | ||
| return as([TYPE, entry], value); | ||
| } | ||
| case 1: { | ||
| if (type) { | ||
| let spread = value; | ||
| if (type === "DataView") spread = new Uint8Array(value.buffer); | ||
| else if (type === "ArrayBuffer") spread = new Uint8Array(value); | ||
| return as([type, [...spread]], value); | ||
| } | ||
| const arr = []; | ||
| const index = as([TYPE, arr], value); | ||
| for (const entry of value) arr.push(pair(entry)); | ||
| return index; | ||
| } | ||
| case 2: { | ||
| if (type) switch (type) { | ||
| case "BigInt": return as([type, value.toString()], value); | ||
| case "Boolean": | ||
| case "Number": | ||
| case "String": return as([type, value.valueOf()], value); | ||
| } | ||
| if (json && "toJSON" in value) return pair(value.toJSON()); | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const key of keys(value)) if (strict || !shouldSkip(typeOf(value[key]))) entries.push([pair(key), pair(value[key])]); | ||
| return index; | ||
| } | ||
| case 3: return as([TYPE, value.toISOString()], value); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as([TYPE, { | ||
| source, | ||
| flags | ||
| }], value); | ||
| } | ||
| case 5: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const [key, entry] of value) if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry)))) entries.push([pair(key), pair(entry)]); | ||
| return index; | ||
| } | ||
| case 6: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const entry of value) if (strict || !shouldSkip(typeOf(entry))) entries.push(pair(entry)); | ||
| return index; | ||
| } | ||
| } | ||
| const { message } = value; | ||
| return as([TYPE, { | ||
| name: type, | ||
| message | ||
| }], value); | ||
| }; | ||
| return pair; | ||
| } | ||
| /** | ||
| * Returns an array of serialized Records. | ||
| */ | ||
| function serialize(value, options = {}) { | ||
| const _ = []; | ||
| serializer(!(options.json || options.lossy), !!options.json, /* @__PURE__ */ new Map(), _)(value); | ||
| return _; | ||
| } | ||
| const { parse: $parse, stringify: $stringify } = JSON; | ||
| const options = { | ||
| json: true, | ||
| lossy: true | ||
| }; | ||
| /** | ||
| * Revive a previously stringified structured clone. | ||
| * @param str previously stringified data as string. | ||
| */ | ||
| function parse(str) { | ||
| return deserialize($parse(str)); | ||
| } | ||
| /** | ||
| * Represent a structured clone value as string. | ||
| * @param any some clone-able value to stringify. | ||
| */ | ||
| function stringify(any) { | ||
| return $stringify(serialize(any, options)); | ||
| } | ||
| //#endregion | ||
| //#region src/utils/structured-clone.ts | ||
| /** | ||
| * Serialize a structured-cloneable value (`Map`, `Set`, `Date`, `BigInt`, | ||
| * cycles, class instances, …) into a JSON-safe records array. | ||
| */ | ||
| function structuredCloneSerialize(value) { | ||
| return serialize(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneSerialize}. | ||
| */ | ||
| function structuredCloneDeserialize(value) { | ||
| return deserialize(value); | ||
| } | ||
| /** | ||
| * Serialize a structured-cloneable value to a single string. Equivalent | ||
| * to `JSON.stringify(structuredCloneSerialize(value))`. | ||
| */ | ||
| function structuredCloneStringify(value) { | ||
| return stringify(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneStringify}. | ||
| */ | ||
| function structuredCloneParse(value) { | ||
| return parse(value); | ||
| } | ||
| //#endregion | ||
| export { structuredCloneStringify as i, structuredCloneParse as n, structuredCloneSerialize as r, structuredCloneDeserialize as t }; |
@@ -1,2 +0,2 @@ | ||
| import { r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| //#region src/adapters/build.d.ts | ||
@@ -3,0 +3,0 @@ interface CreateBuildOptions { |
@@ -5,3 +5,3 @@ import { t as collectStaticRpcDump } from "../dump-Cz7yVvsB.mjs"; | ||
| import { n as strictJsonStringify } from "../serialization-DpLXCy13.mjs"; | ||
| import { n as structuredCloneStringify } from "../structured-clone-XpHLZ8nr.mjs"; | ||
| import { n as structuredCloneStringify } from "../structured-clone-CbAV5rFI.mjs"; | ||
| import { n as createHostContext, t as createH3DevframeHost } from "../host-h3-SjwRTwkE.mjs"; | ||
@@ -8,0 +8,0 @@ import { n as resolveBasePath } from "../_shared-bWRzeSa0.mjs"; |
@@ -1,2 +0,2 @@ | ||
| import { Ft as parseCliFlags, Mt as CliFlagsSchema, Nt as InferCliFlags, Pt as defineCliFlags, r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { Ft as parseCliFlags, Mt as CliFlagsSchema, Nt as InferCliFlags, Pt as defineCliFlags, r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| import { CAC } from "cac"; | ||
@@ -3,0 +3,0 @@ import { H3 } from "h3"; |
@@ -1,2 +0,2 @@ | ||
| import { n as defineCliFlags, r as parseCliFlags, t as createCac } from "../cac-Drj5sjnU.mjs"; | ||
| import { n as defineCliFlags, r as parseCliFlags, t as createCac } from "../cac-CjF0haJ6.mjs"; | ||
| export { createCac, defineCliFlags, parseCliFlags }; |
@@ -1,2 +0,2 @@ | ||
| import { Ft as parseCliFlags, Mt as CliFlagsSchema, Nt as InferCliFlags, Pt as defineCliFlags } from "../devframe-DfzYvlKI.mjs"; | ||
| import { Ft as parseCliFlags, Mt as CliFlagsSchema, Nt as InferCliFlags, Pt as defineCliFlags } from "../devframe-BADsX91-.mjs"; | ||
| import { CacHandle, CreateCacOptions, createCac } from "./cac.mjs"; | ||
@@ -3,0 +3,0 @@ //#region src/adapters/cli.d.ts |
@@ -1,2 +0,2 @@ | ||
| import { n as defineCliFlags, r as parseCliFlags, t as createCac } from "../cac-Drj5sjnU.mjs"; | ||
| import { n as defineCliFlags, r as parseCliFlags, t as createCac } from "../cac-CjF0haJ6.mjs"; | ||
| //#region src/adapters/cli.ts | ||
@@ -3,0 +3,0 @@ /** @deprecated Use `createCac` from `devframe/adapters/cac` instead. */ |
@@ -1,3 +0,3 @@ | ||
| import { d as McpRouteOptions, p as DevframeAuthHandler, r as DevframeDefinition, u as DevframeWsOptions } from "../devframe-DfzYvlKI.mjs"; | ||
| import { n as StartedServer } from "../server-Bf27EWpv.mjs"; | ||
| import { _ as ConnectionMeta, d as McpRouteOptions, p as DevframeAuthHandler, r as DevframeDefinition, u as DevframeWsOptions } from "../devframe-BADsX91-.mjs"; | ||
| import { n as StartedServer } from "../server-Bu5iB3aV.mjs"; | ||
| import { H3 } from "h3"; | ||
@@ -114,3 +114,18 @@ //#region src/adapters/dev.d.ts | ||
| declare function createDevServer(def: DevframeDefinition, options?: CreateDevServerOptions): Promise<StartedServer>; | ||
| /** | ||
| * Resolve the `mcp` entry a `__connection.json` should advertise for a dev | ||
| * server started with the given `mcp` option (falling back to `def.cli?.mcp`, | ||
| * exactly like {@link createDevServer}), or `undefined` when the route is | ||
| * disabled. | ||
| * | ||
| * Hosted bridges that hand-roll their connection meta (`viteDevBridge`, | ||
| * `@devframes/next`'s handler) pass the side-car `port`: the advertised path | ||
| * becomes absolute (the side-car mounts at `/`) and the client dials | ||
| * `<page-host>:<port><path>`. Without `port` the path stays relative, resolved | ||
| * against `__connection.json`'s own location (the same-server default). | ||
| * | ||
| * @experimental | ||
| */ | ||
| declare function resolveMcpConnectionMeta(def: DevframeDefinition, mcp: boolean | McpRouteOptions | undefined, port?: number): ConnectionMeta['mcp']; | ||
| //#endregion | ||
| export { CreateDevServerOptions, ResolveDevServerPortOptions, createDevServer, resolveDevServerPort }; | ||
| export { CreateDevServerOptions, ResolveDevServerPortOptions, createDevServer, resolveDevServerPort, resolveMcpConnectionMeta }; |
@@ -1,2 +0,2 @@ | ||
| import { n as resolveDevServerPort, t as createDevServer } from "../dev-BdegDQKt.mjs"; | ||
| export { createDevServer, resolveDevServerPort }; | ||
| import { n as resolveDevServerPort, r as resolveMcpConnectionMeta, t as createDevServer } from "../dev-OJFr4rx8.mjs"; | ||
| export { createDevServer, resolveDevServerPort, resolveMcpConnectionMeta }; |
@@ -1,2 +0,2 @@ | ||
| import { b as DevframeNodeContext, r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { b as DevframeNodeContext, r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| //#region src/adapters/embedded.d.ts | ||
@@ -3,0 +3,0 @@ interface CreateEmbeddedOptions { |
@@ -1,2 +0,2 @@ | ||
| import { r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| import "@modelcontextprotocol/sdk/server/index.js"; | ||
@@ -6,4 +6,6 @@ //#region src/adapters/mcp/build-server.d.ts | ||
| /** | ||
| * Transport to use. Only `'stdio'` is implemented today; HTTP support | ||
| * is planned in a follow-up PR. | ||
| * Transport to use. `createMcpServer` itself runs `'stdio'` (a standalone | ||
| * process with its own host context); the Streamable-HTTP transport is | ||
| * served route-based by the dev server instead — see `mountMcpHttp` and | ||
| * the `mcp` option on `createDevServer` / `createCac`'s `--mcp` flag. | ||
| */ | ||
@@ -10,0 +12,0 @@ transport?: 'stdio'; |
@@ -1,2 +0,2 @@ | ||
| import { n as createMcpServer } from "../build-server-CBAxmnC8.mjs"; | ||
| import { n as createMcpServer } from "../build-server-cANnMwg0.mjs"; | ||
| export { createMcpServer }; |
@@ -1,2 +0,2 @@ | ||
| import { $ as DevframeRpcServerFunctions, F as ScopedSharedStates, I as SettingsForNamespace, J as RpcSharedStateHost, N as ScopedRpcFn, O as DevframeSettings, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, _ as ConnectionMeta, at as StreamReader, ht as SharedState, kt as EventEmitter, ot as StreamSink, q as RpcSharedStateGetOptions } from "../devframe-DfzYvlKI.mjs"; | ||
| import { $ as DevframeRpcServerFunctions, F as ScopedSharedStates, I as SettingsForNamespace, J as RpcSharedStateHost, N as ScopedRpcFn, O as DevframeSettings, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, _ as ConnectionMeta, at as StreamReader, ht as SharedState, kt as EventEmitter, ot as StreamSink, q as RpcSharedStateGetOptions } from "../devframe-BADsX91-.mjs"; | ||
| import { _ as RpcFunctionDefinition, w as RpcFunctionsCollector } from "../types-CrzNxXKq.mjs"; | ||
@@ -3,0 +3,0 @@ import { C as RpcCacheManager, w as RpcCacheOptions } from "../index-DgsLFhZg.mjs"; |
@@ -1,2 +0,2 @@ | ||
| import { p as DevframeAuthHandler, r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { d as McpRouteOptions, p as DevframeAuthHandler, r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| //#region src/helpers/vite.d.ts | ||
@@ -46,2 +46,15 @@ interface ViteDevBridgeOptions { | ||
| auth?: boolean | DevframeAuthHandler; | ||
| /** | ||
| * Expose the side-car's route-based MCP server (Streamable-HTTP) and | ||
| * advertise it in the bridge's `__connection.json`. Forwarded to | ||
| * {@link createDevServer}: overrides `def.cli?.mcp`, `undefined` falls | ||
| * through to it, `false` disables the route regardless. Only applies in | ||
| * bridge mode (`devMiddleware`); the static-mount mode starts no server. | ||
| * | ||
| * The endpoint lives on the side-car's own port, so the advertised meta | ||
| * carries `{ port, path }` — see `ConnectionMeta['mcp']`. | ||
| * | ||
| * @experimental | ||
| */ | ||
| mcp?: boolean | McpRouteOptions; | ||
| } | ||
@@ -48,0 +61,0 @@ interface DevframeVitePlugin { |
@@ -5,3 +5,3 @@ import { DEVFRAME_CONNECTION_META_FILENAME, DEVFRAME_WS_ROUTE } from "../constants.mjs"; | ||
| import { serveStaticNodeMiddleware } from "../utils/serve-static.mjs"; | ||
| import { n as resolveDevServerPort, t as createDevServer } from "../dev-BdegDQKt.mjs"; | ||
| import { n as resolveDevServerPort, r as resolveMcpConnectionMeta, t as createDevServer } from "../dev-OJFr4rx8.mjs"; | ||
| import { resolve } from "pathe"; | ||
@@ -62,3 +62,4 @@ //#region src/helpers/vite.ts | ||
| openBrowser: false, | ||
| auth: options.auth ?? false | ||
| auth: options.auth ?? false, | ||
| mcp: options.mcp | ||
| }); | ||
@@ -73,2 +74,3 @@ } catch (e) { | ||
| } | ||
| const mcpMeta = resolveMcpConnectionMeta(d, options.mcp, port); | ||
| const metaPath = `${base}${DEVFRAME_CONNECTION_META_FILENAME}`; | ||
@@ -82,3 +84,4 @@ server.middlewares.use(metaPath, (_req, res) => { | ||
| path: `/${DEVFRAME_WS_ROUTE}` | ||
| } | ||
| }, | ||
| ...mcpMeta ? { mcp: mcpMeta } : {} | ||
| })); | ||
@@ -85,0 +88,0 @@ }); |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as EventUnsubscribe, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as DevframeAgentHost, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, N as ScopedRpcFn, O as DevframeSettings, Ot as DevframeAgentHostEvents, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventsMap, k as DevframeSettingsRegistry, kt as EventEmitter, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "./devframe-DfzYvlKI.mjs"; | ||
| import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as EventUnsubscribe, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as DevframeAgentHost, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, N as ScopedRpcFn, O as DevframeSettings, Ot as DevframeAgentHostEvents, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventsMap, k as DevframeSettingsRegistry, kt as EventEmitter, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "./devframe-BADsX91-.mjs"; | ||
| import { C as RpcFunctionType, T as RpcReturnSchema, _ as RpcFunctionDefinition, g as RpcFunctionAgentOptions, i as RpcArgsSchema } from "./types-CrzNxXKq.mjs"; | ||
@@ -3,0 +3,0 @@ import "./index-DgsLFhZg.mjs"; |
@@ -1,3 +0,3 @@ | ||
| import { p as DevframeAuthHandler } from "../devframe-DfzYvlKI.mjs"; | ||
| import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-CxpC1ItQ.mjs"; | ||
| import { p as DevframeAuthHandler } from "../devframe-BADsX91-.mjs"; | ||
| import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-Brcd2V4t.mjs"; | ||
| export { DevframeAuthHandler, buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken }; |
@@ -1,3 +0,3 @@ | ||
| import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-DfzYvlKI.mjs"; | ||
| import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-FonV8enL.mjs"; | ||
| import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-BADsX91-.mjs"; | ||
| import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-C_bqRR0i.mjs"; | ||
| //#region src/adapters/_shared.d.ts | ||
@@ -4,0 +4,0 @@ /** |
@@ -1,5 +0,5 @@ | ||
| import { C as DevframeServicesHost, Ct as AgentResourceContent, Dt as DevframeAgentHost$1, Et as AgentToolInput, H as DevframeDiagnosticsHost$1, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost$1, O as DevframeSettings, Ot as DevframeAgentHostEvents, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, Z as RpcStreamingHost, b as DevframeNodeContext, bt as AgentHandle, ht as SharedState, kt as EventEmitter, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest } from "../devframe-DfzYvlKI.mjs"; | ||
| import { C as DevframeServicesHost, Ct as AgentResourceContent, Dt as DevframeAgentHost$1, Et as AgentToolInput, H as DevframeDiagnosticsHost$1, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost$1, O as DevframeSettings, Ot as DevframeAgentHostEvents, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, Z as RpcStreamingHost, b as DevframeNodeContext, bt as AgentHandle, ht as SharedState, kt as EventEmitter, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest } from "../devframe-BADsX91-.mjs"; | ||
| import { v as RpcFunctionDefinitionAny } from "../types-CrzNxXKq.mjs"; | ||
| import "../index-DgsLFhZg.mjs"; | ||
| import { n as StartedServer, r as startHttpAndWs, t as StartHttpAndWsOptions } from "../server-Bf27EWpv.mjs"; | ||
| import { n as StartedServer, r as startHttpAndWs, t as StartHttpAndWsOptions } from "../server-Bu5iB3aV.mjs"; | ||
| import { BirpcGroup } from "birpc"; | ||
@@ -6,0 +6,0 @@ //#region src/node/context.d.ts |
@@ -1,3 +0,3 @@ | ||
| import { b as DevframeNodeContext, p as DevframeAuthHandler } from "../devframe-DfzYvlKI.mjs"; | ||
| import "../index-CxpC1ItQ.mjs"; | ||
| import { b as DevframeNodeContext, p as DevframeAuthHandler } from "../devframe-BADsX91-.mjs"; | ||
| import "../index-Brcd2V4t.mjs"; | ||
| //#region src/recipes/interactive-auth.d.ts | ||
@@ -4,0 +4,0 @@ interface CreateInteractiveAuthOptions { |
@@ -1,104 +0,6 @@ | ||
| import "../devframe-DfzYvlKI.mjs"; | ||
| import { E as Thenable, S as RpcFunctionSetupResult, c as RpcDump, g as RpcFunctionAgentOptions } from "../types-CrzNxXKq.mjs"; | ||
| import "../index-DgsLFhZg.mjs"; | ||
| import * as v from "valibot"; | ||
| import { commonRpcFunctions, openInEditor, openInFinder } from "./common-rpc-functions.mjs"; | ||
| //#region src/recipes/open-helpers.d.ts | ||
| /** | ||
| * Prebuilt RPC action that opens a file in the user's configured editor. | ||
| * | ||
| * Registered name: `devframe:open-in-editor`. | ||
| * | ||
| * ```ts | ||
| * import { openInEditor } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * defineDevframe({ | ||
| * id: 'my-tool', | ||
| * name: 'My Tool', | ||
| * setup(ctx) { | ||
| * ctx.rpc.register(openInEditor) | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| declare const openInEditor: { | ||
| name: "devframe:open-in-editor"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }; | ||
| /** | ||
| * Prebuilt RPC action that reveals a path in the OS file explorer. | ||
| * | ||
| * Registered name: `devframe:open-in-finder`. | ||
| * | ||
| * ```ts | ||
| * import { openInFinder } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * ctx.rpc.register(openInFinder) | ||
| * ``` | ||
| */ | ||
| declare const openInFinder: { | ||
| name: "devframe:open-in-finder"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }; | ||
| /** | ||
| * Convenience array bundling both helpers so callers can register them | ||
| * in a single `forEach`. | ||
| * | ||
| * ```ts | ||
| * import { openHelpers } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * openHelpers.forEach(fn => ctx.rpc.register(fn)) | ||
| * ``` | ||
| */ | ||
| declare const openHelpers: readonly [{ | ||
| name: "devframe:open-in-editor"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }, { | ||
| name: "devframe:open-in-finder"; | ||
| type?: "action" | undefined; | ||
| cacheable?: boolean; | ||
| args: readonly [v.StringSchema<undefined>]; | ||
| returns: v.VoidSchema<undefined>; | ||
| jsonSerializable?: boolean; | ||
| agent?: RpcFunctionAgentOptions; | ||
| setup?: ((context: undefined) => Thenable<RpcFunctionSetupResult<[string], void>>) | undefined; | ||
| handler?: ((args_0: string) => void) | undefined; | ||
| dump?: RpcDump<[string], void, undefined> | undefined; | ||
| snapshot?: boolean; | ||
| __cache?: WeakMap<object, Thenable<RpcFunctionSetupResult<[string], void>>> | undefined; | ||
| __promise?: Thenable<RpcFunctionSetupResult<[string], void>> | undefined; | ||
| }]; | ||
| /** @deprecated Use `commonRpcFunctions` from `devframe/recipes/common-rpc-functions` instead. */ | ||
| declare const openHelpers: typeof commonRpcFunctions; | ||
| //#endregion | ||
| export { openHelpers, openInEditor, openInFinder }; |
@@ -1,66 +0,6 @@ | ||
| import { t as launchEditor } from "../launch-editor-C_xuzLnF.mjs"; | ||
| import { n as defineRpcFunction } from "../define-BLWPsH6y.mjs"; | ||
| import { t as open } from "../open-Deb5xmIT.mjs"; | ||
| import * as v from "valibot"; | ||
| import { commonRpcFunctions, openInEditor, openInFinder } from "./common-rpc-functions.mjs"; | ||
| //#region src/recipes/open-helpers.ts | ||
| /** | ||
| * Prebuilt RPC action that opens a file in the user's configured editor. | ||
| * | ||
| * Registered name: `devframe:open-in-editor`. | ||
| * | ||
| * ```ts | ||
| * import { openInEditor } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * defineDevframe({ | ||
| * id: 'my-tool', | ||
| * name: 'My Tool', | ||
| * setup(ctx) { | ||
| * ctx.rpc.register(openInEditor) | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| const openInEditor = defineRpcFunction({ | ||
| name: "devframe:open-in-editor", | ||
| type: "action", | ||
| jsonSerializable: true, | ||
| args: [v.string()], | ||
| returns: v.void(), | ||
| async handler(filename) { | ||
| launchEditor(filename); | ||
| } | ||
| }); | ||
| /** | ||
| * Prebuilt RPC action that reveals a path in the OS file explorer. | ||
| * | ||
| * Registered name: `devframe:open-in-finder`. | ||
| * | ||
| * ```ts | ||
| * import { openInFinder } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * ctx.rpc.register(openInFinder) | ||
| * ``` | ||
| */ | ||
| const openInFinder = defineRpcFunction({ | ||
| name: "devframe:open-in-finder", | ||
| type: "action", | ||
| jsonSerializable: true, | ||
| args: [v.string()], | ||
| returns: v.void(), | ||
| async handler(path) { | ||
| await open(path); | ||
| } | ||
| }); | ||
| /** | ||
| * Convenience array bundling both helpers so callers can register them | ||
| * in a single `forEach`. | ||
| * | ||
| * ```ts | ||
| * import { openHelpers } from 'devframe/recipes/open-helpers' | ||
| * | ||
| * openHelpers.forEach(fn => ctx.rpc.register(fn)) | ||
| * ``` | ||
| */ | ||
| const openHelpers = [openInEditor, openInFinder]; | ||
| /** @deprecated Use `commonRpcFunctions` from `devframe/recipes/common-rpc-functions` instead. */ | ||
| const openHelpers = commonRpcFunctions; | ||
| //#endregion | ||
| export { openHelpers, openInEditor, openInFinder }; |
| import { DEVFRAME_AUTH_TOKEN_QUERY_PARAM } from "../../constants.mjs"; | ||
| import { n as strictJsonStringify } from "../../serialization-DpLXCy13.mjs"; | ||
| import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-XpHLZ8nr.mjs"; | ||
| import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-CbAV5rFI.mjs"; | ||
| //#region src/rpc/transports/ws-client.ts | ||
@@ -5,0 +5,0 @@ function NOOP() {} |
| import { n as strictJsonStringify } from "../../serialization-DpLXCy13.mjs"; | ||
| import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-XpHLZ8nr.mjs"; | ||
| import { n as structuredCloneStringify, t as structuredCloneParse } from "../../structured-clone-CbAV5rFI.mjs"; | ||
| import { createServer } from "node:http"; | ||
@@ -4,0 +4,0 @@ import { createServer as createServer$1 } from "node:https"; |
@@ -1,4 +0,4 @@ | ||
| import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as EventUnsubscribe, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as DevframeAgentHost, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, N as ScopedRpcFn, O as DevframeSettings, Ot as DevframeAgentHostEvents, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventsMap, k as DevframeSettingsRegistry, kt as EventEmitter, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "../devframe-DfzYvlKI.mjs"; | ||
| import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as EventUnsubscribe, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as DevframeAgentHost, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, N as ScopedRpcFn, O as DevframeSettings, Ot as DevframeAgentHostEvents, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventsMap, k as DevframeSettingsRegistry, kt as EventEmitter, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "../devframe-BADsX91-.mjs"; | ||
| import { g as RpcFunctionAgentOptions } from "../types-CrzNxXKq.mjs"; | ||
| import { t as DevframeNodeRpcSessionMeta } from "../ws-server-9-wn7MNQ.mjs"; | ||
| export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDockDefaults, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeServiceId, DevframeServiceOf, DevframeServicesHost, DevframeServicesRegistry, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSpaOptions, DevframeStorageScope, DevframeViewHost, DevframeWsOptions, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, McpRouteOptions, PartialWithoutId, RpcBroadcastOptions, type RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedRpcFn, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, Thenable, defineDevframe }; |
@@ -1,2 +0,2 @@ | ||
| import { jt as EventsMap, kt as EventEmitter } from "../devframe-DfzYvlKI.mjs"; | ||
| import { jt as EventsMap, kt as EventEmitter } from "../devframe-BADsX91-.mjs"; | ||
| //#region src/utils/events.d.ts | ||
@@ -3,0 +3,0 @@ /** |
@@ -1,2 +0,746 @@ | ||
| import { t as launchEditor } from "../launch-editor-C_xuzLnF.mjs"; | ||
| import { createRequire } from "node:module"; | ||
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports); | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))(); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js | ||
| var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| let p = process || {}; | ||
| let argv = p.argv || []; | ||
| let env = p.env || {}; | ||
| let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI); | ||
| let formatter = (open, close, replace = open) => (input) => { | ||
| let string = "" + input, index = string.indexOf(close, open.length); | ||
| return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close; | ||
| }; | ||
| let replaceClose = (string, close, replace, index) => { | ||
| let result = "", cursor = 0; | ||
| do { | ||
| result += string.substring(cursor, index) + replace; | ||
| cursor = index + close.length; | ||
| index = string.indexOf(close, cursor); | ||
| } while (~index); | ||
| return result + string.substring(cursor); | ||
| }; | ||
| let createColors = (enabled = isColorSupported) => { | ||
| let f = enabled ? formatter : () => String; | ||
| return { | ||
| isColorSupported: enabled, | ||
| reset: f("\x1B[0m", "\x1B[0m"), | ||
| bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"), | ||
| dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"), | ||
| italic: f("\x1B[3m", "\x1B[23m"), | ||
| underline: f("\x1B[4m", "\x1B[24m"), | ||
| inverse: f("\x1B[7m", "\x1B[27m"), | ||
| hidden: f("\x1B[8m", "\x1B[28m"), | ||
| strikethrough: f("\x1B[9m", "\x1B[29m"), | ||
| black: f("\x1B[30m", "\x1B[39m"), | ||
| red: f("\x1B[31m", "\x1B[39m"), | ||
| green: f("\x1B[32m", "\x1B[39m"), | ||
| yellow: f("\x1B[33m", "\x1B[39m"), | ||
| blue: f("\x1B[34m", "\x1B[39m"), | ||
| magenta: f("\x1B[35m", "\x1B[39m"), | ||
| cyan: f("\x1B[36m", "\x1B[39m"), | ||
| white: f("\x1B[37m", "\x1B[39m"), | ||
| gray: f("\x1B[90m", "\x1B[39m"), | ||
| bgBlack: f("\x1B[40m", "\x1B[49m"), | ||
| bgRed: f("\x1B[41m", "\x1B[49m"), | ||
| bgGreen: f("\x1B[42m", "\x1B[49m"), | ||
| bgYellow: f("\x1B[43m", "\x1B[49m"), | ||
| bgBlue: f("\x1B[44m", "\x1B[49m"), | ||
| bgMagenta: f("\x1B[45m", "\x1B[49m"), | ||
| bgCyan: f("\x1B[46m", "\x1B[49m"), | ||
| bgWhite: f("\x1B[47m", "\x1B[49m"), | ||
| blackBright: f("\x1B[90m", "\x1B[39m"), | ||
| redBright: f("\x1B[91m", "\x1B[39m"), | ||
| greenBright: f("\x1B[92m", "\x1B[39m"), | ||
| yellowBright: f("\x1B[93m", "\x1B[39m"), | ||
| blueBright: f("\x1B[94m", "\x1B[39m"), | ||
| magentaBright: f("\x1B[95m", "\x1B[39m"), | ||
| cyanBright: f("\x1B[96m", "\x1B[39m"), | ||
| whiteBright: f("\x1B[97m", "\x1B[39m"), | ||
| bgBlackBright: f("\x1B[100m", "\x1B[49m"), | ||
| bgRedBright: f("\x1B[101m", "\x1B[49m"), | ||
| bgGreenBright: f("\x1B[102m", "\x1B[49m"), | ||
| bgYellowBright: f("\x1B[103m", "\x1B[49m"), | ||
| bgBlueBright: f("\x1B[104m", "\x1B[49m"), | ||
| bgMagentaBright: f("\x1B[105m", "\x1B[49m"), | ||
| bgCyanBright: f("\x1B[106m", "\x1B[49m"), | ||
| bgWhiteBright: f("\x1B[107m", "\x1B[49m") | ||
| }; | ||
| }; | ||
| module.exports = createColors(); | ||
| module.exports.createColors = createColors; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/quote.js | ||
| var require_quote = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** @import { ControlOperator } from './parse' */ | ||
| /** @type {ControlOperator['op'][]} */ | ||
| var OPS = [ | ||
| "||", | ||
| "&&", | ||
| ";;", | ||
| "|&", | ||
| "<(", | ||
| "<<<", | ||
| ">>", | ||
| ">&", | ||
| "<&", | ||
| "&", | ||
| ";", | ||
| "(", | ||
| ")", | ||
| "|", | ||
| "<", | ||
| ">" | ||
| ]; | ||
| var LINE_TERMINATORS = /[\n\r\u2028\u2029]/; | ||
| var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g; | ||
| /** @type {typeof import('./quote')} */ | ||
| module.exports = function quote(xs) { | ||
| return xs.map(function(s) { | ||
| if (s === "") return "''"; | ||
| if (s && typeof s === "object") { | ||
| if ("op" in s && s.op === "glob") { | ||
| if (typeof s.pattern !== "string") throw new TypeError("glob token requires a string `pattern`"); | ||
| if (LINE_TERMINATORS.test(s.pattern)) throw new TypeError("glob `pattern` must not contain line terminators"); | ||
| return s.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&"); | ||
| } | ||
| if ("op" in s && typeof s.op === "string") { | ||
| if (OPS.indexOf(s.op) < 0) throw new TypeError("invalid `op` value: " + JSON.stringify(s.op)); | ||
| return s.op.replace(/[\s\S]/g, "\\$&"); | ||
| } | ||
| if ("comment" in s && typeof s.comment === "string") { | ||
| if (LINE_TERMINATORS.test(s.comment)) throw new TypeError("`comment` must not contain line terminators"); | ||
| return "#" + s.comment; | ||
| } | ||
| throw new TypeError("unrecognized object token shape"); | ||
| } | ||
| if (/["\s\\]/.test(s) && !/'/.test(s)) return "'" + s.replace(/(['])/g, "\\$1") + "'"; | ||
| if (/["'\s]/.test(s)) return "\"" + s.replace(/(["\\$`!])/g, "\\$1") + "\""; | ||
| return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}~])/g, "$1\\$2"); | ||
| }).join(" "); | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/parse.js | ||
| var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** | ||
| * @import { | ||
| * ControlOperator, | ||
| * Env, | ||
| * GlobPattern, | ||
| * ParseEntry, | ||
| * } from './parse' */ | ||
| var CONTROL = "(?:" + [ | ||
| "\\|\\|", | ||
| "\\&\\&", | ||
| ";;", | ||
| "\\|\\&", | ||
| "\\<\\(", | ||
| "\\<\\<\\<", | ||
| ">>", | ||
| ">\\&", | ||
| "<\\&", | ||
| "[&;()|<>]" | ||
| ].join("|") + ")"; | ||
| var controlRE = new RegExp("^" + CONTROL + "$"); | ||
| var META = "|&;()<> \\t"; | ||
| var SINGLE_QUOTE = "'([^']*?)'"; | ||
| var DOUBLE_QUOTE = "\"((\\\\\"|[^\"])*?)\""; | ||
| var hash = /^#$/; | ||
| var SQ = "'"; | ||
| var DQ = "\""; | ||
| var DS = "$"; | ||
| var TOKEN = ""; | ||
| var mult = 4294967296; | ||
| for (var i = 0; i < 4; i++) TOKEN += (mult * Math.random()).toString(16); | ||
| var startsWithToken = new RegExp("^" + TOKEN); | ||
| /** | ||
| * @param {string} s | ||
| * @param {RegExp} r | ||
| */ | ||
| function matchAll(s, r) { | ||
| var origIndex = r.lastIndex; | ||
| var matches = []; | ||
| var matchObj; | ||
| while (matchObj = r.exec(s)) { | ||
| matches[matches.length] = matchObj; | ||
| if (r.lastIndex === matchObj.index) r.lastIndex += 1; | ||
| } | ||
| r.lastIndex = origIndex; | ||
| return matches; | ||
| } | ||
| /** | ||
| * @param {Env} env | ||
| * @param {string} pre | ||
| * @param {string} key | ||
| */ | ||
| function getVar(env, pre, key) { | ||
| var r = typeof env === "function" ? env(key) : env[key]; | ||
| if (typeof r === "undefined" && key != "") r = ""; | ||
| else if (typeof r === "undefined") r = "$"; | ||
| if (typeof r === "object") return pre + TOKEN + JSON.stringify(r) + TOKEN; | ||
| return pre + r; | ||
| } | ||
| /** | ||
| * @param {string} string | ||
| * @param {Env} [env] | ||
| * @param {{ escape?: string, splitUnquoted?: boolean | string }} [opts] | ||
| * @returns {ParseEntry[]} | ||
| */ | ||
| function parseInternal(string, env, opts) { | ||
| if (!opts) opts = {}; | ||
| var BS = opts.escape || "\\"; | ||
| var ifs = opts.splitUnquoted === true ? " \n" : typeof opts.splitUnquoted === "string" ? opts.splitUnquoted : ""; | ||
| var BAREWORD = "(\\" + BS + "['\"" + META + "]|[^\\s'\"" + META + "])+"; | ||
| var matches = matchAll(string, new RegExp(["(" + CONTROL + ")", "(" + BAREWORD + "|" + DOUBLE_QUOTE + "|" + SINGLE_QUOTE + ")+"].join("|"), "g")); | ||
| if (matches.length === 0) return []; | ||
| if (!env) env = {}; | ||
| var commented = false; | ||
| return matches.map(function(match) { | ||
| var s = match[0]; | ||
| if (!s || commented) return; | ||
| if (controlRE.test(s)) return { op: s }; | ||
| /** @type {string | boolean} */ | ||
| var quote = false; | ||
| var esc = false; | ||
| var out = ""; | ||
| /** @type {string[]} */ | ||
| var words = []; | ||
| var sawQuote = false; | ||
| /** @type {number | null} */ | ||
| var pendingNw = null; | ||
| var isGlob = false; | ||
| /** @type {number} */ | ||
| var i; | ||
| function parseEnvVar() { | ||
| i += 1; | ||
| /** @type {number | RegExpMatchArray | null} */ | ||
| var varend; | ||
| /** @type {string} */ | ||
| var varname; | ||
| var char = s.charAt(i); | ||
| if (char === "{") { | ||
| i += 1; | ||
| if (s.charAt(i) === "}") throw new Error("Bad substitution: " + s.slice(i - 2, i + 1)); | ||
| var depth = 1; | ||
| varend = i; | ||
| while (depth > 0 && varend < s.length) { | ||
| if (s.charAt(varend) === "{" && s.charAt(varend - 1) === "$") depth += 1; | ||
| else if (s.charAt(varend) === "}") depth -= 1; | ||
| varend += 1; | ||
| } | ||
| if (depth !== 0) throw new Error("Bad substitution: " + s.slice(i)); | ||
| varend -= 1; | ||
| varname = s.slice(i, varend); | ||
| i = varend; | ||
| } else if (/[*@#?$!_-]/.test(char)) { | ||
| varname = char; | ||
| i += 1; | ||
| } else { | ||
| var slicedFromI = s.slice(i); | ||
| varend = slicedFromI.match(/[^\w\d_]/); | ||
| if (!varend) { | ||
| varname = slicedFromI; | ||
| i = s.length; | ||
| } else { | ||
| varname = slicedFromI.slice(0, varend.index); | ||
| i += varend.index - 1; | ||
| } | ||
| } | ||
| return getVar(env, "", varname); | ||
| } | ||
| function flushRun() { | ||
| if (pendingNw === null) return; | ||
| if (pendingNw === 0) { | ||
| if (out !== "") { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| } | ||
| } else { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| for (var fe = 1; fe < pendingNw; fe += 1) words[words.length] = ""; | ||
| } | ||
| pendingNw = null; | ||
| } | ||
| for (i = 0; i < s.length; i++) { | ||
| var c = s.charAt(i); | ||
| if (ifs && c !== DS) flushRun(); | ||
| isGlob = isGlob || !quote && (c === "*" || c === "?"); | ||
| if (esc) { | ||
| out += c; | ||
| esc = false; | ||
| } else if (quote) if (c === quote) quote = false; | ||
| else if (quote == SQ) out += c; | ||
| else if (c === BS) { | ||
| i += 1; | ||
| c = s.charAt(i); | ||
| if (c === DQ || c === BS || c === DS) out += c; | ||
| else out += BS + c; | ||
| } else if (c === DS) out += parseEnvVar(); | ||
| else out += c; | ||
| else if (c === DQ || c === SQ) { | ||
| quote = c; | ||
| sawQuote = true; | ||
| } else if (controlRE.test(c)) return { op: s }; | ||
| else if (hash.test(c)) { | ||
| commented = true; | ||
| var commentObj = { comment: string.slice(match.index + i + 1) }; | ||
| if (out.length) return [out, commentObj]; | ||
| return [commentObj]; | ||
| } else if (c === BS) esc = true; | ||
| else if (c === DS) { | ||
| var value = parseEnvVar(); | ||
| if (!ifs) out += value; | ||
| else for (var vi = 0; vi < value.length; vi += 1) { | ||
| var vc = value.charAt(vi); | ||
| if (ifs.indexOf(vc) < 0) { | ||
| flushRun(); | ||
| out += vc; | ||
| } else if (pendingNw === null) pendingNw = vc === " " || vc === " " || vc === "\n" ? 0 : 1; | ||
| else if (vc !== " " && vc !== " " && vc !== "\n") pendingNw += 1; | ||
| } | ||
| } else out += c; | ||
| } | ||
| if (isGlob) return { | ||
| op: "glob", | ||
| pattern: out | ||
| }; | ||
| if (ifs) { | ||
| if (pendingNw !== null && pendingNw > 0) { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| for (var te = 1; te < pendingNw; te += 1) words[words.length] = ""; | ||
| } | ||
| if (out !== "" || sawQuote && words.length === 0) words[words.length] = out; | ||
| return words; | ||
| } | ||
| return out; | ||
| }).reduce(function(prev, arg) { | ||
| if (typeof arg === "undefined") return prev; | ||
| /** @type {ParseEntry[]} */ [].concat(arg).forEach(function(entry) { | ||
| prev[prev.length] = entry; | ||
| }); | ||
| return prev; | ||
| }, []); | ||
| } | ||
| /** @type {typeof import('./parse')} */ | ||
| module.exports = function parse(s, env, opts) { | ||
| var mapped = parseInternal(s, env, opts); | ||
| if (typeof env !== "function") return mapped; | ||
| return mapped.reduce(function(acc, s) { | ||
| if (typeof s === "object") { | ||
| acc[acc.length] = s; | ||
| return acc; | ||
| } | ||
| var xs = s.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g")); | ||
| if (xs.length === 1) { | ||
| acc[acc.length] = xs[0]; | ||
| return acc; | ||
| } | ||
| xs.filter(Boolean).forEach(function(x) { | ||
| acc[acc.length] = startsWithToken.test(x) ? JSON.parse(x.split(TOKEN)[1]) : x; | ||
| }); | ||
| return acc; | ||
| }, []); | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/index.js | ||
| var require_shell_quote = /* @__PURE__ */ __commonJSMin(((exports) => { | ||
| exports.quote = require_quote(); | ||
| exports.parse = require_parse(); | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/macos.js | ||
| var require_macos = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = { | ||
| "/Applications/Atom.app/Contents/MacOS/Atom": "atom", | ||
| "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta": "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta", | ||
| "/Applications/Brackets.app/Contents/MacOS/Brackets": "brackets", | ||
| "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text.app/Contents/MacOS/sublime_text": "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2": "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Visual Studio Code.app/Contents/MacOS/Code": "code", | ||
| "/Applications/Visual Studio Code.app/Contents/MacOS/Electron": "code", | ||
| "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Code - Insiders": "code-insiders", | ||
| "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron": "code-insiders", | ||
| "/Applications/VSCodium.app/Contents/MacOS/Electron": "codium", | ||
| "/Applications/Cursor.app/Contents/MacOS/Cursor": "cursor", | ||
| "/Applications/Trae.app/Contents/MacOS/Electron": "trae", | ||
| "/Applications/Antigravity.app/Contents/MacOS/Electron": "antigravity", | ||
| "/Applications/AppCode.app/Contents/MacOS/appcode": "/Applications/AppCode.app/Contents/MacOS/appcode", | ||
| "/Applications/CLion.app/Contents/MacOS/clion": "/Applications/CLion.app/Contents/MacOS/clion", | ||
| "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea", | ||
| "/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea", | ||
| "/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea", | ||
| "/Applications/PhpStorm.app/Contents/MacOS/phpstorm": "/Applications/PhpStorm.app/Contents/MacOS/phpstorm", | ||
| "/Applications/PyCharm.app/Contents/MacOS/pycharm": "/Applications/PyCharm.app/Contents/MacOS/pycharm", | ||
| "/Applications/PyCharm CE.app/Contents/MacOS/pycharm": "/Applications/PyCharm CE.app/Contents/MacOS/pycharm", | ||
| "/Applications/RubyMine.app/Contents/MacOS/rubymine": "/Applications/RubyMine.app/Contents/MacOS/rubymine", | ||
| "/Applications/WebStorm.app/Contents/MacOS/webstorm": "/Applications/WebStorm.app/Contents/MacOS/webstorm", | ||
| "/Applications/MacVim.app/Contents/MacOS/MacVim": "mvim", | ||
| "/Applications/GoLand.app/Contents/MacOS/goland": "/Applications/GoLand.app/Contents/MacOS/goland", | ||
| "/Applications/Rider.app/Contents/MacOS/rider": "/Applications/Rider.app/Contents/MacOS/rider", | ||
| "/Applications/Zed.app/Contents/MacOS/zed": "zed" | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/linux.js | ||
| var require_linux = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = { | ||
| atom: "atom", | ||
| Brackets: "brackets", | ||
| "code-insiders": "code-insiders", | ||
| code: "code", | ||
| vscodium: "vscodium", | ||
| codium: "codium", | ||
| cursor: "cursor", | ||
| trae: "trae", | ||
| antigravity: "antigravity", | ||
| emacs: "emacs", | ||
| gvim: "gvim", | ||
| idea: "idea", | ||
| "idea.sh": "idea", | ||
| phpstorm: "phpstorm", | ||
| "phpstorm.sh": "phpstorm", | ||
| pycharm: "pycharm", | ||
| "pycharm.sh": "pycharm", | ||
| rubymine: "rubymine", | ||
| "rubymine.sh": "rubymine", | ||
| sublime_text: "subl", | ||
| vim: "vim", | ||
| webstorm: "webstorm", | ||
| "webstorm.sh": "webstorm", | ||
| goland: "goland", | ||
| "goland.sh": "goland", | ||
| rider: "rider", | ||
| "rider.sh": "rider", | ||
| zed: "zed" | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/windows.js | ||
| var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = [ | ||
| "Brackets.exe", | ||
| "Code.exe", | ||
| "Code - Insiders.exe", | ||
| "VSCodium.exe", | ||
| "Cursor.exe", | ||
| "atom.exe", | ||
| "sublime_text.exe", | ||
| "notepad++.exe", | ||
| "clion.exe", | ||
| "clion64.exe", | ||
| "idea.exe", | ||
| "idea64.exe", | ||
| "phpstorm.exe", | ||
| "phpstorm64.exe", | ||
| "pycharm.exe", | ||
| "pycharm64.exe", | ||
| "rubymine.exe", | ||
| "rubymine64.exe", | ||
| "webstorm.exe", | ||
| "webstorm64.exe", | ||
| "goland.exe", | ||
| "goland64.exe", | ||
| "rider.exe", | ||
| "rider64.exe", | ||
| "Trae.exe", | ||
| "zed.exe", | ||
| "Antigravity.exe" | ||
| ]; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/guess.js | ||
| var require_guess = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| const path$2 = __require("path"); | ||
| const shellQuote = require_shell_quote(); | ||
| const childProcess$1 = __require("child_process"); | ||
| const COMMON_EDITORS_MACOS = require_macos(); | ||
| const COMMON_EDITORS_LINUX = require_linux(); | ||
| const COMMON_EDITORS_WIN = require_windows(); | ||
| function getEditorFromMacProcesses(output) { | ||
| const processNames = Object.keys(COMMON_EDITORS_MACOS); | ||
| const processList = output.split("\n"); | ||
| for (let i = 0; i < processNames.length; i++) { | ||
| const processName = processNames[i]; | ||
| if (processList.includes(processName)) return COMMON_EDITORS_MACOS[processName]; | ||
| const processNameWithoutApplications = processName.replace("/Applications", ""); | ||
| if (output.indexOf(processNameWithoutApplications) !== -1) { | ||
| if (processName !== COMMON_EDITORS_MACOS[processName]) return COMMON_EDITORS_MACOS[processName]; | ||
| const runningProcess = processList.find((procName) => procName.endsWith(processNameWithoutApplications)); | ||
| if (runningProcess !== void 0) return runningProcess; | ||
| } | ||
| } | ||
| } | ||
| function getEditorFromWindowsProcesses(output) { | ||
| const runningProcesses = output.split("\r\n"); | ||
| for (let i = 0; i < runningProcesses.length; i++) { | ||
| const fullProcessPath = runningProcesses[i].trim(); | ||
| const shortProcessName = path$2.win32.basename(fullProcessPath); | ||
| if (COMMON_EDITORS_WIN.indexOf(shortProcessName) !== -1) return fullProcessPath; | ||
| } | ||
| } | ||
| function getEditorFromLinuxProcesses(output) { | ||
| const processNames = Object.keys(COMMON_EDITORS_LINUX); | ||
| for (let i = 0; i < processNames.length; i++) { | ||
| const processName = processNames[i]; | ||
| if (output.indexOf(processName) !== -1) return COMMON_EDITORS_LINUX[processName]; | ||
| } | ||
| } | ||
| function guessEditor(specifiedEditor) { | ||
| if (specifiedEditor) return shellQuote.parse(specifiedEditor); | ||
| if (process.env.LAUNCH_EDITOR) return [process.env.LAUNCH_EDITOR]; | ||
| if (process.versions.webcontainer) return [process.env.EDITOR || "code"]; | ||
| try { | ||
| if (process.platform === "darwin") { | ||
| const editor = getEditorFromMacProcesses(childProcess$1.execSync("ps x -o comm=", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } else if (process.platform === "win32") { | ||
| const editor = getEditorFromWindowsProcesses(childProcess$1.execSync("powershell -NoProfile -Command \"[Console]::OutputEncoding=[Text.Encoding]::UTF8;Get-CimInstance -Query \\\"select executablepath from win32_process where executablepath is not null\\\" | % { $_.ExecutablePath }\"", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } else if (process.platform === "linux") { | ||
| const editor = getEditorFromLinuxProcesses(childProcess$1.execSync("ps x --no-heading -o comm --sort=comm", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } | ||
| } catch (ignoreError) {} | ||
| if (process.env.VISUAL) return [process.env.VISUAL]; | ||
| else if (process.env.EDITOR) return [process.env.EDITOR]; | ||
| return [null]; | ||
| } | ||
| module.exports = guessEditor; | ||
| module.exports.getEditorFromMacProcesses = getEditorFromMacProcesses; | ||
| module.exports.getEditorFromWindowsProcesses = getEditorFromWindowsProcesses; | ||
| module.exports.getEditorFromLinuxProcesses = getEditorFromLinuxProcesses; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/get-args.js | ||
| var require_get_args = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| const path$1 = __require("path"); | ||
| module.exports = function getArgumentsForPosition(editor, fileName, lineNumber, columnNumber = 1) { | ||
| switch (path$1.basename(editor).replace(/\.(exe|cmd|bat)$/i, "")) { | ||
| case "atom": | ||
| case "Atom": | ||
| case "Atom Beta": | ||
| case "subl": | ||
| case "sublime": | ||
| case "sublime_text": | ||
| case "wstorm": | ||
| case "charm": | ||
| case "zed": return [`${fileName}:${lineNumber}:${columnNumber}`]; | ||
| case "notepad++": return [ | ||
| "-n" + lineNumber, | ||
| "-c" + columnNumber, | ||
| fileName | ||
| ]; | ||
| case "vim": | ||
| case "mvim": return [`+call cursor(${lineNumber}, ${columnNumber})`, fileName]; | ||
| case "joe": | ||
| case "gvim": return [`+${lineNumber}`, fileName]; | ||
| case "emacs": | ||
| case "emacsclient": return [`+${lineNumber}:${columnNumber}`, fileName]; | ||
| case "rmate": | ||
| case "mate": | ||
| case "mine": return [ | ||
| "--line", | ||
| lineNumber, | ||
| fileName | ||
| ]; | ||
| case "code": | ||
| case "Code": | ||
| case "code-insiders": | ||
| case "Code - Insiders": | ||
| case "codium": | ||
| case "trae": | ||
| case "antigravity": | ||
| case "cursor": | ||
| case "vscodium": | ||
| case "VSCodium": return [ | ||
| "-r", | ||
| "-g", | ||
| `${fileName}:${lineNumber}:${columnNumber}` | ||
| ]; | ||
| case "appcode": | ||
| case "clion": | ||
| case "clion64": | ||
| case "idea": | ||
| case "idea64": | ||
| case "phpstorm": | ||
| case "phpstorm64": | ||
| case "pycharm": | ||
| case "pycharm64": | ||
| case "rubymine": | ||
| case "rubymine64": | ||
| case "webstorm": | ||
| case "webstorm64": | ||
| case "goland": | ||
| case "goland64": | ||
| case "rider": | ||
| case "rider64": return [ | ||
| "--line", | ||
| lineNumber, | ||
| "--column", | ||
| columnNumber, | ||
| fileName | ||
| ]; | ||
| } | ||
| if (process.env.LAUNCH_EDITOR) return [ | ||
| fileName, | ||
| lineNumber, | ||
| columnNumber | ||
| ]; | ||
| return [fileName]; | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region src/utils/launch-editor.ts | ||
| var import_launch_editor = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** | ||
| * Copyright (c) 2015-present, Facebook, Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file at | ||
| * https://github.com/facebookincubator/create-react-app/blob/master/LICENSE | ||
| * | ||
| * Modified by Yuxi Evan You | ||
| */ | ||
| const fs = __require("fs"); | ||
| const os = __require("os"); | ||
| const path = __require("path"); | ||
| const colors = require_picocolors(); | ||
| const childProcess = __require("child_process"); | ||
| const guessEditor = require_guess(); | ||
| const getArgumentsForPosition = require_get_args(); | ||
| function wrapErrorCallback(cb) { | ||
| return (fileName, errorMessage) => { | ||
| console.log(); | ||
| console.log(colors.red("Could not open " + path.basename(fileName) + " in the editor.")); | ||
| if (errorMessage) { | ||
| if (errorMessage[errorMessage.length - 1] !== ".") errorMessage += "."; | ||
| console.log(colors.red("The editor process exited with an error: " + errorMessage)); | ||
| } | ||
| console.log(); | ||
| if (cb) cb(fileName, errorMessage); | ||
| }; | ||
| } | ||
| function isTerminalEditor(editor) { | ||
| switch (editor) { | ||
| case "vim": | ||
| case "emacs": | ||
| case "nano": return true; | ||
| } | ||
| return false; | ||
| } | ||
| const positionRE = /:(\d+)(:(\d+))?$/; | ||
| function parseFile(file) { | ||
| if (file.startsWith("file://")) file = __require("url").fileURLToPath(file); | ||
| const fileName = file.replace(positionRE, ""); | ||
| const match = file.match(positionRE); | ||
| return { | ||
| fileName, | ||
| lineNumber: match && match[1], | ||
| columnNumber: match && match[3] | ||
| }; | ||
| } | ||
| let currentChildProcess = null; | ||
| function launchEditor(file, specifiedEditor, onErrorCallback) { | ||
| const parsed = parseFile(file); | ||
| let { fileName } = parsed; | ||
| const { lineNumber, columnNumber } = parsed; | ||
| if (process.platform === "win32" && path.resolve(fileName).startsWith("\\\\")) return onErrorCallback(fileName, "UNC paths are not supported on Windows to avoid security issues. See https://github.com/vitejs/launch-editor/tree/main/packages/launch-editor#unc-paths-on-windows for details."); | ||
| if (!fs.existsSync(fileName)) return; | ||
| if (typeof specifiedEditor === "function") { | ||
| onErrorCallback = specifiedEditor; | ||
| specifiedEditor = void 0; | ||
| } | ||
| onErrorCallback = wrapErrorCallback(onErrorCallback); | ||
| const [editor, ...args] = guessEditor(specifiedEditor); | ||
| if (!editor) { | ||
| onErrorCallback(fileName, null); | ||
| return; | ||
| } | ||
| if (process.platform === "linux" && fileName.startsWith("/mnt/") && /Microsoft/i.test(os.release())) fileName = path.relative("", fileName); | ||
| if (lineNumber) { | ||
| const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber); | ||
| args.push.apply(args, extraArgs); | ||
| } else args.push(fileName); | ||
| if (currentChildProcess && isTerminalEditor(editor)) currentChildProcess.kill("SIGKILL"); | ||
| if (process.platform === "win32") { | ||
| function escapeCmdArgs(cmdArgs) { | ||
| return cmdArgs.replace(/([&|<>,;=^])/g, "^$1"); | ||
| } | ||
| function doubleQuoteIfNeeded(str) { | ||
| if (str.includes("^")) return `^"${str}^"`; | ||
| else if (str.includes(" ")) return `"${str}"`; | ||
| return str; | ||
| } | ||
| const launchCommand = [editor, ...args.map(escapeCmdArgs)].map(doubleQuoteIfNeeded).join(" "); | ||
| currentChildProcess = childProcess.exec(launchCommand, { | ||
| stdio: "inherit", | ||
| shell: true | ||
| }); | ||
| } else currentChildProcess = childProcess.spawn(editor, args, { stdio: "inherit" }); | ||
| currentChildProcess.on("exit", function(errorCode) { | ||
| currentChildProcess = null; | ||
| if (errorCode) onErrorCallback(fileName, "(code " + errorCode + ")"); | ||
| }); | ||
| currentChildProcess.on("error", function(error) { | ||
| let { code, message } = error; | ||
| if ("ENOENT" === code) message = `${message} ('${editor}' command does not exist in 'PATH')`; | ||
| onErrorCallback(fileName, message); | ||
| }); | ||
| } | ||
| module.exports = launchEditor; | ||
| })))(), 1); | ||
| /** | ||
| * Open a file in the user's editor. | ||
| * | ||
| * `target` may be a plain path, `file:line`, or `file:line:column`. | ||
| * | ||
| * If `editor` is provided, it is used as the editor command (e.g. `'code'`, | ||
| * `'subl'`) or absolute binary path. Otherwise the editor is auto-detected | ||
| * via the `LAUNCH_EDITOR` env var with a fallback to common defaults. | ||
| */ | ||
| function launchEditor(target, editor) { | ||
| (0, import_launch_editor.default)(target, editor); | ||
| } | ||
| //#endregion | ||
| export { launchEditor }; |
@@ -1,2 +0,2 @@ | ||
| import { _t as SharedStateOptions, dt as ImmutableArray, ft as ImmutableMap, gt as SharedStateEvents, ht as SharedState, mt as ImmutableSet, pt as ImmutableObject, ut as Immutable, vt as SharedStatePatch, yt as createSharedState } from "../devframe-DfzYvlKI.mjs"; | ||
| import { _t as SharedStateOptions, dt as ImmutableArray, ft as ImmutableMap, gt as SharedStateEvents, ht as SharedState, mt as ImmutableSet, pt as ImmutableObject, ut as Immutable, vt as SharedStatePatch, yt as createSharedState } from "../devframe-BADsX91-.mjs"; | ||
| export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, SharedStatePatch, createSharedState }; |
@@ -1,2 +0,2 @@ | ||
| import { at as StreamReader, ct as createStreamReader, it as StreamErrorPayload, lt as createStreamSink, nt as CreateStreamReaderOptions, ot as StreamSink, rt as CreateStreamSinkOptions, st as StreamSinkEvents, tt as BufferedChunk } from "../devframe-DfzYvlKI.mjs"; | ||
| import { at as StreamReader, ct as createStreamReader, it as StreamErrorPayload, lt as createStreamSink, nt as CreateStreamReaderOptions, ot as StreamSink, rt as CreateStreamSinkOptions, st as StreamSinkEvents, tt as BufferedChunk } from "../devframe-BADsX91-.mjs"; | ||
| export { BufferedChunk, CreateStreamReaderOptions, CreateStreamSinkOptions, StreamErrorPayload, StreamReader, StreamSink, StreamSinkEvents, createStreamReader, createStreamSink }; |
@@ -1,2 +0,2 @@ | ||
| import { i as structuredCloneStringify, n as structuredCloneParse, r as structuredCloneSerialize, t as structuredCloneDeserialize } from "../structured-clone-CeZOHvkd.mjs"; | ||
| import { i as structuredCloneStringify, n as structuredCloneParse, r as structuredCloneSerialize, t as structuredCloneDeserialize } from "../structured-clone-CgtQ61SA.mjs"; | ||
| export { structuredCloneDeserialize, structuredCloneParse, structuredCloneSerialize, structuredCloneStringify }; |
+5
-4
| { | ||
| "name": "devframe", | ||
| "type": "module", | ||
| "version": "0.7.14", | ||
| "version": "0.7.15", | ||
| "description": "Framework for building generic devframes", | ||
@@ -35,2 +35,3 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>", | ||
| "./node/hub-internals": "./dist/node/hub-internals.mjs", | ||
| "./recipes/common-rpc-functions": "./dist/recipes/common-rpc-functions.mjs", | ||
| "./recipes/interactive-auth": "./dist/recipes/interactive-auth.mjs", | ||
@@ -83,3 +84,3 @@ "./recipes/open-helpers": "./dist/recipes/open-helpers.mjs", | ||
| "destr": "^2.0.5", | ||
| "h3": "^2.0.1-rc.22", | ||
| "h3": "^2.0.1-rc.26", | ||
| "mrmime": "^2.0.1", | ||
@@ -92,3 +93,3 @@ "nostics": "^1.2.0", | ||
| "devDependencies": { | ||
| "@modelcontextprotocol/sdk": "^1.29.0", | ||
| "@modelcontextprotocol/sdk": "^1.30.0", | ||
| "cac": "^7.0.0", | ||
@@ -104,3 +105,3 @@ "get-port-please": "^3.2.0", | ||
| "perfect-debounce": "^2.1.0", | ||
| "structured-clone-es": "^2.0.0", | ||
| "structured-clone-es": "^2.0.1", | ||
| "tinyglobby": "^0.2.17", | ||
@@ -107,0 +108,0 @@ "tsdown": "^0.22.14", |
@@ -563,3 +563,3 @@ --- | ||
| For "open file in editor" + "reveal in finder", prefer the prebuilt `openHelpers` RPC recipe — it wires the two utilities into named RPC functions ready to register. | ||
| For "open file in editor" + "reveal in finder", prefer the prebuilt `commonRpcFunctions` RPC recipe (`devframe/recipes/common-rpc-functions`) — it wires the two utilities into named RPC functions ready to register. | ||
@@ -566,0 +566,0 @@ ## Security (secure by default) |
| import { a as diagnostics } from "./storage-D_Xy9v1l.mjs"; | ||
| import { n as createHostContext } from "./host-h3-SjwRTwkE.mjs"; | ||
| import { join } from "pathe"; | ||
| import process from "node:process"; | ||
| import { homedir } from "node:os"; | ||
| import { Server } from "@modelcontextprotocol/sdk/server/index.js"; | ||
| import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js"; | ||
| import { toJsonSchema } from "@valibot/to-json-schema"; | ||
| //#region src/adapters/mcp/stringify.ts | ||
| /** | ||
| * JSON-coercing serializer for MCP text payloads. | ||
| * | ||
| * MCP carries tool results and resource reads as plain text over a | ||
| * JSON-RPC transport, so we cannot use the `s:`-prefixed structured-clone | ||
| * format the WS RPC transport falls back to for non-JSON values. Instead, | ||
| * we coerce common non-JSON types into JSON-friendly forms so the LLM | ||
| * client sees something useful instead of `[object Object]`. | ||
| * | ||
| * Coercions: | ||
| * - `BigInt` → `"123n"` | ||
| * - `Date` → ISO string (via the native `toJSON`) | ||
| * - `Map` → `{ __type: 'Map', entries: [[k, v], …] }` | ||
| * - `Set` → `{ __type: 'Set', entries: [v, …] }` | ||
| * - `Error` → `{ name, message, stack, cause? }` (cause recurses) | ||
| * - `Function` → `"[Function: name]"` | ||
| * - `Symbol` → `value.toString()` | ||
| * - cycles → `"[Circular]"` | ||
| */ | ||
| function stringifyForMcp(value) { | ||
| if (value === void 0) return "undefined"; | ||
| if (typeof value === "string") return value; | ||
| const seen = /* @__PURE__ */ new WeakSet(); | ||
| return JSON.stringify(value, (_key, val) => { | ||
| if (typeof val === "bigint") return `${val}n`; | ||
| if (val instanceof Error) { | ||
| const out = { | ||
| name: val.name, | ||
| message: val.message, | ||
| stack: val.stack | ||
| }; | ||
| if (val.cause !== void 0) out.cause = val.cause; | ||
| return out; | ||
| } | ||
| if (val instanceof Map) return { | ||
| __type: "Map", | ||
| entries: [...val.entries()] | ||
| }; | ||
| if (val instanceof Set) return { | ||
| __type: "Set", | ||
| entries: [...val] | ||
| }; | ||
| if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`; | ||
| if (typeof val === "symbol") return val.toString(); | ||
| if (val !== null && typeof val === "object") { | ||
| if (seen.has(val)) return "[Circular]"; | ||
| seen.add(val); | ||
| } | ||
| return val; | ||
| }, 2); | ||
| } | ||
| /** | ||
| * Format a thrown value for an MCP `isError` text payload. Surfaces the | ||
| * `Error.name`/`message`, and one level of `cause.message` so context | ||
| * isn't dropped silently. | ||
| */ | ||
| function formatMcpError(error) { | ||
| if (!(error instanceof Error)) return String(error); | ||
| const cause = error.cause; | ||
| const causeText = cause instanceof Error ? ` (cause: ${cause.message})` : cause !== void 0 ? ` (cause: ${String(cause)})` : ""; | ||
| return `${error.name}: ${error.message}${causeText}`; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/mcp/to-json-schema.ts | ||
| const FALLBACK_OBJECT_SCHEMA = Object.freeze({ | ||
| type: "object", | ||
| additionalProperties: true | ||
| }); | ||
| /** | ||
| * Convert a valibot return schema to JSON Schema. | ||
| * @internal | ||
| */ | ||
| function valibotReturnToJsonSchema(schema) { | ||
| if (!schema) return void 0; | ||
| try { | ||
| return toJsonSchema(schema); | ||
| } catch { | ||
| return FALLBACK_OBJECT_SCHEMA; | ||
| } | ||
| } | ||
| /** | ||
| * Convert positional RPC args schemas to a single MCP-friendly object | ||
| * schema. When the RPC declares `args: [v.object(...)]`, unwrap the | ||
| * single-object schema directly (nicer agent UX than `{ arg0: {...} }`). | ||
| * | ||
| * Returns `undefined` when there are no args (the MCP SDK treats this | ||
| * as `{ type: 'object', properties: {} }`). | ||
| * @internal | ||
| */ | ||
| function valibotArgsToJsonSchema(args) { | ||
| if (!args || args.length === 0) return { | ||
| schema: { | ||
| type: "object", | ||
| properties: {} | ||
| }, | ||
| unwrapped: false | ||
| }; | ||
| if (args.length === 1) { | ||
| const inner = safeToJsonSchema(args[0]); | ||
| if (isObjectJsonSchema(inner)) return { | ||
| schema: inner, | ||
| unwrapped: true | ||
| }; | ||
| } | ||
| const properties = {}; | ||
| const required = []; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const key = `arg${i}`; | ||
| properties[key] = safeToJsonSchema(args[i]); | ||
| required.push(key); | ||
| } | ||
| return { | ||
| schema: { | ||
| type: "object", | ||
| properties, | ||
| required, | ||
| additionalProperties: false | ||
| }, | ||
| unwrapped: false | ||
| }; | ||
| } | ||
| function safeToJsonSchema(schema) { | ||
| try { | ||
| return toJsonSchema(schema); | ||
| } catch { | ||
| return FALLBACK_OBJECT_SCHEMA; | ||
| } | ||
| } | ||
| function isObjectJsonSchema(value) { | ||
| return !!value && typeof value === "object" && value.type === "object"; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/mcp/build-server.ts | ||
| /** | ||
| * Wire an MCP {@link Server} to a devframe context. Returns the server | ||
| * plus a disposal function for the subscriptions it sets up. The | ||
| * transport is the caller's responsibility — `createMcpServer` connects | ||
| * stdio; tests can connect an {@link InMemoryTransport} instead. | ||
| * | ||
| * @internal | ||
| */ | ||
| function buildMcpServerFromContext(ctx, options) { | ||
| const server = new Server({ | ||
| name: options.serverName, | ||
| version: options.serverVersion | ||
| }, { capabilities: { | ||
| tools: { listChanged: true }, | ||
| resources: { listChanged: true } | ||
| } }); | ||
| registerToolHandlers(server, ctx); | ||
| registerResourceHandlers(server, ctx, options.exposeSharedState); | ||
| const notify = (method) => { | ||
| server.notification({ method }).catch(() => {}); | ||
| }; | ||
| const offManifest = ctx.agent.events.on("agent:manifest:changed", () => { | ||
| notify("notifications/tools/list_changed"); | ||
| notify("notifications/resources/list_changed"); | ||
| }); | ||
| const offKeyAdded = ctx.rpc.sharedState.onKeyAdded(() => { | ||
| notify("notifications/resources/list_changed"); | ||
| }); | ||
| return { | ||
| server, | ||
| dispose: () => { | ||
| offManifest(); | ||
| offKeyAdded(); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Build an MCP server over the agent surface of a devframe definition. | ||
| * Currently supports `stdio` transport only. | ||
| * | ||
| * @experimental The agent-native surface is experimental and may change | ||
| * without a major version bump until it stabilizes. | ||
| */ | ||
| async function createMcpServer(definition, options = {}) { | ||
| const transport = options.transport ?? "stdio"; | ||
| if (transport !== "stdio") throw diagnostics.DF0017({ | ||
| transport, | ||
| reason: "Only stdio transport is supported in this release." | ||
| }); | ||
| const ctx = await createHostContext({ | ||
| cwd: process.cwd(), | ||
| mode: "dev", | ||
| host: { | ||
| mountStatic: () => {}, | ||
| resolveOrigin: () => "mcp://devframe", | ||
| getStorageDir: (scope) => { | ||
| if (scope === "workspace") return join(process.cwd(), ".devframe"); | ||
| if (scope === "project") return join(process.cwd(), `node_modules/.${definition.id}/devframe`); | ||
| return join(homedir(), `.${definition.id}/devframe`); | ||
| } | ||
| } | ||
| }); | ||
| await definition.setup(ctx); | ||
| const { server, dispose } = buildMcpServerFromContext(ctx, { | ||
| serverName: options.serverName ?? `${definition.id} (devframe)`, | ||
| serverVersion: options.serverVersion ?? definition.version ?? "0.0.0", | ||
| exposeSharedState: options.exposeSharedState ?? true | ||
| }); | ||
| const { startStdioTransport } = await import("./transports-BmDVn4SF.mjs"); | ||
| let stop; | ||
| try { | ||
| stop = await startStdioTransport(server); | ||
| } catch (error) { | ||
| const reason = error instanceof Error ? error.message : String(error); | ||
| throw diagnostics.DF0017({ | ||
| transport, | ||
| reason, | ||
| cause: error | ||
| }); | ||
| } | ||
| options.onReady?.({ transport: "stdio" }); | ||
| return { async stop() { | ||
| dispose(); | ||
| await stop(); | ||
| } }; | ||
| } | ||
| function registerToolHandlers(server, ctx) { | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => { | ||
| return { tools: ctx.agent.list().tools.map((tool) => projectTool(tool, ctx)) }; | ||
| }); | ||
| server.setRequestHandler(CallToolRequestSchema, async (request) => { | ||
| const { name, arguments: args } = request.params; | ||
| try { | ||
| const tool = ctx.agent.getTool(name); | ||
| const outputSchema = tool ? tool.outputSchema ?? computeOutputSchema(tool, ctx) : void 0; | ||
| const result = await ctx.agent.invoke(name, args ?? {}); | ||
| return { | ||
| content: [{ | ||
| type: "text", | ||
| text: stringifyForMcp(result) | ||
| }], | ||
| ...outputSchema ? { structuredContent: result } : {} | ||
| }; | ||
| } catch (error) { | ||
| return { | ||
| isError: true, | ||
| content: [{ | ||
| type: "text", | ||
| text: `Error invoking "${name}": ${formatMcpError(error)}` | ||
| }] | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| function registerResourceHandlers(server, ctx, exposeSharedState) { | ||
| server.setRequestHandler(ListResourcesRequestSchema, async () => { | ||
| const resources = ctx.agent.list().resources.map((resource) => ({ | ||
| uri: resource.uri, | ||
| name: resource.name, | ||
| description: resource.description, | ||
| mimeType: resource.mimeType | ||
| })); | ||
| if (exposeSharedState !== false) { | ||
| const filter = typeof exposeSharedState === "function" ? exposeSharedState : () => true; | ||
| for (const key of ctx.rpc.sharedState.keys()) { | ||
| if (!filter(key)) continue; | ||
| resources.push({ | ||
| uri: `devframe://state/${encodeURIComponent(key)}`, | ||
| name: key, | ||
| description: `Shared state: ${key}`, | ||
| mimeType: "application/json" | ||
| }); | ||
| } | ||
| } | ||
| return { resources }; | ||
| }); | ||
| server.setRequestHandler(ReadResourceRequestSchema, async (request) => { | ||
| const { uri } = request.params; | ||
| const parsed = parseResourceUri(uri); | ||
| if (parsed.kind === "resource") { | ||
| const content = await ctx.agent.read(parsed.id); | ||
| return { contents: [{ | ||
| uri, | ||
| mimeType: content.mimeType ?? "application/json", | ||
| text: content.text ?? stringifyForMcp(content.json) | ||
| }] }; | ||
| } | ||
| if (parsed.kind === "state") return { contents: [{ | ||
| uri, | ||
| mimeType: "application/json", | ||
| text: stringifyForMcp((await ctx.rpc.sharedState.get(parsed.key)).value()) | ||
| }] }; | ||
| throw new Error(`[devframe/mcp] unknown resource URI "${uri}"`); | ||
| }); | ||
| } | ||
| function projectTool(tool, ctx) { | ||
| const inputSchema = tool.inputSchema ?? computeInputSchema(tool, ctx); | ||
| const outputSchema = tool.outputSchema ?? computeOutputSchema(tool, ctx); | ||
| return { | ||
| name: tool.id, | ||
| title: tool.title, | ||
| description: tool.description, | ||
| inputSchema, | ||
| ...outputSchema ? { outputSchema } : {}, | ||
| annotations: { | ||
| title: tool.title, | ||
| readOnlyHint: tool.safety === "read", | ||
| destructiveHint: tool.safety === "destructive" | ||
| } | ||
| }; | ||
| } | ||
| function computeInputSchema(tool, ctx) { | ||
| if (tool.kind !== "rpc" || !tool.rpcName) return { | ||
| type: "object", | ||
| properties: {} | ||
| }; | ||
| const def = ctx.rpc.definitions.get(tool.rpcName); | ||
| if (!def) return { | ||
| type: "object", | ||
| properties: {} | ||
| }; | ||
| const args = def.args; | ||
| return valibotArgsToJsonSchema(args).schema; | ||
| } | ||
| function computeOutputSchema(tool, ctx) { | ||
| if (tool.kind !== "rpc" || !tool.rpcName) return void 0; | ||
| const def = ctx.rpc.definitions.get(tool.rpcName); | ||
| if (!def) return void 0; | ||
| return valibotReturnToJsonSchema(def.returns); | ||
| } | ||
| function parseResourceUri(uri) { | ||
| const match = uri.match(/^devframe:\/\/(resource|state)\/(.+)$/); | ||
| if (!match) return { kind: "unknown" }; | ||
| const [, kind, rest] = match; | ||
| const decoded = decodeURIComponent(rest); | ||
| if (kind === "resource") return { | ||
| kind: "resource", | ||
| id: decoded | ||
| }; | ||
| return { | ||
| kind: "state", | ||
| key: decoded | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { createMcpServer as n, buildMcpServerFromContext as t }; |
| import { n as colors } from "./diagnostics-reporter-CsIG85Q5.mjs"; | ||
| import { createBuild } from "./adapters/build.mjs"; | ||
| import { n as resolveDevServerPort, t as createDevServer } from "./dev-BdegDQKt.mjs"; | ||
| import process from "node:process"; | ||
| import cac from "cac"; | ||
| import { safeParse } from "valibot"; | ||
| //#region src/adapters/flags.ts | ||
| /** | ||
| * Identity helper that preserves the literal schema-map type — use this | ||
| * so `InferCliFlags<typeof myFlags>` resolves to the right object shape. | ||
| * | ||
| * ```ts | ||
| * const appFlags = defineCliFlags({ | ||
| * depth: v.pipe(v.number(), v.integer()), | ||
| * config: v.optional(v.string()), | ||
| * }) | ||
| * | ||
| * defineDevframe({ | ||
| * cli: { flags: appFlags }, | ||
| * setup(ctx, info) { | ||
| * const flags = info.flags as InferCliFlags<typeof appFlags> | ||
| * flags.depth // number | ||
| * flags.config // string | undefined | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
| function defineCliFlags(flags) { | ||
| return flags; | ||
| } | ||
| /** | ||
| * Best-effort probe of a valibot schema to decide whether the | ||
| * corresponding CAC option takes a value. Unwraps `optional` / `nullable` | ||
| * / `nullish` / `default` / `pipe` wrappers then matches on the inner | ||
| * type's kind. | ||
| */ | ||
| function getSchemaKind(schema) { | ||
| let current = schema; | ||
| while (current) { | ||
| const kind = current.type; | ||
| if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") { | ||
| current = current.wrapped ?? current.inner; | ||
| continue; | ||
| } | ||
| if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) { | ||
| current = current.pipe[0]; | ||
| continue; | ||
| } | ||
| return kind; | ||
| } | ||
| return "unknown"; | ||
| } | ||
| /** Whether the CAC option for this schema should be a boolean flag. */ | ||
| function isBooleanFlag(schema) { | ||
| return getSchemaKind(schema) === "boolean"; | ||
| } | ||
| /** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */ | ||
| function parseCliFlags(schema, raw) { | ||
| const flags = {}; | ||
| const issues = []; | ||
| for (const [key, fieldSchema] of Object.entries(schema)) { | ||
| const result = safeParse(fieldSchema, raw[key]); | ||
| if (result.success) flags[key] = result.output; | ||
| else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`); | ||
| } | ||
| for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value; | ||
| return issues.length ? { | ||
| flags, | ||
| issues | ||
| } : { flags }; | ||
| } | ||
| function toKebab(camel) { | ||
| return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); | ||
| } | ||
| /** Kebab-case a schema key for CAC option registration. */ | ||
| function flagKeyToOption(camel) { | ||
| return toKebab(camel); | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/cac.ts | ||
| /** | ||
| * Wrap a {@link DevframeDefinition} in a `cac`-powered command-line | ||
| * interface exposing `dev` / `build` / `mcp` subcommands. | ||
| * | ||
| * Requires the optional `cac` peer dependency. | ||
| */ | ||
| function createCac(d, options = {}) { | ||
| const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999; | ||
| const defaultHost = d.cli?.host ?? "localhost"; | ||
| const cli = cac(d.cli?.command ?? d.id); | ||
| 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]"); | ||
| if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) { | ||
| const optionName = flagKeyToOption(key); | ||
| const description = schema.description ?? ""; | ||
| if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description); | ||
| else devCommand.option(`--${optionName} <value>`, description); | ||
| } | ||
| devCommand.action(async (_args, rawFlags) => { | ||
| const flags = resolveTypedFlags(d, rawFlags); | ||
| const host = flags.host ?? defaultHost; | ||
| const port = flags.port ?? await resolveDevServerPort(d, { | ||
| host, | ||
| defaultPort | ||
| }); | ||
| const mcp = flags.mcp; | ||
| await createDevServer(d, { | ||
| host, | ||
| port, | ||
| flags, | ||
| mcp, | ||
| onReady: options.onReady | ||
| }); | ||
| }); | ||
| 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) => { | ||
| await createBuild(d, { | ||
| outDir: flags.outDir, | ||
| base: flags.base, | ||
| pretty: flags.pretty | ||
| }); | ||
| }); | ||
| cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => { | ||
| const { createMcpServer } = await import("./adapters/mcp.mjs"); | ||
| await createMcpServer(d, { | ||
| transport: "stdio", | ||
| onReady: ({ transport }) => { | ||
| console.error(`[devframe] "${d.id}" MCP server ready (${transport})`); | ||
| } | ||
| }); | ||
| }); | ||
| d.cli?.configure?.(cli); | ||
| options.configureCli?.(cli); | ||
| cli.help(); | ||
| cli.version("0.0.0"); | ||
| return { | ||
| cli, | ||
| async parse(argv = process.argv) { | ||
| cli.parse(argv, { run: false }); | ||
| await cli.runMatchedCommand(); | ||
| } | ||
| }; | ||
| } | ||
| function resolveTypedFlags(d, raw) { | ||
| if (!d.cli?.flags) return raw; | ||
| const { flags, issues } = parseCliFlags(d.cli.flags, raw); | ||
| if (issues?.length) { | ||
| for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`); | ||
| process.exit(1); | ||
| } | ||
| return flags; | ||
| } | ||
| //#endregion | ||
| export { defineCliFlags as n, parseCliFlags as r, createCac as t }; |
| import { b as DevframeNodeContext, ht as SharedState } from "./devframe-DfzYvlKI.mjs"; | ||
| //#region src/node/hub-internals/context.d.ts | ||
| interface InternalAnonymousAuthStorage { | ||
| trusted: Record<string, { | ||
| authToken: string; | ||
| ua: string; | ||
| origin: string; | ||
| timestamp: number; | ||
| } | undefined>; | ||
| } | ||
| interface RemoteTokenRecord { | ||
| dockId: string; | ||
| /** Dock URL origin — matched against WS handshake `Origin` header when `originLock` is on. */ | ||
| origin: string; | ||
| originLock: boolean; | ||
| } | ||
| interface DevframeInternalContext { | ||
| storage: { | ||
| auth: SharedState<InternalAnonymousAuthStorage>; | ||
| }; | ||
| /** | ||
| * Revoke an auth token: remove from storage and notify all connected clients | ||
| * using this token that they are no longer trusted. | ||
| */ | ||
| revokeAuthToken: (token: string) => Promise<void>; | ||
| /** | ||
| * Session-only tokens issued to remote-UI iframe docks. Not persisted — | ||
| * regenerated on every dev-server restart. | ||
| */ | ||
| remoteTokens: Map<string, RemoteTokenRecord>; | ||
| allocateRemoteToken: (dockId: string, origin: string, originLock: boolean) => string; | ||
| revokeRemoteToken: (token: string) => void; | ||
| revokeRemoteTokensForDock: (dockId: string) => void; | ||
| /** | ||
| * Returns true if `token` is a valid remote token and, when `originLock` is | ||
| * on, `requestOrigin` matches the recorded dock origin. | ||
| */ | ||
| isRemoteTokenTrusted: (token: string, requestOrigin?: string) => boolean; | ||
| /** | ||
| * Populated by `createWsServer` once the WS port is bound. Consumed by the | ||
| * docks host when enriching remote iframe URLs with a connection descriptor. | ||
| */ | ||
| wsEndpoint?: { | ||
| /** Full `ws://` or `wss://` URL with host and port. */ | ||
| url: string; | ||
| }; | ||
| } | ||
| declare const internalContextMap: WeakMap<DevframeNodeContext, DevframeInternalContext>; | ||
| declare function getInternalContext(context: DevframeNodeContext): DevframeInternalContext; | ||
| //#endregion | ||
| export { internalContextMap as a, getInternalContext as i, InternalAnonymousAuthStorage as n, RemoteTokenRecord as r, DevframeInternalContext as t }; |
| import { DEVFRAME_CONNECTION_META_FILENAME } from "./constants.mjs"; | ||
| import { a as diagnostics } from "./storage-D_Xy9v1l.mjs"; | ||
| import { n as createHostContext, t as createH3DevframeHost } from "./host-h3-SjwRTwkE.mjs"; | ||
| import { i as normalizeHttpServerUrl, t as startHttpAndWs } from "./server-BFsuZI9e.mjs"; | ||
| import { n as resolveBasePath, t as normalizeBasePath } from "./_shared-bWRzeSa0.mjs"; | ||
| import { t as open } from "./open-Deb5xmIT.mjs"; | ||
| import { mountStaticHandler } from "./utils/serve-static.mjs"; | ||
| import { createInteractiveAuth } from "./recipes/interactive-auth.mjs"; | ||
| import { resolve } from "pathe"; | ||
| import process$1 from "node:process"; | ||
| import { networkInterfaces } from "node:os"; | ||
| import { H3 } from "h3"; | ||
| import { createServer } from "node:net"; | ||
| import { joinURL, withBase, withLeadingSlash, withoutLeadingSlash } from "ufo"; | ||
| //#region ../../node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs | ||
| const unsafePorts = /* @__PURE__ */ new Set([ | ||
| 1, | ||
| 7, | ||
| 9, | ||
| 11, | ||
| 13, | ||
| 15, | ||
| 17, | ||
| 19, | ||
| 20, | ||
| 21, | ||
| 22, | ||
| 23, | ||
| 25, | ||
| 37, | ||
| 42, | ||
| 43, | ||
| 53, | ||
| 69, | ||
| 77, | ||
| 79, | ||
| 87, | ||
| 95, | ||
| 101, | ||
| 102, | ||
| 103, | ||
| 104, | ||
| 109, | ||
| 110, | ||
| 111, | ||
| 113, | ||
| 115, | ||
| 117, | ||
| 119, | ||
| 123, | ||
| 135, | ||
| 137, | ||
| 139, | ||
| 143, | ||
| 161, | ||
| 179, | ||
| 389, | ||
| 427, | ||
| 465, | ||
| 512, | ||
| 513, | ||
| 514, | ||
| 515, | ||
| 526, | ||
| 530, | ||
| 531, | ||
| 532, | ||
| 540, | ||
| 548, | ||
| 554, | ||
| 556, | ||
| 563, | ||
| 587, | ||
| 601, | ||
| 636, | ||
| 989, | ||
| 990, | ||
| 993, | ||
| 995, | ||
| 1719, | ||
| 1720, | ||
| 1723, | ||
| 2049, | ||
| 3659, | ||
| 4045, | ||
| 5060, | ||
| 5061, | ||
| 6e3, | ||
| 6566, | ||
| 6665, | ||
| 6666, | ||
| 6667, | ||
| 6668, | ||
| 6669, | ||
| 6697, | ||
| 10080 | ||
| ]); | ||
| function isUnsafePort(port) { | ||
| return unsafePorts.has(port); | ||
| } | ||
| function isSafePort(port) { | ||
| return !isUnsafePort(port); | ||
| } | ||
| var GetPortError = class extends Error { | ||
| constructor(message, opts) { | ||
| super(message, opts); | ||
| this.message = message; | ||
| } | ||
| name = "GetPortError"; | ||
| }; | ||
| function _log(verbose, message) { | ||
| if (verbose) console.log(`[get-port] ${message}`); | ||
| } | ||
| function _generateRange(from, to) { | ||
| if (to < from) return []; | ||
| const r = []; | ||
| for (let index = from; index <= to; index++) r.push(index); | ||
| return r; | ||
| } | ||
| function _tryPort(port, host) { | ||
| return new Promise((resolve) => { | ||
| const server = createServer(); | ||
| server.unref(); | ||
| server.on("error", () => { | ||
| resolve(false); | ||
| }); | ||
| server.listen({ | ||
| port, | ||
| host | ||
| }, () => { | ||
| const { port: port2 } = server.address(); | ||
| server.close(() => { | ||
| resolve(isSafePort(port2) && port2); | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
| function _getLocalHosts(additional) { | ||
| const hosts = new Set(additional); | ||
| 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); | ||
| return [...hosts]; | ||
| } | ||
| async function _findPort(ports, host) { | ||
| for (const port of ports) { | ||
| const r = await _tryPort(port, host); | ||
| if (r) return r; | ||
| } | ||
| } | ||
| function _fmtOnHost(hostname) { | ||
| return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host"; | ||
| } | ||
| const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(?<!-)$/; | ||
| function _validateHostname(hostname, _public, verbose) { | ||
| if (hostname && !HOSTNAME_RE.test(hostname)) { | ||
| const fallbackHost = _public ? "0.0.0.0" : "127.0.0.1"; | ||
| _log(verbose, `Invalid hostname: ${JSON.stringify(hostname)}. Using ${JSON.stringify(fallbackHost)} as fallback.`); | ||
| return fallbackHost; | ||
| } | ||
| return hostname; | ||
| } | ||
| async function getPort(_userOptions = {}) { | ||
| if (typeof _userOptions === "number" || typeof _userOptions === "string") _userOptions = { port: Number.parseInt(_userOptions + "") || 0 }; | ||
| const _port = Number(_userOptions.port ?? process.env.PORT); | ||
| const _userSpecifiedAnyPort = Boolean(_userOptions.port || _userOptions.ports?.length || _userOptions.portRange?.length); | ||
| const options = { | ||
| random: _port === 0, | ||
| ports: [], | ||
| portRange: [], | ||
| alternativePortRange: _userSpecifiedAnyPort ? [] : [3e3, 3100], | ||
| verbose: false, | ||
| ..._userOptions, | ||
| port: _port, | ||
| host: _validateHostname(_userOptions.host ?? process.env.HOST, _userOptions.public, _userOptions.verbose) | ||
| }; | ||
| if (options.random && !_userSpecifiedAnyPort) return getRandomPort(options.host); | ||
| const portsToCheck = [ | ||
| options.port, | ||
| ...options.ports, | ||
| ..._generateRange(...options.portRange) | ||
| ].filter((port) => { | ||
| if (!port) return false; | ||
| if (!isSafePort(port)) { | ||
| _log(options.verbose, `Ignoring unsafe port: ${port}`); | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| if (portsToCheck.length === 0) portsToCheck.push(3e3); | ||
| let availablePort = await _findPort(portsToCheck, options.host); | ||
| if (!availablePort && options.alternativePortRange.length > 0) { | ||
| availablePort = await _findPort(_generateRange(...options.alternativePortRange), options.host); | ||
| if (portsToCheck.length > 0) { | ||
| let message = `Unable to find an available port (tried ${portsToCheck.join("-")} ${_fmtOnHost(options.host)}).`; | ||
| if (availablePort) message += ` Using alternative port ${availablePort}.`; | ||
| _log(options.verbose, message); | ||
| } | ||
| } | ||
| if (!availablePort && _userOptions.random !== false) { | ||
| availablePort = await getRandomPort(options.host); | ||
| if (availablePort) _log(options.verbose, `Using random port ${availablePort}`); | ||
| } | ||
| if (!availablePort) { | ||
| const triedRanges = [ | ||
| options.port, | ||
| options.portRange.join("-"), | ||
| options.alternativePortRange.join("-") | ||
| ].filter(Boolean).join(", "); | ||
| throw new GetPortError(`Unable to find an available port ${_fmtOnHost(options.host)} (tried ${triedRanges})`); | ||
| } | ||
| return availablePort; | ||
| } | ||
| async function getRandomPort(host) { | ||
| const port = await checkPort(0, host); | ||
| if (port === false) throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`); | ||
| return port; | ||
| } | ||
| async function checkPort(port, host = process.env.HOST, verbose) { | ||
| if (!host) host = _getLocalHosts([void 0, "0.0.0.0"]); | ||
| if (!Array.isArray(host)) return _tryPort(port, host); | ||
| for (const _host of host) { | ||
| const _port = await _tryPort(port, _host); | ||
| if (_port === false) { | ||
| if (port < 1024 && verbose) _log(verbose, `Unable to listen to the privileged port ${port} ${_fmtOnHost(_host)}`); | ||
| return false; | ||
| } | ||
| if (port === 0 && _port !== 0) port = _port; | ||
| } | ||
| return port; | ||
| } | ||
| //#endregion | ||
| //#region src/adapters/dev.ts | ||
| const DEFAULT_PORT = 9999; | ||
| /** | ||
| * Resolve the listening port for {@link createDevServer}, honoring the | ||
| * definition's `cli.port` / `cli.portRange` / `cli.random` settings. | ||
| * Exposed separately so authors who run their own argv parsing can | ||
| * resolve a port up-front (to print it, log it, etc.) before starting | ||
| * the server. | ||
| */ | ||
| async function resolveDevServerPort(def, options = {}) { | ||
| const host = options.host ?? def.cli?.host ?? "localhost"; | ||
| const portOptions = { | ||
| port: options.defaultPort ?? def.cli?.port ?? DEFAULT_PORT, | ||
| host | ||
| }; | ||
| if (def.cli?.portRange) portOptions.portRange = def.cli.portRange; | ||
| if (def.cli?.random) portOptions.random = def.cli.random; | ||
| return getPort(portOptions); | ||
| } | ||
| /** | ||
| * Start a devframe dev server for a {@link DevframeDefinition} — | ||
| * h3 + WebSocket RPC + (optionally) the author's SPA mounted at the | ||
| * resolved base path. | ||
| * | ||
| * When `distDir` is omitted (and `def.cli?.distDir` is unset) the | ||
| * server runs in **bridge mode**: only `__connection.json` and the WS | ||
| * endpoint are mounted, with no SPA mount. The SPA is expected to be | ||
| * hosted elsewhere (e.g. by a parent Vite/Nuxt dev server) — see | ||
| * `viteDevBridge({ devMiddleware })`. | ||
| * | ||
| * Returns the underlying {@link StartedServer} handle so callers can | ||
| * close it gracefully (SIGINT, hot-reload, test teardown). | ||
| * | ||
| * Use this directly when integrating devframe into an existing CLI | ||
| * framework (commander, yargs, hand-rolled CAC). For the all-in-one | ||
| * `dev` / `build` / `mcp` shell, reach for {@link createCac} instead. | ||
| */ | ||
| async function createDevServer(def, options = {}) { | ||
| const distDir = options.distDir ?? def.cli?.distDir; | ||
| const host = options.host ?? def.cli?.host ?? "localhost"; | ||
| const port = options.port ?? await resolveDevServerPort(def, { host }); | ||
| const flags = options.flags ?? {}; | ||
| const basePath = options.basePath ? normalizeBasePath(options.basePath) : resolveBasePath(def, "standalone"); | ||
| const app = options.app ?? new H3(); | ||
| const h3Host = createH3DevframeHost({ | ||
| origin: normalizeHttpServerUrl(host, port), | ||
| appName: def.id, | ||
| mount: (base, dir) => { | ||
| mountStaticHandler(app, base, dir); | ||
| } | ||
| }); | ||
| const ctx = await createHostContext({ | ||
| cwd: process$1.cwd(), | ||
| mode: "dev", | ||
| host: h3Host | ||
| }); | ||
| const setupInfo = { flags }; | ||
| await def.setup(ctx, setupInfo); | ||
| const mcpConfig = resolveMcpConfig(options.mcp ?? def.cli?.mcp); | ||
| let mcpDispose; | ||
| let mcpMeta; | ||
| if (mcpConfig) { | ||
| const mcpRoute = withoutLeadingSlash(mcpConfig.path ?? "__mcp"); | ||
| const mcpPath = joinURL(basePath, mcpRoute); | ||
| let mountMcpHttp; | ||
| try { | ||
| ({mountMcpHttp} = await import("./http-BaCZYhIR.mjs")); | ||
| } catch (error) { | ||
| const reason = error instanceof Error ? error.message : String(error); | ||
| throw diagnostics.DF0017({ | ||
| transport: "http", | ||
| reason, | ||
| cause: error | ||
| }); | ||
| } | ||
| mcpDispose = mountMcpHttp(app, ctx, mcpPath, { | ||
| serverName: `${def.id} (devframe)`, | ||
| serverVersion: def.version ?? "0.0.0", | ||
| exposeSharedState: true, | ||
| allowedOrigins: mcpConfig.allowedOrigins | ||
| }).dispose; | ||
| mcpMeta = { path: mcpRoute }; | ||
| } | ||
| const { bindPath, wsPort, meta } = resolveWsConnection(def, options, basePath); | ||
| const connectionMetaPath = joinURL(basePath, DEVFRAME_CONNECTION_META_FILENAME); | ||
| app.use(connectionMetaPath, () => ({ | ||
| backend: "websocket", | ||
| websocket: meta, | ||
| ...mcpMeta ? { mcp: mcpMeta } : {} | ||
| })); | ||
| if (distDir) mountStaticHandler(app, basePath, resolve(distDir)); | ||
| const authOption = flags.auth === false ? false : options.auth !== void 0 ? options.auth : def.cli?.auth; | ||
| let authHandler; | ||
| let resolvedAuth; | ||
| if (authOption === false) resolvedAuth = false; | ||
| else if (typeof authOption === "object") { | ||
| authHandler = authOption; | ||
| resolvedAuth = authOption; | ||
| } else { | ||
| authHandler = createInteractiveAuth(ctx); | ||
| resolvedAuth = authHandler; | ||
| } | ||
| const started = await startHttpAndWs({ | ||
| context: ctx, | ||
| host, | ||
| port, | ||
| app, | ||
| path: bindPath, | ||
| wsPort, | ||
| auth: resolvedAuth, | ||
| onReady: async (info) => { | ||
| authHandler?.printBanner(); | ||
| await options.onReady?.(info); | ||
| await maybeOpenBrowser(def, flags, `${info.origin}${basePath}`, options.openBrowser, authHandler); | ||
| } | ||
| }); | ||
| if (mcpDispose) { | ||
| const closeServer = started.close; | ||
| started.close = async () => { | ||
| await mcpDispose(); | ||
| await closeServer(); | ||
| }; | ||
| } | ||
| return started; | ||
| } | ||
| /** | ||
| * Normalize the `cli.mcp` / `mcp` option (`boolean | McpRouteOptions`) into | ||
| * concrete options, or `undefined` when the MCP route is disabled. | ||
| */ | ||
| function resolveMcpConfig(mcp) { | ||
| if (!mcp) return void 0; | ||
| return mcp === true ? {} : mcp; | ||
| } | ||
| /** | ||
| * Resolve the three WS connection scenarios from the definition / call-site | ||
| * config into a concrete server bind path, optional dedicated port, and the | ||
| * `__connection.json` descriptor the browser resolves. | ||
| */ | ||
| function resolveWsConnection(def, options, basePath) { | ||
| const ws = options.ws ?? def.cli?.ws ?? {}; | ||
| const route = withoutLeadingSlash(ws.route ?? "__devframe_ws"); | ||
| if (ws.url) return { | ||
| bindPath: joinURL(basePath, route), | ||
| wsPort: void 0, | ||
| meta: ws.url | ||
| }; | ||
| if (ws.port != null) return { | ||
| bindPath: withLeadingSlash(route), | ||
| wsPort: ws.port, | ||
| meta: { | ||
| port: ws.port, | ||
| path: route | ||
| } | ||
| }; | ||
| return { | ||
| bindPath: joinURL(basePath, route), | ||
| wsPort: void 0, | ||
| meta: { path: route } | ||
| }; | ||
| } | ||
| async function maybeOpenBrowser(def, flags, origin, override, authHandler) { | ||
| const flagsOpen = flags.open; | ||
| const cliOpen = def.cli?.open; | ||
| const resolved = override ?? flagsOpen ?? cliOpen; | ||
| if (resolved === void 0 || resolved === false) return; | ||
| const target = typeof resolved === "string" ? withBase(resolved, origin) : origin; | ||
| const authorizedTarget = authHandler?.buildOpenUrl?.(target) ?? target; | ||
| try { | ||
| await open(authorizedTarget); | ||
| } catch {} | ||
| } | ||
| //#endregion | ||
| export { resolveDevServerPort as n, createDevServer as t }; |
Sorry, the diff of this file is too big to display
| import { isAllowedOrigin } from "./rpc/transports/ws-server.mjs"; | ||
| import { t as buildMcpServerFromContext } from "./build-server-CBAxmnC8.mjs"; | ||
| import { randomUUID } from "node:crypto"; | ||
| import { defineHandler } from "h3"; | ||
| import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"; | ||
| import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; | ||
| //#region src/adapters/mcp/http.ts | ||
| /** | ||
| * Mount an MCP Streamable-HTTP endpoint on an h3 app at `path`. | ||
| * | ||
| * Each MCP session gets its own {@link WebStandardStreamableHTTPServerTransport} | ||
| * and MCP server (built from the shared, live `ctx` via | ||
| * `buildMcpServerFromContext`), correlated by the `Mcp-Session-Id` header: | ||
| * an `initialize` POST spins up a session; later requests route to it; a | ||
| * `DELETE` (or client disconnect) tears it down. | ||
| * | ||
| * The transport is web-standard — its `handleRequest` takes the h3 event's | ||
| * web `Request` and returns a web `Response` (an SSE `ReadableStream` body | ||
| * for the server→client stream). We copy that response onto `event.res` and | ||
| * return its body rather than returning the `Response` object directly, so a | ||
| * legitimate MCP 404 (unknown session) isn't swallowed by h3's | ||
| * "Response-with-404 falls through to the next handler" rule (which would | ||
| * otherwise hand the request to the SPA static catch-all). | ||
| * | ||
| * @experimental | ||
| */ | ||
| function mountMcpHttp(app, ctx, path, options) { | ||
| const sessions = /* @__PURE__ */ new Map(); | ||
| const allowedOrigins = options.allowedOrigins; | ||
| function drop(sessionId) { | ||
| const session = sessions.get(sessionId); | ||
| if (!session) return; | ||
| sessions.delete(sessionId); | ||
| session.dispose(); | ||
| } | ||
| async function createSession() { | ||
| let session; | ||
| const transport = new WebStandardStreamableHTTPServerTransport({ | ||
| sessionIdGenerator: () => randomUUID(), | ||
| onsessioninitialized: (id) => { | ||
| sessions.set(id, session); | ||
| }, | ||
| onsessionclosed: (id) => { | ||
| drop(id); | ||
| } | ||
| }); | ||
| const { server, dispose } = buildMcpServerFromContext(ctx, { | ||
| serverName: options.serverName, | ||
| serverVersion: options.serverVersion, | ||
| exposeSharedState: options.exposeSharedState | ||
| }); | ||
| session = { | ||
| transport, | ||
| dispose: async () => { | ||
| dispose(); | ||
| await server.close(); | ||
| } | ||
| }; | ||
| transport.onclose = () => { | ||
| if (transport.sessionId) drop(transport.sessionId); | ||
| }; | ||
| await server.connect(transport); | ||
| return session; | ||
| } | ||
| app.use(path, defineHandler(async (event) => { | ||
| const req = event.req; | ||
| const origin = req.headers.get("origin") ?? void 0; | ||
| if (allowedOrigins !== false && !isAllowedOrigin(origin, allowedOrigins ?? [])) { | ||
| event.res.status = 403; | ||
| return "Forbidden: origin not allowed"; | ||
| } | ||
| const sessionId = req.headers.get("mcp-session-id") ?? void 0; | ||
| let session = sessionId ? sessions.get(sessionId) : void 0; | ||
| if (!session && req.method === "POST") { | ||
| let body; | ||
| try { | ||
| body = await req.json(); | ||
| } catch { | ||
| body = void 0; | ||
| } | ||
| if (!sessionId && isInitializeRequest(body)) session = await createSession(); | ||
| else { | ||
| event.res.status = sessionId ? 404 : 400; | ||
| return sessionId ? "Not Found: unknown MCP session" : "Bad Request: no valid session ID and not an initialize request"; | ||
| } | ||
| return respond(event, await session.transport.handleRequest(req, { parsedBody: body })); | ||
| } | ||
| if (!session) { | ||
| event.res.status = sessionId ? 404 : 400; | ||
| return sessionId ? "Not Found: unknown MCP session" : "Bad Request: missing MCP session ID"; | ||
| } | ||
| return respond(event, await session.transport.handleRequest(req)); | ||
| })); | ||
| return { dispose: async () => { | ||
| const live = [...sessions.values()]; | ||
| sessions.clear(); | ||
| await Promise.all(live.map((session) => session.dispose())); | ||
| } }; | ||
| } | ||
| /** | ||
| * Copy a web `Response` from the MCP transport onto the h3 event's response | ||
| * and return its body. Returning the body (a `ReadableStream` or `null`) | ||
| * rather than the `Response` object avoids h3's 404-fall-through behavior. | ||
| */ | ||
| function respond(event, response) { | ||
| event.res.status = response.status; | ||
| event.res.statusText = response.statusText; | ||
| response.headers.forEach((value, key) => { | ||
| event.res.headers.set(key, value); | ||
| }); | ||
| return response.body ?? ""; | ||
| } | ||
| //#endregion | ||
| export { mountMcpHttp }; |
| import { W as DevframeNodeRpcSession, b as DevframeNodeContext, ht as SharedState } from "./devframe-DfzYvlKI.mjs"; | ||
| import { n as InternalAnonymousAuthStorage } from "./context-FonV8enL.mjs"; | ||
| //#region src/node/auth/revoke.d.ts | ||
| /** | ||
| * Flip `isTrusted` to false on any live WS clients connected with `token` | ||
| * and broadcast the `auth:revoked` event so they can react. | ||
| * | ||
| * Shared between persisted-auth revocation and remote-dock token revocation. | ||
| */ | ||
| declare function revokeActiveConnectionsForToken(context: DevframeNodeContext, token: string): Promise<void>; | ||
| /** | ||
| * Revoke an auth token: remove from storage and notify all connected clients | ||
| * using this token that they are no longer trusted. | ||
| */ | ||
| declare function revokeAuthToken(context: DevframeNodeContext, storage: SharedState<InternalAnonymousAuthStorage>, token: string): Promise<void>; | ||
| //#endregion | ||
| //#region src/node/auth/state.d.ts | ||
| /** | ||
| * The current one-time authentication code. Display this to the user (e.g. in | ||
| * the dev-server terminal) so they can type it into the browser to authenticate. | ||
| */ | ||
| declare function getTempAuthCode(): string; | ||
| /** | ||
| * Rotate the authentication code, resetting its expiry window and failed-attempt | ||
| * counter. Call this when a new authentication flow begins (e.g. when an | ||
| * untrusted client starts authenticating) so the displayed code is freshly | ||
| * valid for its full TTL. | ||
| */ | ||
| declare function refreshTempAuthCode(): string; | ||
| /** | ||
| * Build a "magic link" authentication URL that embeds a one-time code (OTP) as | ||
| * a query parameter. Opening it authenticates the client without typing — print | ||
| * it on startup (devframe stays headless, so the host prints its own banner). | ||
| * Defaults to the current code; the link is subject to the same TTL. | ||
| */ | ||
| declare function buildOtpAuthUrl(baseUrl: string, code?: string): string; | ||
| /** | ||
| * Re-authenticate a connection that presents a previously-issued bearer token. | ||
| * Returns `true` and marks the session trusted when the token is known. | ||
| * | ||
| * Used by the `anonymous:devframe:auth` handler so a client that already | ||
| * authenticated (token persisted in the browser) is trusted on reconnect | ||
| * without entering the code again. | ||
| */ | ||
| declare function verifyAuthToken(token: string, session: DevframeNodeRpcSession, storage: SharedState<InternalAnonymousAuthStorage>): boolean; | ||
| /** | ||
| * Exchange a one-time authentication code for a fresh, node-issued bearer token. | ||
| * | ||
| * On success this mints a high-entropy token, records it in the trusted store, | ||
| * marks the calling session trusted, rotates the code, and returns the token | ||
| * for the client to persist. Returns `null` on any failure. | ||
| * | ||
| * Because the code is short and human-typed, verification is hardened against | ||
| * brute force: it enforces a time-to-live, compares in constant time, and | ||
| * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an | ||
| * attacker cannot keep guessing against the same code. | ||
| */ | ||
| declare function exchangeTempAuthCode(code: string, session: DevframeNodeRpcSession, info: { | ||
| ua: string; | ||
| origin: string; | ||
| }, storage: SharedState<InternalAnonymousAuthStorage>): string | null; | ||
| //#endregion | ||
| export { verifyAuthToken as a, refreshTempAuthCode as i, exchangeTempAuthCode as n, revokeActiveConnectionsForToken as o, getTempAuthCode as r, revokeAuthToken as s, buildOtpAuthUrl as t }; |
| import { createRequire } from "node:module"; | ||
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports); | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))(); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js | ||
| var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| let p = process || {}; | ||
| let argv = p.argv || []; | ||
| let env = p.env || {}; | ||
| let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI); | ||
| let formatter = (open, close, replace = open) => (input) => { | ||
| let string = "" + input, index = string.indexOf(close, open.length); | ||
| return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close; | ||
| }; | ||
| let replaceClose = (string, close, replace, index) => { | ||
| let result = "", cursor = 0; | ||
| do { | ||
| result += string.substring(cursor, index) + replace; | ||
| cursor = index + close.length; | ||
| index = string.indexOf(close, cursor); | ||
| } while (~index); | ||
| return result + string.substring(cursor); | ||
| }; | ||
| let createColors = (enabled = isColorSupported) => { | ||
| let f = enabled ? formatter : () => String; | ||
| return { | ||
| isColorSupported: enabled, | ||
| reset: f("\x1B[0m", "\x1B[0m"), | ||
| bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"), | ||
| dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"), | ||
| italic: f("\x1B[3m", "\x1B[23m"), | ||
| underline: f("\x1B[4m", "\x1B[24m"), | ||
| inverse: f("\x1B[7m", "\x1B[27m"), | ||
| hidden: f("\x1B[8m", "\x1B[28m"), | ||
| strikethrough: f("\x1B[9m", "\x1B[29m"), | ||
| black: f("\x1B[30m", "\x1B[39m"), | ||
| red: f("\x1B[31m", "\x1B[39m"), | ||
| green: f("\x1B[32m", "\x1B[39m"), | ||
| yellow: f("\x1B[33m", "\x1B[39m"), | ||
| blue: f("\x1B[34m", "\x1B[39m"), | ||
| magenta: f("\x1B[35m", "\x1B[39m"), | ||
| cyan: f("\x1B[36m", "\x1B[39m"), | ||
| white: f("\x1B[37m", "\x1B[39m"), | ||
| gray: f("\x1B[90m", "\x1B[39m"), | ||
| bgBlack: f("\x1B[40m", "\x1B[49m"), | ||
| bgRed: f("\x1B[41m", "\x1B[49m"), | ||
| bgGreen: f("\x1B[42m", "\x1B[49m"), | ||
| bgYellow: f("\x1B[43m", "\x1B[49m"), | ||
| bgBlue: f("\x1B[44m", "\x1B[49m"), | ||
| bgMagenta: f("\x1B[45m", "\x1B[49m"), | ||
| bgCyan: f("\x1B[46m", "\x1B[49m"), | ||
| bgWhite: f("\x1B[47m", "\x1B[49m"), | ||
| blackBright: f("\x1B[90m", "\x1B[39m"), | ||
| redBright: f("\x1B[91m", "\x1B[39m"), | ||
| greenBright: f("\x1B[92m", "\x1B[39m"), | ||
| yellowBright: f("\x1B[93m", "\x1B[39m"), | ||
| blueBright: f("\x1B[94m", "\x1B[39m"), | ||
| magentaBright: f("\x1B[95m", "\x1B[39m"), | ||
| cyanBright: f("\x1B[96m", "\x1B[39m"), | ||
| whiteBright: f("\x1B[97m", "\x1B[39m"), | ||
| bgBlackBright: f("\x1B[100m", "\x1B[49m"), | ||
| bgRedBright: f("\x1B[101m", "\x1B[49m"), | ||
| bgGreenBright: f("\x1B[102m", "\x1B[49m"), | ||
| bgYellowBright: f("\x1B[103m", "\x1B[49m"), | ||
| bgBlueBright: f("\x1B[104m", "\x1B[49m"), | ||
| bgMagentaBright: f("\x1B[105m", "\x1B[49m"), | ||
| bgCyanBright: f("\x1B[106m", "\x1B[49m"), | ||
| bgWhiteBright: f("\x1B[107m", "\x1B[49m") | ||
| }; | ||
| }; | ||
| module.exports = createColors(); | ||
| module.exports.createColors = createColors; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/quote.js | ||
| var require_quote = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** @import { ControlOperator } from './parse' */ | ||
| /** @type {ControlOperator['op'][]} */ | ||
| var OPS = [ | ||
| "||", | ||
| "&&", | ||
| ";;", | ||
| "|&", | ||
| "<(", | ||
| "<<<", | ||
| ">>", | ||
| ">&", | ||
| "<&", | ||
| "&", | ||
| ";", | ||
| "(", | ||
| ")", | ||
| "|", | ||
| "<", | ||
| ">" | ||
| ]; | ||
| var LINE_TERMINATORS = /[\n\r\u2028\u2029]/; | ||
| var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g; | ||
| /** @type {typeof import('./quote')} */ | ||
| module.exports = function quote(xs) { | ||
| return xs.map(function(s) { | ||
| if (s === "") return "''"; | ||
| if (s && typeof s === "object") { | ||
| if ("op" in s && s.op === "glob") { | ||
| if (typeof s.pattern !== "string") throw new TypeError("glob token requires a string `pattern`"); | ||
| if (LINE_TERMINATORS.test(s.pattern)) throw new TypeError("glob `pattern` must not contain line terminators"); | ||
| return s.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&"); | ||
| } | ||
| if ("op" in s && typeof s.op === "string") { | ||
| if (OPS.indexOf(s.op) < 0) throw new TypeError("invalid `op` value: " + JSON.stringify(s.op)); | ||
| return s.op.replace(/[\s\S]/g, "\\$&"); | ||
| } | ||
| if ("comment" in s && typeof s.comment === "string") { | ||
| if (LINE_TERMINATORS.test(s.comment)) throw new TypeError("`comment` must not contain line terminators"); | ||
| return "#" + s.comment; | ||
| } | ||
| throw new TypeError("unrecognized object token shape"); | ||
| } | ||
| if (/["\s\\]/.test(s) && !/'/.test(s)) return "'" + s.replace(/(['])/g, "\\$1") + "'"; | ||
| if (/["'\s]/.test(s)) return "\"" + s.replace(/(["\\$`!])/g, "\\$1") + "\""; | ||
| return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}~])/g, "$1\\$2"); | ||
| }).join(" "); | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/parse.js | ||
| var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** | ||
| * @import { | ||
| * ControlOperator, | ||
| * Env, | ||
| * GlobPattern, | ||
| * ParseEntry, | ||
| * } from './parse' */ | ||
| var CONTROL = "(?:" + [ | ||
| "\\|\\|", | ||
| "\\&\\&", | ||
| ";;", | ||
| "\\|\\&", | ||
| "\\<\\(", | ||
| "\\<\\<\\<", | ||
| ">>", | ||
| ">\\&", | ||
| "<\\&", | ||
| "[&;()|<>]" | ||
| ].join("|") + ")"; | ||
| var controlRE = new RegExp("^" + CONTROL + "$"); | ||
| var META = "|&;()<> \\t"; | ||
| var SINGLE_QUOTE = "'([^']*?)'"; | ||
| var DOUBLE_QUOTE = "\"((\\\\\"|[^\"])*?)\""; | ||
| var hash = /^#$/; | ||
| var SQ = "'"; | ||
| var DQ = "\""; | ||
| var DS = "$"; | ||
| var TOKEN = ""; | ||
| var mult = 4294967296; | ||
| for (var i = 0; i < 4; i++) TOKEN += (mult * Math.random()).toString(16); | ||
| var startsWithToken = new RegExp("^" + TOKEN); | ||
| /** | ||
| * @param {string} s | ||
| * @param {RegExp} r | ||
| */ | ||
| function matchAll(s, r) { | ||
| var origIndex = r.lastIndex; | ||
| var matches = []; | ||
| var matchObj; | ||
| while (matchObj = r.exec(s)) { | ||
| matches[matches.length] = matchObj; | ||
| if (r.lastIndex === matchObj.index) r.lastIndex += 1; | ||
| } | ||
| r.lastIndex = origIndex; | ||
| return matches; | ||
| } | ||
| /** | ||
| * @param {Env} env | ||
| * @param {string} pre | ||
| * @param {string} key | ||
| */ | ||
| function getVar(env, pre, key) { | ||
| var r = typeof env === "function" ? env(key) : env[key]; | ||
| if (typeof r === "undefined" && key != "") r = ""; | ||
| else if (typeof r === "undefined") r = "$"; | ||
| if (typeof r === "object") return pre + TOKEN + JSON.stringify(r) + TOKEN; | ||
| return pre + r; | ||
| } | ||
| /** | ||
| * @param {string} string | ||
| * @param {Env} [env] | ||
| * @param {{ escape?: string, splitUnquoted?: boolean | string }} [opts] | ||
| * @returns {ParseEntry[]} | ||
| */ | ||
| function parseInternal(string, env, opts) { | ||
| if (!opts) opts = {}; | ||
| var BS = opts.escape || "\\"; | ||
| var ifs = opts.splitUnquoted === true ? " \n" : typeof opts.splitUnquoted === "string" ? opts.splitUnquoted : ""; | ||
| var BAREWORD = "(\\" + BS + "['\"" + META + "]|[^\\s'\"" + META + "])+"; | ||
| var matches = matchAll(string, new RegExp(["(" + CONTROL + ")", "(" + BAREWORD + "|" + DOUBLE_QUOTE + "|" + SINGLE_QUOTE + ")+"].join("|"), "g")); | ||
| if (matches.length === 0) return []; | ||
| if (!env) env = {}; | ||
| var commented = false; | ||
| return matches.map(function(match) { | ||
| var s = match[0]; | ||
| if (!s || commented) return; | ||
| if (controlRE.test(s)) return { op: s }; | ||
| /** @type {string | boolean} */ | ||
| var quote = false; | ||
| var esc = false; | ||
| var out = ""; | ||
| /** @type {string[]} */ | ||
| var words = []; | ||
| var sawQuote = false; | ||
| /** @type {number | null} */ | ||
| var pendingNw = null; | ||
| var isGlob = false; | ||
| /** @type {number} */ | ||
| var i; | ||
| function parseEnvVar() { | ||
| i += 1; | ||
| /** @type {number | RegExpMatchArray | null} */ | ||
| var varend; | ||
| /** @type {string} */ | ||
| var varname; | ||
| var char = s.charAt(i); | ||
| if (char === "{") { | ||
| i += 1; | ||
| if (s.charAt(i) === "}") throw new Error("Bad substitution: " + s.slice(i - 2, i + 1)); | ||
| var depth = 1; | ||
| varend = i; | ||
| while (depth > 0 && varend < s.length) { | ||
| if (s.charAt(varend) === "{" && s.charAt(varend - 1) === "$") depth += 1; | ||
| else if (s.charAt(varend) === "}") depth -= 1; | ||
| varend += 1; | ||
| } | ||
| if (depth !== 0) throw new Error("Bad substitution: " + s.slice(i)); | ||
| varend -= 1; | ||
| varname = s.slice(i, varend); | ||
| i = varend; | ||
| } else if (/[*@#?$!_-]/.test(char)) { | ||
| varname = char; | ||
| i += 1; | ||
| } else { | ||
| var slicedFromI = s.slice(i); | ||
| varend = slicedFromI.match(/[^\w\d_]/); | ||
| if (!varend) { | ||
| varname = slicedFromI; | ||
| i = s.length; | ||
| } else { | ||
| varname = slicedFromI.slice(0, varend.index); | ||
| i += varend.index - 1; | ||
| } | ||
| } | ||
| return getVar(env, "", varname); | ||
| } | ||
| function flushRun() { | ||
| if (pendingNw === null) return; | ||
| if (pendingNw === 0) { | ||
| if (out !== "") { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| } | ||
| } else { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| for (var fe = 1; fe < pendingNw; fe += 1) words[words.length] = ""; | ||
| } | ||
| pendingNw = null; | ||
| } | ||
| for (i = 0; i < s.length; i++) { | ||
| var c = s.charAt(i); | ||
| if (ifs && c !== DS) flushRun(); | ||
| isGlob = isGlob || !quote && (c === "*" || c === "?"); | ||
| if (esc) { | ||
| out += c; | ||
| esc = false; | ||
| } else if (quote) if (c === quote) quote = false; | ||
| else if (quote == SQ) out += c; | ||
| else if (c === BS) { | ||
| i += 1; | ||
| c = s.charAt(i); | ||
| if (c === DQ || c === BS || c === DS) out += c; | ||
| else out += BS + c; | ||
| } else if (c === DS) out += parseEnvVar(); | ||
| else out += c; | ||
| else if (c === DQ || c === SQ) { | ||
| quote = c; | ||
| sawQuote = true; | ||
| } else if (controlRE.test(c)) return { op: s }; | ||
| else if (hash.test(c)) { | ||
| commented = true; | ||
| var commentObj = { comment: string.slice(match.index + i + 1) }; | ||
| if (out.length) return [out, commentObj]; | ||
| return [commentObj]; | ||
| } else if (c === BS) esc = true; | ||
| else if (c === DS) { | ||
| var value = parseEnvVar(); | ||
| if (!ifs) out += value; | ||
| else for (var vi = 0; vi < value.length; vi += 1) { | ||
| var vc = value.charAt(vi); | ||
| if (ifs.indexOf(vc) < 0) { | ||
| flushRun(); | ||
| out += vc; | ||
| } else if (pendingNw === null) pendingNw = vc === " " || vc === " " || vc === "\n" ? 0 : 1; | ||
| else if (vc !== " " && vc !== " " && vc !== "\n") pendingNw += 1; | ||
| } | ||
| } else out += c; | ||
| } | ||
| if (isGlob) return { | ||
| op: "glob", | ||
| pattern: out | ||
| }; | ||
| if (ifs) { | ||
| if (pendingNw !== null && pendingNw > 0) { | ||
| words[words.length] = out; | ||
| out = ""; | ||
| for (var te = 1; te < pendingNw; te += 1) words[words.length] = ""; | ||
| } | ||
| if (out !== "" || sawQuote && words.length === 0) words[words.length] = out; | ||
| return words; | ||
| } | ||
| return out; | ||
| }).reduce(function(prev, arg) { | ||
| if (typeof arg === "undefined") return prev; | ||
| /** @type {ParseEntry[]} */ [].concat(arg).forEach(function(entry) { | ||
| prev[prev.length] = entry; | ||
| }); | ||
| return prev; | ||
| }, []); | ||
| } | ||
| /** @type {typeof import('./parse')} */ | ||
| module.exports = function parse(s, env, opts) { | ||
| var mapped = parseInternal(s, env, opts); | ||
| if (typeof env !== "function") return mapped; | ||
| return mapped.reduce(function(acc, s) { | ||
| if (typeof s === "object") { | ||
| acc[acc.length] = s; | ||
| return acc; | ||
| } | ||
| var xs = s.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g")); | ||
| if (xs.length === 1) { | ||
| acc[acc.length] = xs[0]; | ||
| return acc; | ||
| } | ||
| xs.filter(Boolean).forEach(function(x) { | ||
| acc[acc.length] = startsWithToken.test(x) ? JSON.parse(x.split(TOKEN)[1]) : x; | ||
| }); | ||
| return acc; | ||
| }, []); | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/shell-quote@1.10.0/node_modules/shell-quote/index.js | ||
| var require_shell_quote = /* @__PURE__ */ __commonJSMin(((exports) => { | ||
| exports.quote = require_quote(); | ||
| exports.parse = require_parse(); | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/macos.js | ||
| var require_macos = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = { | ||
| "/Applications/Atom.app/Contents/MacOS/Atom": "atom", | ||
| "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta": "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta", | ||
| "/Applications/Brackets.app/Contents/MacOS/Brackets": "brackets", | ||
| "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text.app/Contents/MacOS/sublime_text": "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2": "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl", | ||
| "/Applications/Visual Studio Code.app/Contents/MacOS/Code": "code", | ||
| "/Applications/Visual Studio Code.app/Contents/MacOS/Electron": "code", | ||
| "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Code - Insiders": "code-insiders", | ||
| "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron": "code-insiders", | ||
| "/Applications/VSCodium.app/Contents/MacOS/Electron": "codium", | ||
| "/Applications/Cursor.app/Contents/MacOS/Cursor": "cursor", | ||
| "/Applications/Trae.app/Contents/MacOS/Electron": "trae", | ||
| "/Applications/Antigravity.app/Contents/MacOS/Electron": "antigravity", | ||
| "/Applications/AppCode.app/Contents/MacOS/appcode": "/Applications/AppCode.app/Contents/MacOS/appcode", | ||
| "/Applications/CLion.app/Contents/MacOS/clion": "/Applications/CLion.app/Contents/MacOS/clion", | ||
| "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea", | ||
| "/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea", | ||
| "/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea", | ||
| "/Applications/PhpStorm.app/Contents/MacOS/phpstorm": "/Applications/PhpStorm.app/Contents/MacOS/phpstorm", | ||
| "/Applications/PyCharm.app/Contents/MacOS/pycharm": "/Applications/PyCharm.app/Contents/MacOS/pycharm", | ||
| "/Applications/PyCharm CE.app/Contents/MacOS/pycharm": "/Applications/PyCharm CE.app/Contents/MacOS/pycharm", | ||
| "/Applications/RubyMine.app/Contents/MacOS/rubymine": "/Applications/RubyMine.app/Contents/MacOS/rubymine", | ||
| "/Applications/WebStorm.app/Contents/MacOS/webstorm": "/Applications/WebStorm.app/Contents/MacOS/webstorm", | ||
| "/Applications/MacVim.app/Contents/MacOS/MacVim": "mvim", | ||
| "/Applications/GoLand.app/Contents/MacOS/goland": "/Applications/GoLand.app/Contents/MacOS/goland", | ||
| "/Applications/Rider.app/Contents/MacOS/rider": "/Applications/Rider.app/Contents/MacOS/rider", | ||
| "/Applications/Zed.app/Contents/MacOS/zed": "zed" | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/linux.js | ||
| var require_linux = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = { | ||
| atom: "atom", | ||
| Brackets: "brackets", | ||
| "code-insiders": "code-insiders", | ||
| code: "code", | ||
| vscodium: "vscodium", | ||
| codium: "codium", | ||
| cursor: "cursor", | ||
| trae: "trae", | ||
| antigravity: "antigravity", | ||
| emacs: "emacs", | ||
| gvim: "gvim", | ||
| idea: "idea", | ||
| "idea.sh": "idea", | ||
| phpstorm: "phpstorm", | ||
| "phpstorm.sh": "phpstorm", | ||
| pycharm: "pycharm", | ||
| "pycharm.sh": "pycharm", | ||
| rubymine: "rubymine", | ||
| "rubymine.sh": "rubymine", | ||
| sublime_text: "subl", | ||
| vim: "vim", | ||
| webstorm: "webstorm", | ||
| "webstorm.sh": "webstorm", | ||
| goland: "goland", | ||
| "goland.sh": "goland", | ||
| rider: "rider", | ||
| "rider.sh": "rider", | ||
| zed: "zed" | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/editor-info/windows.js | ||
| var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| module.exports = [ | ||
| "Brackets.exe", | ||
| "Code.exe", | ||
| "Code - Insiders.exe", | ||
| "VSCodium.exe", | ||
| "Cursor.exe", | ||
| "atom.exe", | ||
| "sublime_text.exe", | ||
| "notepad++.exe", | ||
| "clion.exe", | ||
| "clion64.exe", | ||
| "idea.exe", | ||
| "idea64.exe", | ||
| "phpstorm.exe", | ||
| "phpstorm64.exe", | ||
| "pycharm.exe", | ||
| "pycharm64.exe", | ||
| "rubymine.exe", | ||
| "rubymine64.exe", | ||
| "webstorm.exe", | ||
| "webstorm64.exe", | ||
| "goland.exe", | ||
| "goland64.exe", | ||
| "rider.exe", | ||
| "rider64.exe", | ||
| "Trae.exe", | ||
| "zed.exe", | ||
| "Antigravity.exe" | ||
| ]; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/guess.js | ||
| var require_guess = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| const path$2 = __require("path"); | ||
| const shellQuote = require_shell_quote(); | ||
| const childProcess$1 = __require("child_process"); | ||
| const COMMON_EDITORS_MACOS = require_macos(); | ||
| const COMMON_EDITORS_LINUX = require_linux(); | ||
| const COMMON_EDITORS_WIN = require_windows(); | ||
| function getEditorFromMacProcesses(output) { | ||
| const processNames = Object.keys(COMMON_EDITORS_MACOS); | ||
| const processList = output.split("\n"); | ||
| for (let i = 0; i < processNames.length; i++) { | ||
| const processName = processNames[i]; | ||
| if (processList.includes(processName)) return COMMON_EDITORS_MACOS[processName]; | ||
| const processNameWithoutApplications = processName.replace("/Applications", ""); | ||
| if (output.indexOf(processNameWithoutApplications) !== -1) { | ||
| if (processName !== COMMON_EDITORS_MACOS[processName]) return COMMON_EDITORS_MACOS[processName]; | ||
| const runningProcess = processList.find((procName) => procName.endsWith(processNameWithoutApplications)); | ||
| if (runningProcess !== void 0) return runningProcess; | ||
| } | ||
| } | ||
| } | ||
| function getEditorFromWindowsProcesses(output) { | ||
| const runningProcesses = output.split("\r\n"); | ||
| for (let i = 0; i < runningProcesses.length; i++) { | ||
| const fullProcessPath = runningProcesses[i].trim(); | ||
| const shortProcessName = path$2.win32.basename(fullProcessPath); | ||
| if (COMMON_EDITORS_WIN.indexOf(shortProcessName) !== -1) return fullProcessPath; | ||
| } | ||
| } | ||
| function getEditorFromLinuxProcesses(output) { | ||
| const processNames = Object.keys(COMMON_EDITORS_LINUX); | ||
| for (let i = 0; i < processNames.length; i++) { | ||
| const processName = processNames[i]; | ||
| if (output.indexOf(processName) !== -1) return COMMON_EDITORS_LINUX[processName]; | ||
| } | ||
| } | ||
| function guessEditor(specifiedEditor) { | ||
| if (specifiedEditor) return shellQuote.parse(specifiedEditor); | ||
| if (process.env.LAUNCH_EDITOR) return [process.env.LAUNCH_EDITOR]; | ||
| if (process.versions.webcontainer) return [process.env.EDITOR || "code"]; | ||
| try { | ||
| if (process.platform === "darwin") { | ||
| const editor = getEditorFromMacProcesses(childProcess$1.execSync("ps x -o comm=", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } else if (process.platform === "win32") { | ||
| const editor = getEditorFromWindowsProcesses(childProcess$1.execSync("powershell -NoProfile -Command \"[Console]::OutputEncoding=[Text.Encoding]::UTF8;Get-CimInstance -Query \\\"select executablepath from win32_process where executablepath is not null\\\" | % { $_.ExecutablePath }\"", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } else if (process.platform === "linux") { | ||
| const editor = getEditorFromLinuxProcesses(childProcess$1.execSync("ps x --no-heading -o comm --sort=comm", { stdio: [ | ||
| "pipe", | ||
| "pipe", | ||
| "ignore" | ||
| ] }).toString()); | ||
| if (editor !== void 0) return [editor]; | ||
| } | ||
| } catch (ignoreError) {} | ||
| if (process.env.VISUAL) return [process.env.VISUAL]; | ||
| else if (process.env.EDITOR) return [process.env.EDITOR]; | ||
| return [null]; | ||
| } | ||
| module.exports = guessEditor; | ||
| module.exports.getEditorFromMacProcesses = getEditorFromMacProcesses; | ||
| module.exports.getEditorFromWindowsProcesses = getEditorFromWindowsProcesses; | ||
| module.exports.getEditorFromLinuxProcesses = getEditorFromLinuxProcesses; | ||
| })); | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/launch-editor@2.14.1/node_modules/launch-editor/get-args.js | ||
| var require_get_args = /* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| const path$1 = __require("path"); | ||
| module.exports = function getArgumentsForPosition(editor, fileName, lineNumber, columnNumber = 1) { | ||
| switch (path$1.basename(editor).replace(/\.(exe|cmd|bat)$/i, "")) { | ||
| case "atom": | ||
| case "Atom": | ||
| case "Atom Beta": | ||
| case "subl": | ||
| case "sublime": | ||
| case "sublime_text": | ||
| case "wstorm": | ||
| case "charm": | ||
| case "zed": return [`${fileName}:${lineNumber}:${columnNumber}`]; | ||
| case "notepad++": return [ | ||
| "-n" + lineNumber, | ||
| "-c" + columnNumber, | ||
| fileName | ||
| ]; | ||
| case "vim": | ||
| case "mvim": return [`+call cursor(${lineNumber}, ${columnNumber})`, fileName]; | ||
| case "joe": | ||
| case "gvim": return [`+${lineNumber}`, fileName]; | ||
| case "emacs": | ||
| case "emacsclient": return [`+${lineNumber}:${columnNumber}`, fileName]; | ||
| case "rmate": | ||
| case "mate": | ||
| case "mine": return [ | ||
| "--line", | ||
| lineNumber, | ||
| fileName | ||
| ]; | ||
| case "code": | ||
| case "Code": | ||
| case "code-insiders": | ||
| case "Code - Insiders": | ||
| case "codium": | ||
| case "trae": | ||
| case "antigravity": | ||
| case "cursor": | ||
| case "vscodium": | ||
| case "VSCodium": return [ | ||
| "-r", | ||
| "-g", | ||
| `${fileName}:${lineNumber}:${columnNumber}` | ||
| ]; | ||
| case "appcode": | ||
| case "clion": | ||
| case "clion64": | ||
| case "idea": | ||
| case "idea64": | ||
| case "phpstorm": | ||
| case "phpstorm64": | ||
| case "pycharm": | ||
| case "pycharm64": | ||
| case "rubymine": | ||
| case "rubymine64": | ||
| case "webstorm": | ||
| case "webstorm64": | ||
| case "goland": | ||
| case "goland64": | ||
| case "rider": | ||
| case "rider64": return [ | ||
| "--line", | ||
| lineNumber, | ||
| "--column", | ||
| columnNumber, | ||
| fileName | ||
| ]; | ||
| } | ||
| if (process.env.LAUNCH_EDITOR) return [ | ||
| fileName, | ||
| lineNumber, | ||
| columnNumber | ||
| ]; | ||
| return [fileName]; | ||
| }; | ||
| })); | ||
| //#endregion | ||
| //#region src/utils/launch-editor.ts | ||
| var import_launch_editor = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => { | ||
| /** | ||
| * Copyright (c) 2015-present, Facebook, Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file at | ||
| * https://github.com/facebookincubator/create-react-app/blob/master/LICENSE | ||
| * | ||
| * Modified by Yuxi Evan You | ||
| */ | ||
| const fs = __require("fs"); | ||
| const os = __require("os"); | ||
| const path = __require("path"); | ||
| const colors = require_picocolors(); | ||
| const childProcess = __require("child_process"); | ||
| const guessEditor = require_guess(); | ||
| const getArgumentsForPosition = require_get_args(); | ||
| function wrapErrorCallback(cb) { | ||
| return (fileName, errorMessage) => { | ||
| console.log(); | ||
| console.log(colors.red("Could not open " + path.basename(fileName) + " in the editor.")); | ||
| if (errorMessage) { | ||
| if (errorMessage[errorMessage.length - 1] !== ".") errorMessage += "."; | ||
| console.log(colors.red("The editor process exited with an error: " + errorMessage)); | ||
| } | ||
| console.log(); | ||
| if (cb) cb(fileName, errorMessage); | ||
| }; | ||
| } | ||
| function isTerminalEditor(editor) { | ||
| switch (editor) { | ||
| case "vim": | ||
| case "emacs": | ||
| case "nano": return true; | ||
| } | ||
| return false; | ||
| } | ||
| const positionRE = /:(\d+)(:(\d+))?$/; | ||
| function parseFile(file) { | ||
| if (file.startsWith("file://")) file = __require("url").fileURLToPath(file); | ||
| const fileName = file.replace(positionRE, ""); | ||
| const match = file.match(positionRE); | ||
| return { | ||
| fileName, | ||
| lineNumber: match && match[1], | ||
| columnNumber: match && match[3] | ||
| }; | ||
| } | ||
| let currentChildProcess = null; | ||
| function launchEditor(file, specifiedEditor, onErrorCallback) { | ||
| const parsed = parseFile(file); | ||
| let { fileName } = parsed; | ||
| const { lineNumber, columnNumber } = parsed; | ||
| if (process.platform === "win32" && path.resolve(fileName).startsWith("\\\\")) return onErrorCallback(fileName, "UNC paths are not supported on Windows to avoid security issues. See https://github.com/vitejs/launch-editor/tree/main/packages/launch-editor#unc-paths-on-windows for details."); | ||
| if (!fs.existsSync(fileName)) return; | ||
| if (typeof specifiedEditor === "function") { | ||
| onErrorCallback = specifiedEditor; | ||
| specifiedEditor = void 0; | ||
| } | ||
| onErrorCallback = wrapErrorCallback(onErrorCallback); | ||
| const [editor, ...args] = guessEditor(specifiedEditor); | ||
| if (!editor) { | ||
| onErrorCallback(fileName, null); | ||
| return; | ||
| } | ||
| if (process.platform === "linux" && fileName.startsWith("/mnt/") && /Microsoft/i.test(os.release())) fileName = path.relative("", fileName); | ||
| if (lineNumber) { | ||
| const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber); | ||
| args.push.apply(args, extraArgs); | ||
| } else args.push(fileName); | ||
| if (currentChildProcess && isTerminalEditor(editor)) currentChildProcess.kill("SIGKILL"); | ||
| if (process.platform === "win32") { | ||
| function escapeCmdArgs(cmdArgs) { | ||
| return cmdArgs.replace(/([&|<>,;=^])/g, "^$1"); | ||
| } | ||
| function doubleQuoteIfNeeded(str) { | ||
| if (str.includes("^")) return `^"${str}^"`; | ||
| else if (str.includes(" ")) return `"${str}"`; | ||
| return str; | ||
| } | ||
| const launchCommand = [editor, ...args.map(escapeCmdArgs)].map(doubleQuoteIfNeeded).join(" "); | ||
| currentChildProcess = childProcess.exec(launchCommand, { | ||
| stdio: "inherit", | ||
| shell: true | ||
| }); | ||
| } else currentChildProcess = childProcess.spawn(editor, args, { stdio: "inherit" }); | ||
| currentChildProcess.on("exit", function(errorCode) { | ||
| currentChildProcess = null; | ||
| if (errorCode) onErrorCallback(fileName, "(code " + errorCode + ")"); | ||
| }); | ||
| currentChildProcess.on("error", function(error) { | ||
| let { code, message } = error; | ||
| if ("ENOENT" === code) message = `${message} ('${editor}' command does not exist in 'PATH')`; | ||
| onErrorCallback(fileName, message); | ||
| }); | ||
| } | ||
| module.exports = launchEditor; | ||
| })))(), 1); | ||
| /** | ||
| * Open a file in the user's editor. | ||
| * | ||
| * `target` may be a plain path, `file:line`, or `file:line:column`. | ||
| * | ||
| * If `editor` is provided, it is used as the editor command (e.g. `'code'`, | ||
| * `'subl'`) or absolute binary path. Otherwise the editor is auto-detected | ||
| * via the `LAUNCH_EDITOR` env var with a fallback to common defaults. | ||
| */ | ||
| function launchEditor(target, editor) { | ||
| (0, import_launch_editor.default)(target, editor); | ||
| } | ||
| //#endregion | ||
| export { launchEditor as t }; |
| import { $ as DevframeRpcServerFunctions, Q as DevframeRpcClientFunctions, W as DevframeNodeRpcSession, _ as ConnectionMeta, b as DevframeNodeContext, p as DevframeAuthHandler } from "./devframe-DfzYvlKI.mjs"; | ||
| import "./index-CxpC1ItQ.mjs"; | ||
| import { Peer } from "crossws"; | ||
| import { BirpcGroup, EventOptions } from "birpc"; | ||
| import { NodeAdapter } from "crossws/adapters/node"; | ||
| import { Server } from "node:http"; | ||
| import { H3 } from "h3"; | ||
| //#region src/node/server.d.ts | ||
| interface StartHttpAndWsOptions { | ||
| context: DevframeNodeContext; | ||
| host?: string; | ||
| port: number; | ||
| /** | ||
| * Optional h3 app to mount on. When omitted a fresh one is created; | ||
| * when provided, callers can add their own routes (static handlers, | ||
| * auth middleware, etc.) first. | ||
| */ | ||
| app?: H3; | ||
| /** | ||
| * Bind the WS endpoint to a single upgrade route (e.g. `/__devframe_ws`) instead of | ||
| * claiming every upgrade on the port. This lets the socket share a server | ||
| * with other upgrade handlers (Vite HMR, a host framework's own sockets) | ||
| * and is what the SPA's `__connection.json` points at. When omitted, the WS | ||
| * server handles every upgrade on the port (legacy behaviour). | ||
| */ | ||
| path?: string; | ||
| /** | ||
| * Bind the WS endpoint on its own port instead of sharing the HTTP server's. | ||
| * The HTTP/SPA server still listens on `port`; the socket gets a dedicated | ||
| * `ws` server on `wsPort` (same `host`). Use this for the "different port" | ||
| * connection scenario. Ignored when a `server` is supplied. | ||
| */ | ||
| wsPort?: number; | ||
| /** | ||
| * Mount the WS endpoint onto an existing HTTP server, sharing its port, | ||
| * rather than creating and listening on a fresh one. Use this to embed | ||
| * devframe's RPC socket inside a host server (e.g. a Vite dev server) — pair | ||
| * it with `path` so it coexists with the host's routes. The caller owns the | ||
| * server's lifecycle: {@link StartedServer.close} detaches devframe's upgrade | ||
| * listener but leaves the host server running. When set, `host`/`port` are | ||
| * only used to report the resolved origin. | ||
| */ | ||
| server?: Server; | ||
| /** | ||
| * Authentication for the server: | ||
| * | ||
| * - `true` (default) — no gate; every registered method is callable | ||
| * regardless of trust (today's behavior, unchanged). | ||
| * - `false` — the RPC server is started without a trust handshake. | ||
| * Intended for single-user localhost tools where an auth round-trip | ||
| * would only get in the way. A noop `anonymous:devframe:auth` handler | ||
| * is registered so the browser client's unconditional handshake call | ||
| * succeeds and auto-trusts. | ||
| * - A {@link DevframeAuthHandler} (e.g. from | ||
| * `devframe/recipes/interactive-auth`'s `createInteractiveAuth`) — | ||
| * registers its `rpcFunctions`, wires its `authorize` as the resolver | ||
| * gate, and wires its `onConnect` on every new peer. This is the | ||
| * fully-authenticated server: an untrusted caller can only reach | ||
| * `anonymous:`-prefixed methods (see `isAnonymousRpcMethod`). | ||
| */ | ||
| auth?: boolean | DevframeAuthHandler; | ||
| /** | ||
| * Lower-level escape hatch: gate individual RPC calls by method name and | ||
| * session without a full {@link DevframeAuthHandler}. Ignored when `auth` | ||
| * is a handler object (its own `authorize` is used); combine with `auth: | ||
| * true` to layer a custom policy on top of an otherwise ungated server. | ||
| */ | ||
| authorize?: (methodName: string, session: DevframeNodeRpcSession) => boolean; | ||
| /** | ||
| * Called once per new WS connection, right after its session is created | ||
| * (before any RPC call is dispatched). Runs after the auth handler's own | ||
| * `onConnect` (when `auth` is a {@link DevframeAuthHandler}), so it can | ||
| * observe — but not override — the connect-time trust decision. | ||
| */ | ||
| onPeerConnect?: (peer: Peer, session: DevframeNodeRpcSession) => void; | ||
| /** | ||
| * Forwarded verbatim to the internal `createRpcServer`'s birpc | ||
| * `rpcOptions`, alongside the resolver `startHttpAndWs` installs for | ||
| * auth/session wiring. Use this so a host that owns its own structured | ||
| * diagnostics (e.g. a coded error reporter) keeps seeing RPC failures | ||
| * instead of them being silently absorbed by delegating to | ||
| * `startHttpAndWs`. Returning `true` from either callback suppresses | ||
| * birpc's own error response to the caller — see birpc's | ||
| * `EventOptions` for the full contract. | ||
| */ | ||
| rpcOptions?: Pick<EventOptions<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>, 'onFunctionError' | 'onGeneralError'>; | ||
| /** | ||
| * Extra origins to accept on the WS upgrade beyond the loopback default | ||
| * (`localhost`/`127.0.0.1`/`::1` and any `Origin`-less request from a | ||
| * native client). Add your LAN/tunnel origin here when reaching the tool | ||
| * from another host. Pass `false` to disable origin checking entirely | ||
| * (not recommended). Default: loopback-only. | ||
| */ | ||
| allowedOrigins?: readonly string[] | false; | ||
| /** | ||
| * Called once the WS server is bound so callers can mount static | ||
| * handlers whose origin depends on the resolved port, or print their | ||
| * own startup banner. Devframe does not print one itself. | ||
| */ | ||
| onReady?: (info: { | ||
| origin: string; | ||
| port: number; | ||
| app: H3; | ||
| }) => void | Promise<void>; | ||
| } | ||
| interface StartedServer { | ||
| /** Listening origin, e.g. `http://localhost:9999`. */ | ||
| origin: string; | ||
| port: number; | ||
| app: H3; | ||
| /** The crossws node adapter driving the RPC socket (connected peers, pub/sub). */ | ||
| ws: NodeAdapter; | ||
| rpcGroup: BirpcGroup<DevframeRpcClientFunctions, DevframeRpcServerFunctions, false>; | ||
| /** | ||
| * The {@link ConnectionMeta} descriptor for this server — the same shape | ||
| * a `__connection.json` route should serve so a devframe client's | ||
| * `resolveWsUrl` can dial back in. Reflects the `path` / `wsPort` this | ||
| * server was started with and the `jsonSerializable` methods currently | ||
| * registered on `context.rpc`. | ||
| */ | ||
| connectionMeta: () => ConnectionMeta; | ||
| close: () => Promise<void>; | ||
| } | ||
| /** | ||
| * Compose an h3 + WebSocket server for a devframe context. The RPC | ||
| * group is bound to `context.rpc.functions`; the WS endpoint lives on | ||
| * the same port as the HTTP server. | ||
| */ | ||
| declare function startHttpAndWs(options: StartHttpAndWsOptions): Promise<StartedServer>; | ||
| //#endregion | ||
| export { StartedServer as n, startHttpAndWs as r, StartHttpAndWsOptions as t }; |
| //#region ../../node_modules/.pnpm/structured-clone-es@2.0.0/node_modules/structured-clone-es/dist/index.mjs | ||
| const env = typeof self === "object" ? self : globalThis; | ||
| function deserializer($, _) { | ||
| const as = (out, index) => { | ||
| $.set(index, out); | ||
| return out; | ||
| }; | ||
| const unpair = (index) => { | ||
| if ($.has(index)) return $.get(index); | ||
| const [type, value] = _[index]; | ||
| switch (type) { | ||
| case 0: | ||
| case -1: return as(value, index); | ||
| case 1: { | ||
| const arr = as([], index); | ||
| for (const index of value) arr.push(unpair(index)); | ||
| return arr; | ||
| } | ||
| case 2: { | ||
| const object = as({}, index); | ||
| for (const [key, index] of value) object[unpair(key)] = unpair(index); | ||
| return object; | ||
| } | ||
| case 3: return as(new Date(value), index); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as(new RegExp(source, flags), index); | ||
| } | ||
| case 5: { | ||
| const map = as(/* @__PURE__ */ new Map(), index); | ||
| for (const [key, index] of value) map.set(unpair(key), unpair(index)); | ||
| return map; | ||
| } | ||
| case 6: { | ||
| const set = as(/* @__PURE__ */ new Set(), index); | ||
| for (const index of value) set.add(unpair(index)); | ||
| return set; | ||
| } | ||
| case 7: { | ||
| const { name, message } = value; | ||
| return as(new env[name](message), index); | ||
| } | ||
| case 8: return as(BigInt(value), index); | ||
| case "BigInt": return as(Object(BigInt(value)), index); | ||
| case "ArrayBuffer": return as(new Uint8Array(value).buffer, value); | ||
| case "DataView": { | ||
| const { buffer } = new Uint8Array(value); | ||
| return as(new DataView(buffer), value); | ||
| } | ||
| } | ||
| return as(new env[type](value), index); | ||
| }; | ||
| return unpair; | ||
| } | ||
| /** | ||
| * Returns a deserialized value from a serialized array of Records. | ||
| * @param serialized a previously serialized value. | ||
| */ | ||
| function deserialize(serialized) { | ||
| return deserializer(/* @__PURE__ */ new Map(), serialized)(0); | ||
| } | ||
| const EMPTY = ""; | ||
| const { toString } = {}; | ||
| const { keys } = Object; | ||
| function typeOf(value) { | ||
| const type = typeof value; | ||
| if (type !== "object" || !value) return [0, type]; | ||
| const asString = toString.call(value).slice(8, -1); | ||
| switch (asString) { | ||
| case "Array": return [1, EMPTY]; | ||
| case "Object": return [2, EMPTY]; | ||
| case "Date": return [3, EMPTY]; | ||
| case "RegExp": return [4, EMPTY]; | ||
| case "Map": return [5, EMPTY]; | ||
| case "Set": return [6, EMPTY]; | ||
| case "DataView": return [1, asString]; | ||
| } | ||
| if (asString.includes("Array")) return [1, asString]; | ||
| if (asString.includes("Error")) return [7, asString]; | ||
| return [2, asString]; | ||
| } | ||
| function shouldSkip([TYPE, type]) { | ||
| return TYPE === 0 && (type === "function" || type === "symbol"); | ||
| } | ||
| function serializer(strict, json, $, _) { | ||
| const as = (out, value) => { | ||
| const index = _.push(out) - 1; | ||
| $.set(value, index); | ||
| return index; | ||
| }; | ||
| const pair = (value) => { | ||
| if ($.has(value)) return $.get(value); | ||
| let [TYPE, type] = typeOf(value); | ||
| switch (TYPE) { | ||
| case 0: { | ||
| let entry = value; | ||
| switch (type) { | ||
| case "bigint": | ||
| TYPE = 8; | ||
| entry = value.toString(); | ||
| break; | ||
| case "function": | ||
| case "symbol": | ||
| if (strict) throw new TypeError(`unable to serialize ${type}`); | ||
| entry = null; | ||
| break; | ||
| case "undefined": return as([-1], value); | ||
| } | ||
| return as([TYPE, entry], value); | ||
| } | ||
| case 1: { | ||
| if (type) { | ||
| let spread = value; | ||
| if (type === "DataView") spread = new Uint8Array(value.buffer); | ||
| else if (type === "ArrayBuffer") spread = new Uint8Array(value); | ||
| return as([type, [...spread]], value); | ||
| } | ||
| const arr = []; | ||
| const index = as([TYPE, arr], value); | ||
| for (const entry of value) arr.push(pair(entry)); | ||
| return index; | ||
| } | ||
| case 2: { | ||
| if (type) switch (type) { | ||
| case "BigInt": return as([type, value.toString()], value); | ||
| case "Boolean": | ||
| case "Number": | ||
| case "String": return as([type, value.valueOf()], value); | ||
| } | ||
| if (json && "toJSON" in value) return pair(value.toJSON()); | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const key of keys(value)) if (strict || !shouldSkip(typeOf(value[key]))) entries.push([pair(key), pair(value[key])]); | ||
| return index; | ||
| } | ||
| case 3: return as([TYPE, value.toISOString()], value); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as([TYPE, { | ||
| source, | ||
| flags | ||
| }], value); | ||
| } | ||
| case 5: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const [key, entry] of value) if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry)))) entries.push([pair(key), pair(entry)]); | ||
| return index; | ||
| } | ||
| case 6: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const entry of value) if (strict || !shouldSkip(typeOf(entry))) entries.push(pair(entry)); | ||
| return index; | ||
| } | ||
| } | ||
| const { message } = value; | ||
| return as([TYPE, { | ||
| name: type, | ||
| message | ||
| }], value); | ||
| }; | ||
| return pair; | ||
| } | ||
| /** | ||
| * Returns an array of serialized Records. | ||
| */ | ||
| function serialize(value, options = {}) { | ||
| const _ = []; | ||
| serializer(!(options.json || options.lossy), !!options.json, /* @__PURE__ */ new Map(), _)(value); | ||
| return _; | ||
| } | ||
| const { parse: $parse, stringify: $stringify } = JSON; | ||
| const options = { | ||
| json: true, | ||
| lossy: true | ||
| }; | ||
| /** | ||
| * Revive a previously stringified structured clone. | ||
| * @param str previously stringified data as string. | ||
| */ | ||
| function parse(str) { | ||
| return deserialize($parse(str)); | ||
| } | ||
| /** | ||
| * Represent a structured clone value as string. | ||
| * @param any some clone-able value to stringify. | ||
| */ | ||
| function stringify(any) { | ||
| return $stringify(serialize(any, options)); | ||
| } | ||
| //#endregion | ||
| //#region src/utils/structured-clone.ts | ||
| /** | ||
| * Serialize a structured-cloneable value (`Map`, `Set`, `Date`, `BigInt`, | ||
| * cycles, class instances, …) into a JSON-safe records array. | ||
| */ | ||
| function structuredCloneSerialize(value) { | ||
| return serialize(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneSerialize}. | ||
| */ | ||
| function structuredCloneDeserialize(value) { | ||
| return deserialize(value); | ||
| } | ||
| /** | ||
| * Serialize a structured-cloneable value to a single string. Equivalent | ||
| * to `JSON.stringify(structuredCloneSerialize(value))`. | ||
| */ | ||
| function structuredCloneStringify(value) { | ||
| return stringify(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneStringify}. | ||
| */ | ||
| function structuredCloneParse(value) { | ||
| return parse(value); | ||
| } | ||
| //#endregion | ||
| export { structuredCloneStringify as i, structuredCloneParse as n, structuredCloneSerialize as r, structuredCloneDeserialize as t }; |
| //#region ../../node_modules/.pnpm/structured-clone-es@2.0.0/node_modules/structured-clone-es/dist/index.mjs | ||
| const env = typeof self === "object" ? self : globalThis; | ||
| function deserializer($, _) { | ||
| const as = (out, index) => { | ||
| $.set(index, out); | ||
| return out; | ||
| }; | ||
| const unpair = (index) => { | ||
| if ($.has(index)) return $.get(index); | ||
| const [type, value] = _[index]; | ||
| switch (type) { | ||
| case 0: | ||
| case -1: return as(value, index); | ||
| case 1: { | ||
| const arr = as([], index); | ||
| for (const index of value) arr.push(unpair(index)); | ||
| return arr; | ||
| } | ||
| case 2: { | ||
| const object = as({}, index); | ||
| for (const [key, index] of value) object[unpair(key)] = unpair(index); | ||
| return object; | ||
| } | ||
| case 3: return as(new Date(value), index); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as(new RegExp(source, flags), index); | ||
| } | ||
| case 5: { | ||
| const map = as(/* @__PURE__ */ new Map(), index); | ||
| for (const [key, index] of value) map.set(unpair(key), unpair(index)); | ||
| return map; | ||
| } | ||
| case 6: { | ||
| const set = as(/* @__PURE__ */ new Set(), index); | ||
| for (const index of value) set.add(unpair(index)); | ||
| return set; | ||
| } | ||
| case 7: { | ||
| const { name, message } = value; | ||
| return as(new env[name](message), index); | ||
| } | ||
| case 8: return as(BigInt(value), index); | ||
| case "BigInt": return as(Object(BigInt(value)), index); | ||
| case "ArrayBuffer": return as(new Uint8Array(value).buffer, value); | ||
| case "DataView": { | ||
| const { buffer } = new Uint8Array(value); | ||
| return as(new DataView(buffer), value); | ||
| } | ||
| } | ||
| return as(new env[type](value), index); | ||
| }; | ||
| return unpair; | ||
| } | ||
| /** | ||
| * Returns a deserialized value from a serialized array of Records. | ||
| * @param serialized a previously serialized value. | ||
| */ | ||
| function deserialize(serialized) { | ||
| return deserializer(/* @__PURE__ */ new Map(), serialized)(0); | ||
| } | ||
| const EMPTY = ""; | ||
| const { toString } = {}; | ||
| const { keys } = Object; | ||
| function typeOf(value) { | ||
| const type = typeof value; | ||
| if (type !== "object" || !value) return [0, type]; | ||
| const asString = toString.call(value).slice(8, -1); | ||
| switch (asString) { | ||
| case "Array": return [1, EMPTY]; | ||
| case "Object": return [2, EMPTY]; | ||
| case "Date": return [3, EMPTY]; | ||
| case "RegExp": return [4, EMPTY]; | ||
| case "Map": return [5, EMPTY]; | ||
| case "Set": return [6, EMPTY]; | ||
| case "DataView": return [1, asString]; | ||
| } | ||
| if (asString.includes("Array")) return [1, asString]; | ||
| if (asString.includes("Error")) return [7, asString]; | ||
| return [2, asString]; | ||
| } | ||
| function shouldSkip([TYPE, type]) { | ||
| return TYPE === 0 && (type === "function" || type === "symbol"); | ||
| } | ||
| function serializer(strict, json, $, _) { | ||
| const as = (out, value) => { | ||
| const index = _.push(out) - 1; | ||
| $.set(value, index); | ||
| return index; | ||
| }; | ||
| const pair = (value) => { | ||
| if ($.has(value)) return $.get(value); | ||
| let [TYPE, type] = typeOf(value); | ||
| switch (TYPE) { | ||
| case 0: { | ||
| let entry = value; | ||
| switch (type) { | ||
| case "bigint": | ||
| TYPE = 8; | ||
| entry = value.toString(); | ||
| break; | ||
| case "function": | ||
| case "symbol": | ||
| if (strict) throw new TypeError(`unable to serialize ${type}`); | ||
| entry = null; | ||
| break; | ||
| case "undefined": return as([-1], value); | ||
| } | ||
| return as([TYPE, entry], value); | ||
| } | ||
| case 1: { | ||
| if (type) { | ||
| let spread = value; | ||
| if (type === "DataView") spread = new Uint8Array(value.buffer); | ||
| else if (type === "ArrayBuffer") spread = new Uint8Array(value); | ||
| return as([type, [...spread]], value); | ||
| } | ||
| const arr = []; | ||
| const index = as([TYPE, arr], value); | ||
| for (const entry of value) arr.push(pair(entry)); | ||
| return index; | ||
| } | ||
| case 2: { | ||
| if (type) switch (type) { | ||
| case "BigInt": return as([type, value.toString()], value); | ||
| case "Boolean": | ||
| case "Number": | ||
| case "String": return as([type, value.valueOf()], value); | ||
| } | ||
| if (json && "toJSON" in value) return pair(value.toJSON()); | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const key of keys(value)) if (strict || !shouldSkip(typeOf(value[key]))) entries.push([pair(key), pair(value[key])]); | ||
| return index; | ||
| } | ||
| case 3: return as([TYPE, value.toISOString()], value); | ||
| case 4: { | ||
| const { source, flags } = value; | ||
| return as([TYPE, { | ||
| source, | ||
| flags | ||
| }], value); | ||
| } | ||
| case 5: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const [key, entry] of value) if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry)))) entries.push([pair(key), pair(entry)]); | ||
| return index; | ||
| } | ||
| case 6: { | ||
| const entries = []; | ||
| const index = as([TYPE, entries], value); | ||
| for (const entry of value) if (strict || !shouldSkip(typeOf(entry))) entries.push(pair(entry)); | ||
| return index; | ||
| } | ||
| } | ||
| const { message } = value; | ||
| return as([TYPE, { | ||
| name: type, | ||
| message | ||
| }], value); | ||
| }; | ||
| return pair; | ||
| } | ||
| /** | ||
| * Returns an array of serialized Records. | ||
| */ | ||
| function serialize(value, options = {}) { | ||
| const _ = []; | ||
| serializer(!(options.json || options.lossy), !!options.json, /* @__PURE__ */ new Map(), _)(value); | ||
| return _; | ||
| } | ||
| const { parse: $parse, stringify: $stringify } = JSON; | ||
| const options = { | ||
| json: true, | ||
| lossy: true | ||
| }; | ||
| /** | ||
| * Revive a previously stringified structured clone. | ||
| * @param str previously stringified data as string. | ||
| */ | ||
| function parse(str) { | ||
| return deserialize($parse(str)); | ||
| } | ||
| /** | ||
| * Represent a structured clone value as string. | ||
| * @param any some clone-able value to stringify. | ||
| */ | ||
| function stringify(any) { | ||
| return $stringify(serialize(any, options)); | ||
| } | ||
| //#endregion | ||
| //#region src/utils/structured-clone.ts | ||
| /** | ||
| * Serialize a structured-cloneable value to a single string. Equivalent | ||
| * to `JSON.stringify(structuredCloneSerialize(value))`. | ||
| */ | ||
| function structuredCloneStringify(value) { | ||
| return stringify(value); | ||
| } | ||
| /** | ||
| * Inverse of {@link structuredCloneStringify}. | ||
| */ | ||
| function structuredCloneParse(value) { | ||
| return parse(value); | ||
| } | ||
| //#endregion | ||
| export { structuredCloneStringify as n, structuredCloneParse as t }; |
Sorry, the diff of this file is too big to display
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
626534
1.32%113
0.89%12399
1.14%34
3.03%Updated