diff --git a/AGENTS.md b/AGENTS.md index 701838b1..b371f76a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ The `pnpm test` script intentionally runs `build` first so `tsnapi` snapshots co ## Conventions - RPC functions must use `defineRpcFunction`; always namespace IDs `devframes:plugin::` (matching the plugin's `@devframes/plugin-` package name). +- **Stay validator-neutral.** `devframe` and every `@devframes/*` package must not introduce a preferred schema validator dependency — no `valibot`, `zod`, `arktype`, etc. in their runtime `dependencies`. `args`/`returns`/flag schemas are typed against [Standard Schema](https://standardschema.dev/) (`@standard-schema/spec`, types-only); first-party code that needs to author a schema uses the built-in zero-dep `devframe/utils/simple-schema` builder (deliberately minimal — not a general validator). JSON-schema conversion uses each schema's own Standard JSON Schema converter (`~standard.jsonSchema`, implemented by e.g. zod 4) when present and degrades to a permissive object otherwise — no converter library and no vendor dependency is required. Docs, by contrast, should point *users* at a real validator for their own integrations — recommend **valibot** (lightest) or **zod** (worth reusing if they already pull it via the JSON-render or MCP integrations). - Shared state via `devframe/utils/shared-state`; keep values serializable. - Utility imports use the package-path form `devframe/utils/*`, never relative `../utils/*`. - Dependencies go through the pnpm catalogs in `pnpm-workspace.yaml` (`cli`, `inlined`, `testing`, `types`) — add to a catalog and reference as `catalog:`, don't pin versions in `package.json`. diff --git a/alias.ts b/alias.ts index e284552c..2ea324ee 100644 --- a/alias.ts +++ b/alias.ts @@ -26,6 +26,7 @@ export const alias = { 'devframe/utils/nanoid': r('devframe/src/utils/nanoid.ts'), 'devframe/utils/open': r('devframe/src/utils/open.ts'), 'devframe/utils/promise': r('devframe/src/utils/promise.ts'), + 'devframe/utils/simple-schema': r('devframe/src/utils/simple-schema.ts'), 'devframe/utils/scope': r('devframe/src/utils/scope.ts'), 'devframe/utils/serve-static': r('devframe/src/utils/serve-static.ts'), 'devframe/utils/shared-state': r('devframe/src/utils/shared-state.ts'), diff --git a/docs/errors/DF0019.md b/docs/errors/DF0019.md index 51c3c4c2..a02d3ebe 100644 --- a/docs/errors/DF0019.md +++ b/docs/errors/DF0019.md @@ -10,7 +10,7 @@ outline: deep ## Cause -The `agent` field exposes an RPC function as an MCP tool. MCP and the underlying schema-conversion path (`@valibot/to-json-schema`) only consume JSON-shaped data. Functions whose payloads can include `Map`, `Set`, `Date`, `BigInt`, circular references, or class instances cannot be safely advertised to agents. +The `agent` field exposes an RPC function as an MCP tool. MCP only consumes JSON-shaped data. Functions whose payloads can include `Map`, `Set`, `Date`, `BigInt`, circular references, or class instances cannot be safely advertised to agents. A registered function is rejected when `agent` is present and `jsonSerializable` is not explicitly `true`. diff --git a/docs/errors/DF0043.md b/docs/errors/DF0043.md new file mode 100644 index 00000000..a55f0d33 --- /dev/null +++ b/docs/errors/DF0043.md @@ -0,0 +1,38 @@ +--- +outline: deep +--- + +# DF0043: Invalid RPC Argument + +## Message + +> RPC function "`{name}`" received an invalid argument at position `{index}`: `{issues}` + +## Cause + +When an RPC function declares `args` schemas, each incoming argument is validated against its positional [Standard Schema](https://standardschema.dev/) (valibot, zod, arktype, …) before the handler runs — on every path: local calls, over-the-wire calls, and the agent/MCP bridge. The argument at `{index}` failed that schema. Validation guards the payload without rewriting it, so extra object fields the schema doesn't mention still reach the handler. + +## Example + +```ts +const greet = defineRpcFunction({ + name: 'greet', + args: [v.string()], + returns: v.string(), + handler: name => `hi ${name}`, +}) + +// ✓ Good +await ctx.rpc.functions.greet('ada') + +// ✗ Bad — a number where a string is required → DF0043 at position 0 +await ctx.rpc.functions.greet(42 as never) +``` + +## Fix + +Pass a value that satisfies the `args` schema declared for the function, or widen the schema if the value is legitimately allowed. + +## Source + +- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts) — `validateRpcArgs()` throws `DF0043` on the first argument that fails its declared schema. diff --git a/docs/errors/DF0044.md b/docs/errors/DF0044.md new file mode 100644 index 00000000..3cbdb157 --- /dev/null +++ b/docs/errors/DF0044.md @@ -0,0 +1,33 @@ +--- +outline: deep +--- + +# DF0044: Invalid RPC Return Value + +## Message + +> RPC function "`{name}`" returned a value that failed its `returns` schema: `{issues}` + +## Cause + +When an RPC function declares a `returns` schema, the handler's resolved value is validated against that [Standard Schema](https://standardschema.dev/) (valibot, zod, arktype, …) before it is sent back to the caller. The value the handler produced does not satisfy the schema — a bug in the handler or a schema that is narrower than the real result. Validation guards the payload without rewriting it, so a value that merely carries extra object fields is accepted. + +## Example + +```ts +const count = defineRpcFunction({ + name: 'count', + args: [], + returns: v.number(), + // ✗ Bad — returns a string where a number is declared → DF0044 + handler: () => 'twelve' as never, +}) +``` + +## Fix + +Make the handler return a value that satisfies the `returns` schema, or relax the schema so it describes the value the handler actually produces. + +## Source + +- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts) — `validateRpcReturn()` throws `DF0044` when the handler's resolved value fails its declared schema. diff --git a/docs/guide/devframe-definition.md b/docs/guide/devframe-definition.md index 9c87de34..e389d7e4 100644 --- a/docs/guide/devframe-definition.md +++ b/docs/guide/devframe-definition.md @@ -10,7 +10,7 @@ Every Devframe tool starts with a single `defineDevframe` call. The returned `De ```ts twoslash import { defineDevframe, defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import * as v from 'valibot' // npm i valibot export default defineDevframe({ id: 'my-devframe', diff --git a/docs/guide/rpc.md b/docs/guide/rpc.md index 6a185a0c..31e37f39 100644 --- a/docs/guide/rpc.md +++ b/docs/guide/rpc.md @@ -4,7 +4,7 @@ outline: deep # RPC -Devframe's RPC layer is type-safe bidirectional communication between your server (Node.js) and client (browser), built on [`birpc`](https://github.com/antfu/birpc) and validated at runtime with [`valibot`](https://valibot.dev/). In dev mode it runs over WebSocket; in build / SPA mode it serves a pre-computed static dump so the client still works offline. +Devframe's RPC layer is type-safe bidirectional communication between your server (Node.js) and client (browser), built on [`birpc`](https://github.com/antfu/birpc) and validated at runtime against any [Standard Schema](https://standardschema.dev/) validator — valibot, zod, arktype, and others all work. In dev mode it runs over WebSocket; in build / SPA mode it serves a pre-computed static dump so the client still works offline. ## Overview @@ -22,7 +22,7 @@ sequenceDiagram ```ts import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import * as v from 'valibot' // npm i valibot (or use zod / arktype) export const getModules = defineRpcFunction({ name: 'get-modules', // bare — the scope namespaces it to `my-devframe:get-modules` @@ -75,7 +75,12 @@ Use `static` for data collected once during `setup` and shipped to read-only sta ### Handler arguments -Handlers accept any serializable arguments. With `args` valibot schemas, arguments are validated at the boundary: +Handlers accept any serializable arguments. Declare `args` schemas — any [Standard Schema](https://standardschema.dev/) validator (valibot, zod, arktype, …) — and each argument is validated at the boundary before the handler runs; a mismatch is rejected with a coded diagnostic. Validation guards the payload without rewriting it, so extra object fields the schema doesn't mention still reach the handler. + +Devframe forces no validator on you: bring whichever [Standard Schema](https://standardschema.dev/) validator you prefer (valibot, zod, arktype) and install it yourself. The examples here use valibot (`npm i valibot`) — it's the lightest option and a good default. + +> [!TIP] +> If your app already pulls in **zod** — the JSON-render integration and the MCP server both use it — prefer zod for your RPC schemas too, and you'll reuse a dependency you're already shipping instead of adding valibot. Any Standard Schema validator works either way; this is purely about dependency reuse. ```ts defineRpcFunction({ @@ -94,6 +99,9 @@ defineRpcFunction({ Prefer a single object argument (`args: [v.object({ ... })]`) over positional args — property names are self-describing and agents/IDEs work best with object shapes. +> [!WARNING] +> Declared `args`/`returns` schemas are enforced at runtime — a call whose arguments, or a handler whose return value, fail the schema is rejected with `DF0043` / `DF0044`. Make sure each schema matches what the function actually accepts and returns; a schema stricter than reality will now reject calls that previously ran. + ### Setup vs handler Two ways to wire a handler: diff --git a/docs/guide/standalone-cli.md b/docs/guide/standalone-cli.md index 3239d8f6..9968a211 100644 --- a/docs/guide/standalone-cli.md +++ b/docs/guide/standalone-cli.md @@ -168,13 +168,13 @@ const payload = await my.rpc.call('get-payload') ## Typed CLI flags -For flags that are specific to your tool, declare them as valibot schemas so they're validated at parse time and typed at the call site: +For flags that are specific to your tool, declare them with any [Standard Schema](https://standardschema.dev/) validator (valibot below — `npm i valibot`, the lightest option — or zod / arktype) so they're validated at parse time and typed at the call site. If you already depend on zod through the JSON-render or MCP integrations, prefer zod here to avoid adding a second validator: ```ts import type { InferCliFlags } from 'devframe/adapters/cac' import { defineDevframe } from 'devframe' import { defineCliFlags } from 'devframe/adapters/cac' -import * as v from 'valibot' +import * as v from 'valibot' // npm i valibot const appFlags = defineCliFlags({ depth: v.pipe(v.number(), v.integer()), diff --git a/docs/guide/streaming.md b/docs/guide/streaming.md index d5198e37..31852db4 100644 --- a/docs/guide/streaming.md +++ b/docs/guide/streaming.md @@ -29,7 +29,7 @@ Create the channel once in `setup`. Channels are framework-neutral, so the same ```ts import { defineDevframe, defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import * as v from 'valibot' // npm i valibot export default defineDevframe({ id: 'my-devframe', diff --git a/docs/helpers/common-rpc-functions.md b/docs/helpers/common-rpc-functions.md index b600c3ca..8efa0d43 100644 --- a/docs/helpers/common-rpc-functions.md +++ b/docs/helpers/common-rpc-functions.md @@ -28,7 +28,7 @@ defineDevframe({ | `KNOWN_EDITORS` | — | `readonly string[]` | — | The editor commands `openInEditor`'s `editor` argument accepts (`code`, `vim`, `subl`, `idea`, …). | | `KnownEditor` | — | type | — | Union of `KNOWN_EDITORS`. | -Both functions are `action`-type RPCs returning `void` and use `valibot` schemas for their arguments — `openInEditor`'s `editor` argument is `v.optional(v.picklist(KNOWN_EDITORS))`, so a value outside `KNOWN_EDITORS` fails validation rather than reaching the underlying `launch-editor` process spawn. Both handlers dynamically `import()` their underlying `devframe/utils/*` implementation, so the `launch-editor` and `open` dependencies only load when the recipe actually runs. +Both functions are `action`-type RPCs returning `void`, and their arguments are schema-validated — `openInEditor`'s `editor` argument is restricted to `KNOWN_EDITORS`, so a value outside that list fails validation rather than reaching the underlying `launch-editor` process spawn. Both handlers dynamically `import()` their underlying `devframe/utils/*` implementation, so the `launch-editor` and `open` dependencies only load when the recipe actually runs. The `devframe/recipes/open-helpers` entry (`openHelpers`) remains as a deprecated alias for this module — new code should import `commonRpcFunctions` from `devframe/recipes/common-rpc-functions`. diff --git a/packages/devframe/package.json b/packages/devframe/package.json index eb98692a..29680312 100644 --- a/packages/devframe/package.json +++ b/packages/devframe/package.json @@ -50,6 +50,7 @@ "./utils/nanoid": "./dist/utils/nanoid.mjs", "./utils/open": "./dist/utils/open.mjs", "./utils/promise": "./dist/utils/promise.mjs", + "./utils/simple-schema": "./dist/utils/simple-schema.mjs", "./utils/scope": "./dist/utils/scope.mjs", "./utils/serve-static": "./dist/utils/serve-static.mjs", "./utils/shared-state": "./dist/utils/shared-state.mjs", @@ -82,7 +83,7 @@ } }, "dependencies": { - "@valibot/to-json-schema": "catalog:deps", + "@standard-schema/spec": "catalog:deps", "birpc": "catalog:deps", "crossws": "catalog:deps", "destr": "catalog:deps", @@ -90,8 +91,7 @@ "mrmime": "catalog:deps", "nostics": "catalog:deps", "pathe": "catalog:deps", - "ufo": "catalog:deps", - "valibot": "catalog:deps" + "ufo": "catalog:deps" }, "devDependencies": { "@modelcontextprotocol/client": "catalog:deps", @@ -110,6 +110,7 @@ "tinyglobby": "catalog:deps", "tsdown": "catalog:build", "ua-parser-modern": "catalog:inlined", + "valibot": "catalog:deps", "whenexpr": "catalog:deps", "ws": "catalog:deps" } diff --git a/packages/devframe/src/adapters/flags.ts b/packages/devframe/src/adapters/flags.ts index b104219a..d69a0ddf 100644 --- a/packages/devframe/src/adapters/flags.ts +++ b/packages/devframe/src/adapters/flags.ts @@ -1,14 +1,14 @@ -import type { GenericSchema, InferOutput } from 'valibot' -import { safeParse } from 'valibot' +import type { StandardSchemaV1 } from '@standard-schema/spec' /** * Schema map for typed CLI flags. Keys are flag names in camelCase — * this matches CAC's parsed-flag output ( `--no-open` → `noOpen` ). Each - * value is a valibot schema used to both (a) derive the CAC option type - * when the flag is registered and (b) validate / coerce the parsed - * value before it's forwarded to `setup(ctx, { flags })`. + * value is any [Standard Schema](https://standardschema.dev/) validator + * (valibot, zod, arktype, devframe's built-in `s`, …) used to both (a) + * derive the CAC option type when the flag is registered and (b) validate + * the parsed value before it's forwarded to `setup(ctx, { flags })`. */ -export type CliFlagsSchema = Record +export type CliFlagsSchema = Record /** * Identity helper that preserves the literal schema-map type — use this @@ -36,16 +36,18 @@ export function defineCliFlags(flags: T): T { /** Extract the parsed-output type from a {@link CliFlagsSchema}. */ export type InferCliFlags = { - [K in keyof T]: InferOutput + [K in keyof T]: StandardSchemaV1.InferOutput } /** - * 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. + * Best-effort, dependency-free probe of a schema to decide whether the + * corresponding CAC option takes a value. Duck-types the `type` / + * `wrapped` / `inner` / `pipe` fields exposed by valibot and by devframe's + * built-in `s` builder, unwrapping `optional` / `nullable` / `nullish` / + * `pipe` wrappers then matching on the inner kind. Validators that don't + * expose these fields (e.g. zod) fall through to a value-taking option. */ -function getSchemaKind(schema: GenericSchema): string { +function getSchemaKind(schema: StandardSchemaV1): string { let current: any = schema while (current) { const kind = current.type @@ -57,17 +59,17 @@ function getSchemaKind(schema: GenericSchema): string { current = current.pipe[0] continue } - return kind + return kind ?? 'unknown' } return 'unknown' } /** Whether the CAC option for this schema should be a boolean flag. */ -export function isBooleanFlag(schema: GenericSchema): boolean { +export function isBooleanFlag(schema: StandardSchemaV1): boolean { return getSchemaKind(schema) === 'boolean' } -/** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */ +/** Validate the raw cac-parsed bag against a {@link CliFlagsSchema}. */ export function parseCliFlags( schema: CliFlagsSchema, raw: Record, @@ -75,13 +77,18 @@ export function parseCliFlags( const flags: Record = {} const issues: string[] = [] for (const [key, fieldSchema] of Object.entries(schema)) { - const result = safeParse(fieldSchema, raw[key]) - if (result.success) { - flags[key] = result.output + const result = fieldSchema['~standard'].validate(raw[key]) + if (result instanceof Promise) { + // CLI parsing is synchronous; an async validator can't be awaited here. + issues.push(`--${toKebab(key)}: async flag validation is not supported`) + continue } - else { + if (result.issues) { issues.push(`--${toKebab(key)}: ${result.issues.map(i => i.message).join(', ')}`) } + else { + flags[key] = result.value + } } // Preserve any raw flags that aren't in the schema (e.g. --host, --port, // or options contributed via cli.configure) so authors keep access to diff --git a/packages/devframe/src/adapters/mcp/__tests__/to-json-schema.test.ts b/packages/devframe/src/adapters/mcp/__tests__/to-json-schema.test.ts index b275ec57..132f95df 100644 --- a/packages/devframe/src/adapters/mcp/__tests__/to-json-schema.test.ts +++ b/packages/devframe/src/adapters/mcp/__tests__/to-json-schema.test.ts @@ -1,53 +1,56 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' import * as v from 'valibot' import { describe, expect, it } from 'vitest' -import { valibotArgsToJsonSchema, valibotReturnToJsonSchema } from '../to-json-schema' +import { argsToJsonSchema, returnToJsonSchema } from '../to-json-schema' -describe('valibotArgsToJsonSchema', () => { +const PERMISSIVE = { type: 'object', additionalProperties: true } + +/** A Standard Schema that also implements the Standard JSON Schema converter (like zod 4). */ +function withJsonSchema(json: Record): StandardSchemaV1 { + return { + '~standard': { + version: 1, + vendor: 'test', + validate: (value: unknown) => ({ value }), + jsonSchema: { + input: () => json, + output: () => json, + }, + } as StandardSchemaV1['~standard'], + } +} + +describe('argsToJsonSchema', () => { it('returns an empty object schema when no args', () => { - const { schema, unwrapped } = valibotArgsToJsonSchema(undefined) + const { schema, unwrapped } = argsToJsonSchema(undefined) expect(unwrapped).toBe(false) expect(schema).toEqual({ type: 'object', properties: {} }) }) - it('wraps multiple positional args under arg0/arg1/...', () => { - const { schema, unwrapped } = valibotArgsToJsonSchema([v.string(), v.number()]) - expect(unwrapped).toBe(false) - expect(schema).toMatchObject({ - type: 'object', - required: ['arg0', 'arg1'], - additionalProperties: false, - }) - const props = (schema as any).properties - expect(props.arg0).toMatchObject({ type: 'string' }) - expect(props.arg1).toMatchObject({ type: 'number' }) - }) - - it('unwraps a single object schema for nicer agent UX', () => { - const { schema, unwrapped } = valibotArgsToJsonSchema([ - v.object({ name: v.string(), age: v.number() }), - ]) - expect(unwrapped).toBe(true) - expect((schema as any).type).toBe('object') - const props = (schema as any).properties - expect(props.name).toBeDefined() - expect(props.age).toBeDefined() + it('uses the schema\'s own Standard JSON Schema converter when present', () => { + const { schema } = argsToJsonSchema([withJsonSchema({ type: 'string' })]) + expect((schema as any).properties.arg0).toEqual({ type: 'string' }) }) - it('keeps arg0 shape when the single arg is a primitive', () => { - const { schema, unwrapped } = valibotArgsToJsonSchema([v.string()]) - expect(unwrapped).toBe(false) - expect(schema).toMatchObject({ type: 'object', required: ['arg0'] }) + it('falls back to a permissive object for validators without a native converter (valibot)', () => { + const { schema } = argsToJsonSchema([v.string(), v.number()]) + expect((schema as any).properties.arg0).toEqual(PERMISSIVE) + expect((schema as any).properties.arg1).toEqual(PERMISSIVE) + expect(schema).toMatchObject({ type: 'object', required: ['arg0', 'arg1'], additionalProperties: false }) }) }) -describe('valibotReturnToJsonSchema', () => { +describe('returnToJsonSchema', () => { it('returns undefined when no schema is provided', () => { - expect(valibotReturnToJsonSchema(undefined)).toBeUndefined() + expect(returnToJsonSchema(undefined)).toBeUndefined() + }) + + it('uses the native converter when present', () => { + expect(returnToJsonSchema(withJsonSchema({ type: 'object', properties: { ok: { type: 'boolean' } } }))) + .toEqual({ type: 'object', properties: { ok: { type: 'boolean' } } }) }) - it('converts a simple schema', () => { - const schema = valibotReturnToJsonSchema(v.object({ ok: v.boolean() })) - expect((schema as any).type).toBe('object') - expect((schema as any).properties.ok).toMatchObject({ type: 'boolean' }) + it('falls back to permissive for validators without a native converter', () => { + expect(returnToJsonSchema(v.object({ ok: v.boolean() }))).toEqual(PERMISSIVE) }) }) diff --git a/packages/devframe/src/adapters/mcp/build-server.ts b/packages/devframe/src/adapters/mcp/build-server.ts index 8a9dad9e..b2aac021 100644 --- a/packages/devframe/src/adapters/mcp/build-server.ts +++ b/packages/devframe/src/adapters/mcp/build-server.ts @@ -1,7 +1,7 @@ import type { Tool } from '@modelcontextprotocol/server' +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { RpcFunctionDefinitionAnyWithContext } from 'devframe/rpc' import type { AgentTool, DevframeDefinition, DevframeHost, DevframeNodeContext } from 'devframe/types' -import type { GenericSchema } from 'valibot' import { homedir } from 'node:os' import process from 'node:process' import { Server } from '@modelcontextprotocol/server' @@ -9,7 +9,7 @@ import { createHostContext } from 'devframe/node' import { join } from 'pathe' import { diagnostics } from '../../node/diagnostics' import { formatMcpError, stringifyForMcp } from './stringify' -import { valibotArgsToJsonSchema, valibotReturnToJsonSchema } from './to-json-schema' +import { argsToJsonSchema, returnToJsonSchema } from './to-json-schema' export interface CreateMcpServerOptions { /** @@ -271,8 +271,8 @@ function computeInputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown const def = ctx.rpc.definitions.get(tool.rpcName) as RpcFunctionDefinitionAnyWithContext | undefined if (!def) return { type: 'object', properties: {} } - const args = def.args as readonly GenericSchema[] | undefined - return valibotArgsToJsonSchema(args).schema + const args = def.args as readonly StandardSchemaV1[] | undefined + return argsToJsonSchema(args).schema } function computeOutputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown { @@ -281,7 +281,7 @@ function computeOutputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown const def = ctx.rpc.definitions.get(tool.rpcName) as RpcFunctionDefinitionAnyWithContext | undefined if (!def) return undefined - return valibotReturnToJsonSchema(def.returns as GenericSchema | undefined) + return returnToJsonSchema(def.returns as StandardSchemaV1 | undefined) } function parseResourceUri(uri: string): { kind: 'resource', id: string } | { kind: 'state', key: string } | { kind: 'unknown' } { diff --git a/packages/devframe/src/adapters/mcp/to-json-schema.ts b/packages/devframe/src/adapters/mcp/to-json-schema.ts index ccf1b144..6a678e89 100644 --- a/packages/devframe/src/adapters/mcp/to-json-schema.ts +++ b/packages/devframe/src/adapters/mcp/to-json-schema.ts @@ -1,54 +1,62 @@ -import type { GenericSchema } from 'valibot' -import { toJsonSchema } from '@valibot/to-json-schema' +import type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec' const FALLBACK_OBJECT_SCHEMA = Object.freeze({ type: 'object', additionalProperties: true }) +/** A `~standard` prop that may also carry the Standard JSON Schema converter. */ +type MaybeJsonSchema = StandardSchemaV1['~standard'] & Partial + /** - * Convert a valibot return schema to JSON Schema. + * Convert a Standard Schema to JSON Schema for the agent/MCP surface. + * + * Devframe stays validator-neutral, so conversion uses the schema's own + * [Standard JSON Schema](https://standardschema.dev/) converter + * (`~standard.jsonSchema`) when the validator provides one — zod 4 does, + * for example. Validators without a native converter (e.g. valibot) degrade + * to a permissive object schema rather than pulling in a converter library. + */ +function safeToJsonSchema(schema: StandardSchemaV1): unknown { + const standard = schema['~standard'] as MaybeJsonSchema + if (standard.jsonSchema) { + try { + return standard.jsonSchema.input({ target: 'draft-2020-12' }) + } + catch { + return FALLBACK_OBJECT_SCHEMA + } + } + return FALLBACK_OBJECT_SCHEMA +} + +/** + * JSON Schema for an RPC return value on the agent/MCP surface. * @internal */ -export function valibotReturnToJsonSchema(schema: GenericSchema | undefined): unknown { +export function returnToJsonSchema(schema: StandardSchemaV1 | undefined): unknown { if (!schema) return undefined - try { - return toJsonSchema(schema as any) - } - catch { - return FALLBACK_OBJECT_SCHEMA - } + return safeToJsonSchema(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: {...} }`). + * JSON Schema for an RPC function's positional args on the agent/MCP + * surface. Each positional arg is advertised under `arg0` / `arg1` / … — + * matching how the agent bridge coerces the incoming object payload back + * into positional arguments. * - * Returns `undefined` when there are no args (the MCP SDK treats this - * as `{ type: 'object', properties: {} }`). + * Returns `{ type: 'object', properties: {} }` when there are no args. * @internal */ -export function valibotArgsToJsonSchema( - args: readonly GenericSchema[] | undefined, +export function argsToJsonSchema( + args: readonly StandardSchemaV1[] | undefined, ): { schema: unknown, unwrapped: boolean } { if (!args || args.length === 0) return { schema: { type: 'object', properties: {} }, unwrapped: false } - // Single-object arg: unwrap. - if (args.length === 1) { - const inner = safeToJsonSchema(args[0]!) - if (isObjectJsonSchema(inner)) - return { schema: inner, unwrapped: true } - // Non-object single arg (e.g. a string): fall through to arg0 shape. - } - const properties: Record = {} const required: string[] = [] for (let i = 0; i < args.length; i++) { const key = `arg${i}` - const s = safeToJsonSchema(args[i]!) - properties[key] = s - // Conservatively mark every positional arg as required — the RPC - // layer validates against valibot anyway. + properties[key] = safeToJsonSchema(args[i]!) required.push(key) } @@ -62,20 +70,3 @@ export function valibotArgsToJsonSchema( unwrapped: false, } } - -function safeToJsonSchema(schema: GenericSchema): unknown { - try { - return toJsonSchema(schema as any) - } - catch { - return FALLBACK_OBJECT_SCHEMA - } -} - -function isObjectJsonSchema(value: unknown): boolean { - return ( - !!value - && typeof value === 'object' - && (value as { type?: unknown }).type === 'object' - ) -} diff --git a/packages/devframe/src/node/host-agent.ts b/packages/devframe/src/node/host-agent.ts index 5ccb6441..12245734 100644 --- a/packages/devframe/src/node/host-agent.ts +++ b/packages/devframe/src/node/host-agent.ts @@ -199,7 +199,8 @@ export class DevframeAgentHost implements DevframeAgentHostType { rpcName: name, examples: agent.examples, // Schemas are carried by the definition itself — consumers - // (e.g. the MCP adapter) convert valibot → JSON Schema on demand. + // (e.g. the MCP adapter) convert the Standard Schema → JSON Schema + // on demand. }) } return out diff --git a/packages/devframe/src/recipes/__tests__/common-rpc-functions.test.ts b/packages/devframe/src/recipes/__tests__/common-rpc-functions.test.ts index a4db8438..37b21f37 100644 --- a/packages/devframe/src/recipes/__tests__/common-rpc-functions.test.ts +++ b/packages/devframe/src/recipes/__tests__/common-rpc-functions.test.ts @@ -1,8 +1,16 @@ -import * as v from 'valibot' +import type { StandardSchemaV1 } from '@standard-schema/spec' import { describe, expect, it } from 'vitest' import { commonRpcFunctions, KNOWN_EDITORS, openInEditor, openInFinder } from '../common-rpc-functions' import { openHelpers } from '../open-helpers' +/** Synchronously check whether a value satisfies a Standard Schema. */ +function accepts(schema: StandardSchemaV1, value: unknown): boolean { + const result = schema['~standard'].validate(value) + if (result instanceof Promise) + throw new TypeError('unexpected async validator') + return !result.issues +} + describe('recipes/common-rpc-functions', () => { it('exposes `openInEditor` as a devframe-namespaced action', () => { expect(openInEditor.name).toBe('devframe:open-in-editor') @@ -16,10 +24,10 @@ describe('recipes/common-rpc-functions', () => { expect(KNOWN_EDITORS).toContain('vim') const editorSchema = openInEditor.args[1] - expect(v.safeParse(editorSchema, undefined).success).toBe(true) + expect(accepts(editorSchema, undefined)).toBe(true) for (const editor of KNOWN_EDITORS) - expect(v.safeParse(editorSchema, editor).success).toBe(true) - expect(v.safeParse(editorSchema, 'not-a-real-editor').success).toBe(false) + expect(accepts(editorSchema, editor)).toBe(true) + expect(accepts(editorSchema, 'not-a-real-editor')).toBe(false) }) it('exposes `openInFinder` as a devframe-namespaced action', () => { diff --git a/packages/devframe/src/recipes/common-rpc-functions.ts b/packages/devframe/src/recipes/common-rpc-functions.ts index 927164be..60f8b9fd 100644 --- a/packages/devframe/src/recipes/common-rpc-functions.ts +++ b/packages/devframe/src/recipes/common-rpc-functions.ts @@ -1,4 +1,4 @@ -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { defineRpcFunction } from '../rpc/define' /** @@ -42,7 +42,7 @@ export type KnownEditor | 'goland' | 'rider' -/** Runtime list of every {@link KnownEditor}, in the order `v.picklist` reports them. */ +/** Runtime list of every {@link KnownEditor}. */ export const KNOWN_EDITORS: KnownEditor[] = [ 'atom', 'subl', @@ -103,8 +103,8 @@ export const openInEditor = defineRpcFunction({ name: 'devframe:open-in-editor', type: 'action', jsonSerializable: true, - args: [v.string(), v.optional(v.picklist(KNOWN_EDITORS))], - returns: v.void(), + args: [s.string(), s.optional(s.picklist(KNOWN_EDITORS))], + returns: s.void(), async handler(filename: string, editor?: KnownEditor) { const { launchEditor } = await import('devframe/utils/launch-editor') launchEditor(filename, editor) @@ -126,8 +126,8 @@ export const openInFinder = defineRpcFunction({ name: 'devframe:open-in-finder', type: 'action', jsonSerializable: true, - args: [v.string()], - returns: v.void(), + args: [s.string()], + returns: s.void(), async handler(path: string) { const { open } = await import('devframe/utils/open') await open(path) diff --git a/packages/devframe/src/recipes/interactive-auth.ts b/packages/devframe/src/recipes/interactive-auth.ts index a52ea783..4af42d98 100644 --- a/packages/devframe/src/recipes/interactive-auth.ts +++ b/packages/devframe/src/recipes/interactive-auth.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext, DevframeNodeRpcSession } from 'devframe/types' import type { DevframeAuthHandler } from '../node/auth' import { colors } from 'devframe/utils/colors' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { DEVFRAME_AUTH_TOKEN_QUERY_PARAM, isAnonymousRpcMethod } from '../constants' import { buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, verifyAuthToken } from '../node/auth/state' import { getInternalContext } from '../node/hub-internals/context' @@ -86,12 +86,12 @@ export function createInteractiveAuth( name: 'anonymous:devframe:auth', type: 'action', jsonSerializable: true, - args: [v.object({ - authToken: v.string(), - ua: v.string(), - origin: v.string(), + args: [s.object({ + authToken: s.string(), + ua: s.string(), + origin: s.string(), })], - returns: v.object({ isTrusted: v.boolean() }), + returns: s.object({ isTrusted: s.boolean() }), handler(params) { const session = context.rpc.getCurrentRpcSession() if (!session) @@ -111,12 +111,12 @@ export function createInteractiveAuth( name: 'anonymous:devframe:auth:exchange', type: 'action', jsonSerializable: true, - args: [v.object({ - code: v.string(), - ua: v.string(), - origin: v.string(), + args: [s.object({ + code: s.string(), + ua: s.string(), + origin: s.string(), })], - returns: v.object({ authToken: v.nullable(v.string()) }), + returns: s.object({ authToken: s.nullable(s.string()) }), handler(params) { const session = context.rpc.getCurrentRpcSession() if (!session) @@ -134,7 +134,7 @@ export function createInteractiveAuth( type: 'action', jsonSerializable: true, args: [], - returns: v.void(), + returns: s.void(), async handler() { const session = context.rpc.getCurrentRpcSession() const token = session?.meta.clientAuthToken diff --git a/packages/devframe/src/rpc/diagnostics.ts b/packages/devframe/src/rpc/diagnostics.ts index d8df5841..3ba5b711 100644 --- a/packages/devframe/src/rpc/diagnostics.ts +++ b/packages/devframe/src/rpc/diagnostics.ts @@ -41,5 +41,15 @@ export const diagnostics = defineDiagnostics({ why: (p: { name: string, type: string }) => `Function "${p.name}" with type "${p.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`, fix: 'Remove `snapshot: true`, or change the function type to `query`.', }, + DF0043: { + why: (p: { name: string, index: number, issues: string }) => + `RPC function "${p.name}" received an invalid argument at position ${p.index}: ${p.issues}`, + fix: 'Pass a value that satisfies the `args` schema declared for this function.', + }, + DF0044: { + why: (p: { name: string, issues: string }) => + `RPC function "${p.name}" returned a value that failed its \`returns\` schema: ${p.issues}`, + fix: 'Make the handler return a value that satisfies the `returns` schema, or relax the schema.', + }, }, }) diff --git a/packages/devframe/src/rpc/handler.ts b/packages/devframe/src/rpc/handler.ts index f522b79e..5b1a23b5 100644 --- a/packages/devframe/src/rpc/handler.ts +++ b/packages/devframe/src/rpc/handler.ts @@ -1,5 +1,6 @@ import type { RpcFunctionDefinition, RpcFunctionSetupResult, RpcFunctionType } from './types' import { diagnostics } from './diagnostics' +import { validateRpcArgs, validateRpcReturn } from './validate-io' export async function getRpcResolvedSetupResult< NAME extends string, @@ -58,12 +59,31 @@ export async function getRpcHandler< definition: RpcFunctionDefinition, context: CONTEXT, ): Promise<(...args: ARGS) => RETURN> { - if (definition.handler) { - return definition.handler + let handler = definition.handler + if (!handler) { + const result = await getRpcResolvedSetupResult(definition, context) + if (!result.handler) { + throw diagnostics.DF0024({ name: definition.name }) + } + handler = result.handler + } + + // When `args`/`returns` Standard Schemas are declared, validate inputs + // before the handler runs and the output after it returns (guard-only — + // payloads are never rewritten). Wrapping here means every invocation + // path — local, over-the-wire, and the agent/MCP bridge — funnels + // through the same validation. + const argsSchema = definition.args + const returnSchema = definition.returns + if (!argsSchema && !returnSchema) { + return handler } - const result = await getRpcResolvedSetupResult(definition, context) - if (!result.handler) { - throw diagnostics.DF0024({ name: definition.name }) + + const inner = handler + const validating = async (...args: ARGS): Promise => { + const validatedArgs = await validateRpcArgs(definition.name, argsSchema, args) + const output = await inner(...(validatedArgs as ARGS)) + return await validateRpcReturn(definition.name, returnSchema, output) as RETURN } - return result.handler + return validating as (...args: ARGS) => RETURN } diff --git a/packages/devframe/src/rpc/index.ts b/packages/devframe/src/rpc/index.ts index 8201c21a..00448b0d 100644 --- a/packages/devframe/src/rpc/index.ts +++ b/packages/devframe/src/rpc/index.ts @@ -26,6 +26,7 @@ export * from './define' export * from './handler' export * from './serialization' export * from './types' +export * from './validate-io' export * from './validation' /** @deprecated Import from `devframe/rpc/dump` instead. */ diff --git a/packages/devframe/src/rpc/types.test.ts b/packages/devframe/src/rpc/types.test.ts index f4a25a80..5d690b80 100644 --- a/packages/devframe/src/rpc/types.test.ts +++ b/packages/devframe/src/rpc/types.test.ts @@ -1,4 +1,5 @@ /* eslint-disable unused-imports/no-unused-vars */ +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { RpcDefinitionsToFunctions, RpcFunctionDefinitionToFunction, @@ -8,6 +9,17 @@ import * as v from 'valibot' import { describe, it } from 'vitest' import { defineRpcFunction } from '.' +/** Fake a typed Standard Schema from a non-valibot vendor. */ +function schema(): StandardSchemaV1 { + return { + '~standard': { + version: 1, + vendor: 'test', + validate: value => ({ value: value as Output }), + }, + } +} + describe('rpcFunctionDefinitionToFunction', () => { it('should infer types from generic parameters when no schemas', () => { const fn = defineRpcFunction({ @@ -59,6 +71,18 @@ describe('rpcFunctionDefinitionToFunction', () => { type _Test = AssertEqual number> }) + it('should infer types from any Standard Schema vendor', () => { + const fn = defineRpcFunction({ + name: 'anyVendor', + args: [schema(), schema()], + returns: schema(), + handler: (a, b) => a.length > b, + }) + + type Result = RpcFunctionDefinitionToFunction + type _Test = AssertEqual boolean> + }) + it('should work with setup function instead of handler', () => { const fn = defineRpcFunction({ name: 'withSetup', diff --git a/packages/devframe/src/rpc/types.ts b/packages/devframe/src/rpc/types.ts index 370c08e6..ed75147a 100644 --- a/packages/devframe/src/rpc/types.ts +++ b/packages/devframe/src/rpc/types.ts @@ -1,4 +1,4 @@ -import type { GenericSchema } from 'valibot' +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { InferArgsType, InferReturnType } from './utils' export type { BirpcFn, BirpcReturn } from 'birpc' @@ -93,10 +93,20 @@ export interface RpcFunctionSetupResult< dump?: RpcDumpDefinition } -/** Valibot schema array for validating function arguments */ -export type RpcArgsSchema = readonly GenericSchema[] -/** Valibot schema for validating function return value */ -export type RpcReturnSchema = GenericSchema +/** + * Positional argument schemas for an RPC function. Each entry is any + * [Standard Schema](https://standardschema.dev)-compliant validator + * (valibot, zod, arktype, …); the entry at index `i` validates argument + * `i` at call time and drives that argument's inferred type. + */ +export type RpcArgsSchema = readonly StandardSchemaV1[] +/** + * Return-value schema for an RPC function. Any + * [Standard Schema](https://standardschema.dev)-compliant validator; it + * validates the handler's resolved return value and drives its inferred + * type. + */ +export type RpcReturnSchema = StandardSchemaV1 /** * Serialized representation of a thrown value in a dump record. @@ -233,9 +243,9 @@ export type RpcFunctionDefinition< type?: TYPE /** Whether the function results should be cached */ cacheable?: boolean - /** Valibot schema array for validating function arguments */ + /** Standard Schema array validating (and typing) the arguments */ args?: AS - /** Valibot schema for validating function return value */ + /** Standard Schema validating (and typing) the return value */ returns?: RS /** * Declares whether this function's args/return are JSON-serializable @@ -281,9 +291,9 @@ export type RpcFunctionDefinition< type?: TYPE /** Whether the function results should be cached */ cacheable?: boolean - /** Valibot schema array for validating function arguments */ + /** Standard Schema array validating (and typing) the arguments */ args: AS - /** Valibot schema for validating function return value */ + /** Standard Schema validating (and typing) the return value */ returns: RS /** * Declares whether this function's args/return are JSON-serializable diff --git a/packages/devframe/src/rpc/utils.ts b/packages/devframe/src/rpc/utils.ts index 18e3fb46..16f2323e 100644 --- a/packages/devframe/src/rpc/utils.ts +++ b/packages/devframe/src/rpc/utils.ts @@ -1,4 +1,4 @@ -import type { GenericSchema, InferInput } from 'valibot' +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { RpcArgsSchema, RpcReturnSchema } from './types' /** Type-level assertion that two types are equal */ @@ -6,19 +6,19 @@ export type AssertEqual = (() => T extends X ? 1 : 2) extends (() => T extends Y ? 1 : 2) ? true : never -/** Infers TypeScript tuple type from Valibot schema array */ +/** Infers a TypeScript argument tuple from a Standard Schema array */ export type InferArgsType = S extends readonly [] ? [] : S extends readonly [infer H, ...infer T] - ? H extends GenericSchema - ? T extends readonly GenericSchema[] - ? [InferInput, ...InferArgsType] + ? H extends StandardSchemaV1 + ? T extends readonly StandardSchemaV1[] + ? [StandardSchemaV1.InferInput, ...InferArgsType] : never : never : never -/** Infers TypeScript return type from Valibot return schema */ +/** Infers a TypeScript return type from a Standard Schema */ export type InferReturnType - = S extends RpcReturnSchema - ? InferInput + = S extends StandardSchemaV1 + ? StandardSchemaV1.InferInput : void diff --git a/packages/devframe/src/rpc/validate-io.test.ts b/packages/devframe/src/rpc/validate-io.test.ts new file mode 100644 index 00000000..4e05515e --- /dev/null +++ b/packages/devframe/src/rpc/validate-io.test.ts @@ -0,0 +1,131 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' +import * as v from 'valibot' +import { describe, expect, it } from 'vitest' +import { defineRpcFunction } from './define' +import { getRpcHandler } from './handler' +import { validateRpcArgs, validateRpcReturn } from './validate-io' + +/** A minimal async Standard Schema from a non-valibot vendor. */ +function asyncPositive(): StandardSchemaV1 { + return { + '~standard': { + version: 1, + vendor: 'test', + async validate(value) { + await Promise.resolve() + if (typeof value === 'number' && value > 0) + return { value } + return { issues: [{ message: 'expected a positive number' }] } + }, + }, + } +} + +describe('validateRpcArgs', () => { + it('returns args untouched when no schema is declared', async () => { + await expect(validateRpcArgs('fn', undefined, ['a', 1])).resolves.toEqual(['a', 1]) + }) + + it('passes the original values through without rewriting them', async () => { + // A transform would coerce to `5`; guard-only validation keeps `'hello'`. + const schema = [v.pipe(v.string(), v.transform(s => s.length))] as const + await expect(validateRpcArgs('fn', schema, ['hello'])).resolves.toEqual(['hello']) + }) + + it('preserves object fields beyond the schema (no key stripping)', async () => { + const schema = [v.object({ id: v.string() })] as const + const value = { id: 'x', extra: true } + const [out] = await validateRpcArgs('fn', schema, [value]) + expect(out).toEqual({ id: 'x', extra: true }) + }) + + it('leaves un-schema-ed trailing args in place', async () => { + const schema = [v.string()] as const + await expect(validateRpcArgs('fn', schema, ['a', 'passthrough'])).resolves.toEqual(['a', 'passthrough']) + }) + + it('throws DF0043 with the failing index', async () => { + const schema = [v.string(), v.number()] as const + await expect(validateRpcArgs('fn', schema, ['ok', 'nope'])).rejects.toThrow(/position 1/) + }) + + it('awaits async validators from any vendor', async () => { + const schema = [asyncPositive()] as const + await expect(validateRpcArgs('fn', schema, [3])).resolves.toEqual([3]) + await expect(validateRpcArgs('fn', schema, [-1])).rejects.toThrow(/positive number/) + }) +}) + +describe('validateRpcReturn', () => { + it('passes through when no schema is declared', async () => { + await expect(validateRpcReturn('fn', undefined, { a: 1 })).resolves.toEqual({ a: 1 }) + }) + + it('returns the original value, preserving fields beyond the schema', async () => { + // Mirrors a real plugin (terminals) whose return schema is a subset of + // the payload — validation must not drop the undeclared field. + const schema = v.object({ id: v.string() }) + const value = { id: 'x', restartable: false } + await expect(validateRpcReturn('fn', schema, value)).resolves.toEqual({ id: 'x', restartable: false }) + }) + + it('throws DF0044 when the return fails its schema', async () => { + await expect(validateRpcReturn('fn', v.number(), 'not-a-number')).rejects.toThrow(/returns` schema/) + }) +}) + +describe('getRpcHandler validation wrapping', () => { + it('returns the raw handler untouched when no schemas are declared', async () => { + const original = (a: number, b: number): number => a + b + const fn = defineRpcFunction({ name: 'add', handler: original }) + const handler = await getRpcHandler(fn, undefined) + expect(handler).toBe(original) + expect(handler(2, 3)).toBe(5) + }) + + it('validates args before the handler runs', async () => { + const fn = defineRpcFunction({ + name: 'len', + args: [v.string()], + returns: v.number(), + handler: (s: string) => s.length * 2, + }) + const handler = await getRpcHandler(fn, undefined) + await expect(handler('hello')).resolves.toBe(10) + }) + + it('rejects invalid arguments with DF0043', async () => { + const fn = defineRpcFunction({ + name: 'greet', + args: [v.string()], + returns: v.string(), + handler: (name: string) => `hi ${name}`, + }) + const handler = await getRpcHandler(fn, undefined) + await expect(handler(42 as never)).rejects.toThrow(/invalid argument at position 0/) + }) + + it('rejects an invalid return value with DF0044', async () => { + const fn = defineRpcFunction({ + name: 'bad-return', + args: [], + returns: v.number(), + // Handler lies about its return type at runtime. + handler: () => 'not-a-number' as never, + }) + const handler = await getRpcHandler(fn, undefined) + await expect(handler()).rejects.toThrow(/failed its `returns` schema/) + }) + + it('works with a setup-provided handler', async () => { + const fn = defineRpcFunction({ + name: 'setup-fn', + args: [v.number()], + returns: v.number(), + setup: () => ({ handler: (n: number) => n + 1 }), + }) + const handler = await getRpcHandler(fn, undefined) + await expect(handler(1)).resolves.toBe(2) + await expect(handler('x' as never)).rejects.toThrow(/position 0/) + }) +}) diff --git a/packages/devframe/src/rpc/validate-io.ts b/packages/devframe/src/rpc/validate-io.ts new file mode 100644 index 00000000..286bc968 --- /dev/null +++ b/packages/devframe/src/rpc/validate-io.ts @@ -0,0 +1,84 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' +import type { RpcArgsSchema, RpcReturnSchema } from './types' +import { diagnostics } from './diagnostics' + +/** + * Run a single [Standard Schema](https://standardschema.dev) validator, + * awaiting the result when the validator is asynchronous. + */ +async function runStandardSchema( + schema: T, + value: unknown, +): Promise>> { + const result = schema['~standard'].validate(value) + return result instanceof Promise ? await result : result +} + +/** + * Render Standard Schema issues into a single human-readable line for a + * diagnostic message, prefixing each with its dotted path when present. + */ +function formatIssues(issues: readonly StandardSchemaV1.Issue[]): string { + return issues + .map((issue) => { + const path = issue.path + ?.map(segment => (typeof segment === 'object' ? segment.key : segment)) + .join('.') + return path ? `${path}: ${issue.message}` : issue.message + }) + .join('; ') +} + +/** + * Validate positional arguments against their declared schemas. Only + * indices with a schema are checked; extra arguments pass through + * untouched. Throws `DF0038` on the first failing argument. + * + * Validation guards the payload without rewriting it: the original values + * are handed to the handler unchanged, so a schema that describes a subset + * of an object never silently strips the sender's extra fields (and any + * declared transforms stay a purely type-level concern). + * + * @internal + */ +export async function validateRpcArgs( + name: string, + argsSchema: RpcArgsSchema | undefined, + args: readonly unknown[], +): Promise { + const original = args.slice() + if (!argsSchema || argsSchema.length === 0) + return original + + for (let index = 0; index < argsSchema.length; index++) { + const schema = argsSchema[index] + if (!schema) + continue + const result = await runStandardSchema(schema, args[index]) + if (result.issues) + throw diagnostics.DF0043({ name, index, issues: formatIssues(result.issues) }) + } + + return original +} + +/** + * Validate a handler's resolved return value against its declared schema. + * Throws `DF0039` when the value fails the schema, otherwise returns the + * original value unchanged (guard-only, never rewriting the payload — see + * {@link validateRpcArgs}). Passes through when no return schema is set. + * + * @internal + */ +export async function validateRpcReturn( + name: string, + returnSchema: RpcReturnSchema | undefined, + value: unknown, +): Promise { + if (!returnSchema) + return value + const result = await runStandardSchema(returnSchema, value) + if (result.issues) + throw diagnostics.DF0044({ name, issues: formatIssues(result.issues) }) + return value +} diff --git a/packages/devframe/src/types/devframe.ts b/packages/devframe/src/types/devframe.ts index cd650357..77dbde86 100644 --- a/packages/devframe/src/types/devframe.ts +++ b/packages/devframe/src/types/devframe.ts @@ -163,10 +163,11 @@ export interface DevframeCliOptions { */ configure?: (cli: CAC) => void /** - * Typed CLI flags for the default `dev` command, backed by valibot - * schemas. The adapter registers matching `--kebab-key` options on - * CAC, validates the parsed values, and forwards the typed bag to - * `setup(ctx, { flags })`. + * Typed CLI flags for the default `dev` command, backed by any + * [Standard Schema](https://standardschema.dev/) validator (valibot, + * zod, arktype, or devframe's built-in `s`). The adapter registers + * matching `--kebab-key` options on CAC, validates the parsed values, + * and forwards the typed bag to `setup(ctx, { flags })`. * * Use {@link defineCliFlags} to preserve the literal schema-map * shape, and {@link InferCliFlags} to recover the typed output at the diff --git a/packages/devframe/src/utils/simple-schema.test.ts b/packages/devframe/src/utils/simple-schema.test.ts new file mode 100644 index 00000000..e4d5fc82 --- /dev/null +++ b/packages/devframe/src/utils/simple-schema.test.ts @@ -0,0 +1,71 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' +import { describe, expect, it } from 'vitest' +import { s } from './simple-schema' + +function run(schema: T, value: unknown): StandardSchemaV1.Result> { + const result = schema['~standard'].validate(value) + if (result instanceof Promise) + throw new TypeError('unexpected async validator') + return result +} + +function accepts(schema: StandardSchemaV1, value: unknown): boolean { + return !run(schema, value).issues +} + +describe('utils/simple-schema builder', () => { + it('produces valid Standard Schema objects', () => { + const schema = s.string() + expect(schema['~standard'].version).toBe(1) + expect(schema['~standard'].vendor).toBe('devframe') + expect(typeof schema['~standard'].validate).toBe('function') + }) + + it('validates primitives', () => { + expect(accepts(s.string(), 'x')).toBe(true) + expect(accepts(s.string(), 1)).toBe(false) + expect(accepts(s.number(), 3)).toBe(true) + expect(accepts(s.number(), Number.NaN)).toBe(false) + expect(accepts(s.boolean(), true)).toBe(true) + expect(accepts(s.boolean(), 'true')).toBe(false) + expect(accepts(s.void(), undefined)).toBe(true) + expect(accepts(s.void(), null)).toBe(false) + expect(accepts(s.null(), null)).toBe(true) + }) + + it('handles picklist', () => { + const schema = s.picklist(['a', 'b'] as const) + expect(accepts(schema, 'a')).toBe(true) + expect(accepts(schema, 'c')).toBe(false) + }) + + it('handles optional and nullable wrappers', () => { + expect(accepts(s.optional(s.string()), undefined)).toBe(true) + expect(accepts(s.optional(s.string()), 'x')).toBe(true) + expect(accepts(s.optional(s.string()), 1)).toBe(false) + expect(accepts(s.nullable(s.number()), null)).toBe(true) + expect(accepts(s.nullable(s.number()), 2)).toBe(true) + expect(accepts(s.nullable(s.number()), 'x')).toBe(false) + }) + + it('exposes duck-typed kind markers for CLI-flag introspection', () => { + expect((s.boolean() as any).type).toBe('boolean') + expect((s.optional(s.boolean()) as any).type).toBe('optional') + expect((s.optional(s.boolean()) as any).wrapped['~standard'].vendor).toBe('devframe') + }) + + it('validates objects and reports issue paths', () => { + const schema = s.object({ id: s.string(), count: s.number() }) + expect(accepts(schema, { id: 'x', count: 1 })).toBe(true) + const bad = run(schema, { id: 'x', count: 'nope' }) + expect(bad.issues?.[0]?.path).toEqual(['count']) + }) + + it('keeps object keys beyond the schema (guard-only)', () => { + const schema = s.object({ id: s.string() }) + const result = run(schema, { id: 'x', extra: true }) + expect(result.issues).toBeUndefined() + if (!result.issues) + expect(result.value).toEqual({ id: 'x', extra: true }) + }) +}) diff --git a/packages/devframe/src/utils/simple-schema.ts b/packages/devframe/src/utils/simple-schema.ts new file mode 100644 index 00000000..2124d94e --- /dev/null +++ b/packages/devframe/src/utils/simple-schema.ts @@ -0,0 +1,265 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' + +/** + * A tiny, zero-dependency [Standard Schema](https://standardschema.dev/) + * builder. + * + * ⚠️ **Discouraged for app code.** This is a deliberately minimal, + * best-effort validator that exists only so devframe's own first-party + * packages (recipes, built-in plugins) can declare `args`/`returns`/flag + * schemas without taking on a validator dependency. It implements a small + * subset of primitives and approximates refinements — it is not a + * general-purpose validator. + * + * For your own code, prefer a real Standard Schema validator — **valibot**, + * **zod**, or **arktype**. Devframe's RPC and CLI-flag layers accept any of + * them; install the one you like and use it directly: + * + * ```ts + * import * as v from 'valibot' // npm i valibot + * + * defineRpcFunction({ + * name: 'greet', + * args: [v.object({ name: v.string() })], + * returns: v.string(), + * handler: ({ name }) => `hi ${name}`, + * }) + * ``` + */ + +/** + * A Standard Schema produced by the {@link s} builder. It carries a + * duck-typed `type` marker (and `wrapped` for wrappers) alongside the + * standard `~standard` prop so the CLI-flags adapter can introspect the + * schema kind without importing any validator. + */ +export interface SimpleSchema extends StandardSchemaV1 { + /** Schema kind marker, e.g. `'string'`, `'boolean'`, `'optional'`. */ + readonly type: string + /** Inner schema for wrapper kinds (`optional` / `nullable`). */ + readonly wrapped?: StandardSchemaV1 + /** Optional human description (surfaced as CLI option help). */ + readonly description?: string +} + +type Issue = StandardSchemaV1.Issue + +function ok(value: T): StandardSchemaV1.Result { + return { value } +} + +function fail(message: string, path?: Issue['path']): StandardSchemaV1.FailureResult { + return { issues: [path ? { message, path } : { message }] } +} + +function make( + type: string, + validate: StandardSchemaV1.Props['validate'], + extra?: Record, +): SimpleSchema { + return { + type, + ...extra, + '~standard': { + version: 1, + vendor: 'devframe', + validate, + }, + } as SimpleSchema +} + +/** Run a Standard Schema synchronously, rejecting async validators. */ +function runSync( + schema: T, + value: unknown, +): StandardSchemaV1.Result> { + const result = schema['~standard'].validate(value) + if (result instanceof Promise) + throw new TypeError('[devframe/utils/simple-schema] async validators are not supported inside object()/optional()/nullable()') + return result +} + +/** Any string. */ +export function string(): SimpleSchema { + return make('string', v => (typeof v === 'string' ? ok(v) : fail('Expected a string'))) +} + +/** A finite number (rejects `NaN`). */ +export function number(): SimpleSchema { + return make('number', v => (typeof v === 'number' && !Number.isNaN(v) ? ok(v) : fail('Expected a number'))) +} + +/** A boolean. */ +export function boolean(): SimpleSchema { + return make('boolean', v => (typeof v === 'boolean' ? ok(v) : fail('Expected a boolean'))) +} + +/** `undefined` — mirrors valibot's `void`. */ +export function voidType(): SimpleSchema { + return make('void', v => (v === undefined ? ok(undefined) : fail('Expected undefined'))) +} + +/** `null`. */ +export function nullType(): SimpleSchema { + return make('null', v => (v === null ? ok(null) : fail('Expected null'))) +} + +/** One of a fixed set of literal values. */ +export function picklist( + values: T, +): SimpleSchema { + const set = new Set(values) + return make( + 'picklist', + v => (set.has(v) ? ok(v as T[number]) : fail(`Expected one of: ${values.join(', ')}`)), + { values }, + ) +} + +/** A single literal value (string / number / boolean). */ +export function literal(value: T): SimpleSchema { + return make('literal', v => (v === value ? ok(v as T) : fail(`Expected ${JSON.stringify(value)}`)), { value }) +} + +/** A value matching any one of the given schemas. */ +export function union( + options: T, +): SimpleSchema, StandardSchemaV1.InferOutput> { + return make('union', (v) => { + const issues: Issue[] = [] + for (const option of options) { + const result = runSync(option, v) + if (!result.issues) + return ok(v as any) + issues.push(...result.issues) + } + return { issues } + }, { options }) +} + +/** A record with string keys whose values each satisfy the value schema. */ +export function record( + _key: StandardSchemaV1, + value: V, +): SimpleSchema>, Record>> { + return make('record', (v) => { + if (typeof v !== 'object' || v === null || Array.isArray(v)) + return fail('Expected an object') + const obj = v as Record + const issues: Issue[] = [] + for (const key of Object.keys(obj)) { + const result = runSync(value, obj[key]) + if (result.issues) { + for (const issue of result.issues) + issues.push({ message: issue.message, path: [key, ...(issue.path ?? [])] }) + } + } + return issues.length ? { issues } : ok(v as any) + }) +} + +/** An array whose every element satisfies the item schema. */ +export function array( + item: T, +): SimpleSchema[], StandardSchemaV1.InferOutput[]> { + return make('array', (v) => { + if (!Array.isArray(v)) + return fail('Expected an array') + const issues: Issue[] = [] + for (let i = 0; i < v.length; i++) { + const result = runSync(item, v[i]) + if (result.issues) { + for (const issue of result.issues) + issues.push({ message: issue.message, path: [i, ...(issue.path ?? [])] }) + } + } + return issues.length ? { issues } : ok(v as any) + }) +} + +/** Flatten an intersection into a single object literal for readable types. */ +type Prettify = { [K in keyof T]: T[K] } & {} + +/** + * Map a shape to its object type, turning fields whose type includes + * `undefined` (i.e. `optional()`) into optional keys — mirroring how + * valibot/zod render `optional` object entries. + */ +type InferField + = Mode extends 'input' ? StandardSchemaV1.InferInput : StandardSchemaV1.InferOutput + +type InferObject, Mode extends 'input' | 'output'> = Prettify< + & { [K in keyof T as undefined extends InferField ? never : K]: InferField } + & { [K in keyof T as undefined extends InferField ? K : never]?: InferField } +> + +/** An object whose known keys each satisfy their schema (extra keys are kept). */ +export function object>( + shape: T, +): SimpleSchema, InferObject> { + const entries = Object.entries(shape) + return make('object', (v) => { + if (typeof v !== 'object' || v === null || Array.isArray(v)) + return fail('Expected an object') + const obj = v as Record + const issues: Issue[] = [] + for (const [key, schema] of entries) { + const result = runSync(schema, obj[key]) + if (result.issues) { + for (const issue of result.issues) + issues.push({ message: issue.message, path: [key, ...(issue.path ?? [])] }) + } + } + // Guard-only: return the original object so extra keys survive. + return issues.length ? { issues } : ok(v as any) + }) +} + +/** Allow `undefined` in addition to the inner schema. */ +export function optional( + inner: T, +): SimpleSchema | undefined, StandardSchemaV1.InferOutput | undefined> { + return make( + 'optional', + v => (v === undefined ? ok(undefined) : runSync(inner, v)), + { wrapped: inner }, + ) +} + +/** Allow `null` in addition to the inner schema. */ +export function nullable( + inner: T, +): SimpleSchema | null, StandardSchemaV1.InferOutput | null> { + return make( + 'nullable', + v => (v === null ? ok(null) : runSync(inner, v)), + { wrapped: inner }, + ) +} + +/** Attach a human-readable description (used for CLI option help). */ +export function describe>(schema: T, description: string): T { + return { ...schema, description } +} + +/** + * Grouped access to every builder — `s.string()`, `s.object({ ... })`, + * `s.void()`, etc. Handy for a valibot-like `import { s } from + * 'devframe/utils/simple-schema'` call site. + */ +export const s = { + string, + number, + boolean, + void: voidType, + null: nullType, + literal, + picklist, + union, + record, + array, + object, + optional, + nullable, + describe, +} as const diff --git a/packages/devframe/tsdown.config.ts b/packages/devframe/tsdown.config.ts index ee003592..6f1ffe4f 100644 --- a/packages/devframe/tsdown.config.ts +++ b/packages/devframe/tsdown.config.ts @@ -75,6 +75,7 @@ const clientEntries = { 'utils/hash': 'src/utils/hash.ts', 'utils/nanoid': 'src/utils/nanoid.ts', 'utils/promise': 'src/utils/promise.ts', + 'utils/simple-schema': 'src/utils/simple-schema.ts', 'utils/scope': 'src/utils/scope.ts', 'utils/shared-state': 'src/utils/shared-state.ts', 'utils/streaming-channel': 'src/utils/streaming-channel.ts', @@ -148,6 +149,7 @@ export default defineConfig([ resolve(distDir, 'utils/hash.mjs'), resolve(distDir, 'utils/nanoid.mjs'), resolve(distDir, 'utils/promise.mjs'), + resolve(distDir, 'utils/simple-schema.mjs'), resolve(distDir, 'utils/scope.mjs'), resolve(distDir, 'utils/shared-state.mjs'), resolve(distDir, 'utils/streaming-channel.mjs'), diff --git a/plugins/assets/package.json b/plugins/assets/package.json index 212430ab..067e6981 100644 --- a/plugins/assets/package.json +++ b/plugins/assets/package.json @@ -64,8 +64,7 @@ "pathe": "catalog:deps", "perfect-debounce": "catalog:deps", "tinyglobby": "catalog:deps", - "ufo": "catalog:deps", - "valibot": "catalog:deps" + "ufo": "catalog:deps" }, "devDependencies": { "@antfu/design": "catalog:frontend", diff --git a/plugins/assets/src/rpc/functions/capabilities.ts b/plugins/assets/src/rpc/functions/capabilities.ts index 09c9997c..97f38ad5 100644 --- a/plugins/assets/src/rpc/functions/capabilities.ts +++ b/plugins/assets/src/rpc/functions/capabilities.ts @@ -1,6 +1,6 @@ import type { DevframeNodeContext } from 'devframe/types' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -22,9 +22,9 @@ export const capabilities = defineAssetsRpc({ snapshot: true, jsonSerializable: true, args: [], - returns: v.object({ - write: v.boolean(), - uploadExtensions: v.union([v.array(v.string()), v.literal('*')]), + returns: s.object({ + write: s.boolean(), + uploadExtensions: s.union([s.array(s.string()), s.literal('*')]), }), agent: { title: 'Read assets capabilities', diff --git a/plugins/assets/src/rpc/functions/delete.ts b/plugins/assets/src/rpc/functions/delete.ts index 3e363f5a..e5654e56 100644 --- a/plugins/assets/src/rpc/functions/delete.ts +++ b/plugins/assets/src/rpc/functions/delete.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext } from 'devframe/types' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -11,8 +11,8 @@ export const deleteAssets = defineAssetsRpc({ name: 'devframes:plugin:assets:delete', type: 'action', jsonSerializable: true, - args: [v.object({ paths: v.array(v.string()) })], - returns: v.object({ deleted: v.array(v.string()) }), + args: [s.object({ paths: s.array(s.string()) })], + returns: s.object({ deleted: s.array(s.string()) }), agent: { title: 'Delete assets', description: 'Delete one or more assets from the managed directory.', diff --git a/plugins/assets/src/rpc/functions/list.ts b/plugins/assets/src/rpc/functions/list.ts index 5134c9d0..9116a9d3 100644 --- a/plugins/assets/src/rpc/functions/list.ts +++ b/plugins/assets/src/rpc/functions/list.ts @@ -1,18 +1,18 @@ import type { DevframeNodeContext } from 'devframe/types' import type { AssetInfo } from '../../types' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getAssetsContext } from '../../node/context' import { scanAssets } from '../../node/scanner' const defineAssetsRpc = createDefineWrapperWithContext() -export const assetInfoSchema = v.object({ - path: v.string(), - type: v.picklist(['image', 'font', 'video', 'audio', 'text', 'other']), - publicPath: v.string(), - size: v.number(), - mtime: v.number(), +export const assetInfoSchema = s.object({ + path: s.string(), + type: s.picklist(['image', 'font', 'video', 'audio', 'text', 'other']), + publicPath: s.string(), + size: s.number(), + mtime: s.number(), }) export const list = defineAssetsRpc({ @@ -21,7 +21,7 @@ export const list = defineAssetsRpc({ snapshot: true, jsonSerializable: true, args: [], - returns: v.array(assetInfoSchema), + returns: s.array(assetInfoSchema), agent: { title: 'List managed assets', description: 'List every file under the managed directory with its type, size, and last-modified time.', diff --git a/plugins/assets/src/rpc/functions/mkdir.ts b/plugins/assets/src/rpc/functions/mkdir.ts index 8b5d085e..6ecbd744 100644 --- a/plugins/assets/src/rpc/functions/mkdir.ts +++ b/plugins/assets/src/rpc/functions/mkdir.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext } from 'devframe/types' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { diagnostics } from '../../diagnostics' import { getAssetsContext } from '../../node/context' @@ -11,8 +11,8 @@ export const mkdir = defineAssetsRpc({ name: 'devframes:plugin:assets:mkdir', type: 'action', jsonSerializable: true, - args: [v.object({ path: v.string() })], - returns: v.void(), + args: [s.object({ path: s.string() })], + returns: s.void(), agent: { title: 'Create a folder', description: 'Create a folder under the managed directory, including any missing parent folders.', diff --git a/plugins/assets/src/rpc/functions/open-in-editor.ts b/plugins/assets/src/rpc/functions/open-in-editor.ts index a0810232..10b0fcd1 100644 --- a/plugins/assets/src/rpc/functions/open-in-editor.ts +++ b/plugins/assets/src/rpc/functions/open-in-editor.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext } from 'devframe/types' import { createDefineWrapperWithContext } from 'devframe/rpc' import { launchEditor } from 'devframe/utils/launch-editor' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -16,8 +16,8 @@ export const openInEditor = defineAssetsRpc({ name: 'devframes:plugin:assets:open-in-editor', type: 'action', jsonSerializable: true, - args: [v.string()], - returns: v.void(), + args: [s.string()], + returns: s.void(), agent: { title: 'Open an asset in the editor', description: 'Open an asset in the user\'s configured editor.', diff --git a/plugins/assets/src/rpc/functions/read-image-meta.ts b/plugins/assets/src/rpc/functions/read-image-meta.ts index 26b5e643..f35abda7 100644 --- a/plugins/assets/src/rpc/functions/read-image-meta.ts +++ b/plugins/assets/src/rpc/functions/read-image-meta.ts @@ -2,8 +2,8 @@ import type { DevframeNodeContext } from 'devframe/types' import type { AssetImageMeta } from '../../types' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' +import { s } from 'devframe/utils/simple-schema' import { imageMeta } from 'image-meta' -import * as v from 'valibot' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -12,11 +12,11 @@ export const readImageMeta = defineAssetsRpc({ name: 'devframes:plugin:assets:read-image-meta', type: 'query', jsonSerializable: true, - args: [v.string()], - returns: v.nullable(v.object({ - width: v.optional(v.number()), - height: v.optional(v.number()), - orientation: v.optional(v.number()), + args: [s.string()], + returns: s.nullable(s.object({ + width: s.optional(s.number()), + height: s.optional(s.number()), + orientation: s.optional(s.number()), })), agent: { title: 'Read image dimensions', diff --git a/plugins/assets/src/rpc/functions/read-text.ts b/plugins/assets/src/rpc/functions/read-text.ts index e1b9da04..36563216 100644 --- a/plugins/assets/src/rpc/functions/read-text.ts +++ b/plugins/assets/src/rpc/functions/read-text.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext } from 'devframe/types' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -12,8 +12,8 @@ export const readText = defineAssetsRpc({ name: 'devframes:plugin:assets:read-text', type: 'query', jsonSerializable: true, - args: [v.string(), v.optional(v.number())], - returns: v.nullable(v.string()), + args: [s.string(), s.optional(s.number())], + returns: s.nullable(s.string()), agent: { title: 'Read a text asset', description: 'Read the (possibly truncated) text content of a text-type asset, for preview or editing.', diff --git a/plugins/assets/src/rpc/functions/rename.ts b/plugins/assets/src/rpc/functions/rename.ts index 2f555d50..5dda4489 100644 --- a/plugins/assets/src/rpc/functions/rename.ts +++ b/plugins/assets/src/rpc/functions/rename.ts @@ -2,8 +2,8 @@ import type { DevframeNodeContext } from 'devframe/types' import type { AssetInfo } from '../../types' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' +import { s } from 'devframe/utils/simple-schema' import { dirname, extname } from 'pathe' -import * as v from 'valibot' import { diagnostics } from '../../diagnostics' import { getAssetsContext } from '../../node/context' import { statToAssetInfo } from '../../node/scanner' @@ -27,7 +27,7 @@ export const rename = defineAssetsRpc({ name: 'devframes:plugin:assets:rename', type: 'action', jsonSerializable: true, - args: [v.object({ path: v.string(), newName: v.string() })], + args: [s.object({ path: s.string(), newName: s.string() })], returns: assetInfoSchema, agent: { title: 'Rename an asset', diff --git a/plugins/assets/src/rpc/functions/reveal-in-folder.ts b/plugins/assets/src/rpc/functions/reveal-in-folder.ts index 0c2b3d8a..c3c9df6a 100644 --- a/plugins/assets/src/rpc/functions/reveal-in-folder.ts +++ b/plugins/assets/src/rpc/functions/reveal-in-folder.ts @@ -1,8 +1,8 @@ import type { DevframeNodeContext } from 'devframe/types' import { createDefineWrapperWithContext } from 'devframe/rpc' import { open } from 'devframe/utils/open' +import { s } from 'devframe/utils/simple-schema' import { dirname } from 'pathe' -import * as v from 'valibot' import { getAssetsContext } from '../../node/context' const defineAssetsRpc = createDefineWrapperWithContext() @@ -17,8 +17,8 @@ export const revealInFolder = defineAssetsRpc({ name: 'devframes:plugin:assets:reveal-in-folder', type: 'action', jsonSerializable: true, - args: [v.string()], - returns: v.void(), + args: [s.string()], + returns: s.void(), agent: { title: 'Reveal an asset in the file manager', description: 'Open the OS file manager at the asset\'s containing folder.', diff --git a/plugins/assets/src/rpc/functions/upload.ts b/plugins/assets/src/rpc/functions/upload.ts index e86aa1b3..ca5f656e 100644 --- a/plugins/assets/src/rpc/functions/upload.ts +++ b/plugins/assets/src/rpc/functions/upload.ts @@ -2,8 +2,8 @@ import type { DevframeNodeContext } from 'devframe/types' import { createWriteStream } from 'node:fs' import fsp from 'node:fs/promises' import { createDefineWrapperWithContext } from 'devframe/rpc' +import { s } from 'devframe/utils/simple-schema' import { dirname, extname } from 'pathe' -import * as v from 'valibot' import { diagnostics } from '../../diagnostics' import { getAssetsContext } from '../../node/context' @@ -28,8 +28,8 @@ export const upload = defineAssetsRpc({ name: 'devframes:plugin:assets:upload', type: 'action', jsonSerializable: true, - args: [v.object({ path: v.string() })], - returns: v.object({ uploadId: v.string() }), + args: [s.object({ path: s.string() })], + returns: s.object({ uploadId: s.string() }), agent: { title: 'Upload an asset', description: 'Allocate an upload slot for a new file at the given path. The caller streams the bytes over the paired upload channel.', diff --git a/plugins/inspect/src/rpc/functions/_schema.ts b/plugins/inspect/src/rpc/functions/_schema.ts index 3f4bc967..0562e26e 100644 --- a/plugins/inspect/src/rpc/functions/_schema.ts +++ b/plugins/inspect/src/rpc/functions/_schema.ts @@ -1,16 +1,24 @@ +import type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec' import { toJsonSchema } from '@valibot/to-json-schema' const FALLBACK_SCHEMA = Object.freeze({ type: 'object', additionalProperties: true }) +/** A `~standard` prop that may also carry the Standard JSON Schema converter. */ +type MaybeJsonSchema = StandardSchemaV1['~standard'] & Partial + /** - * Convert a valibot return schema to JSON Schema, swallowing - * conversion failures (unsupported valibot actions) into a permissive - * fallback so introspection never throws. + * Convert a schema to JSON Schema for the inspector, vendor-neutrally. + * + * Prefers the schema's own Standard JSON Schema converter + * (`~standard.jsonSchema`, implemented by e.g. zod 4), then falls back to + * valibot's converter, then to a permissive object — so introspection never + * throws regardless of which validator produced the schema. */ -export function returnSchemaToJson(schema: unknown): unknown { - if (!schema) - return undefined +function convert(schema: unknown): unknown { + const standard = (schema as StandardSchemaV1)['~standard'] as MaybeJsonSchema try { + if (standard.jsonSchema) + return standard.jsonSchema.input({ target: 'draft-2020-12' }) return toJsonSchema(schema as never) } catch { @@ -19,22 +27,25 @@ export function returnSchemaToJson(schema: unknown): unknown { } /** - * Convert the positional args valibot schemas to a single JSON Schema - * tuple (`type: 'array'` + `prefixItems`). Returns `undefined` when the - * function declares no args. + * Convert an RPC return schema to JSON Schema, swallowing conversion + * failures into a permissive fallback so introspection never throws. + */ +export function returnSchemaToJson(schema: unknown): unknown { + if (!schema) + return undefined + return convert(schema) +} + +/** + * Convert positional args schemas to a single JSON Schema tuple + * (`type: 'array'` + `prefixItems`). Returns `undefined` when the function + * declares no args. */ export function argsSchemaToJson(args: readonly unknown[] | undefined): unknown { if (!args || args.length === 0) return undefined return { type: 'array', - prefixItems: args.map((arg) => { - try { - return toJsonSchema(arg as never) - } - catch { - return FALLBACK_SCHEMA - } - }), + prefixItems: args.map(arg => convert(arg)), } } diff --git a/plugins/og/package.json b/plugins/og/package.json index b80aa855..808efdb2 100644 --- a/plugins/og/package.json +++ b/plugins/og/package.json @@ -60,8 +60,7 @@ "dependencies": { "cac": "catalog:deps", "nostics": "catalog:deps", - "parse5": "catalog:deps", - "valibot": "catalog:deps" + "parse5": "catalog:deps" }, "devDependencies": { "@antfu/design": "catalog:frontend", diff --git a/plugins/og/src/rpc/functions/resolve-metadata.ts b/plugins/og/src/rpc/functions/resolve-metadata.ts index f12f3445..5b36b02d 100644 --- a/plugins/og/src/rpc/functions/resolve-metadata.ts +++ b/plugins/og/src/rpc/functions/resolve-metadata.ts @@ -1,7 +1,7 @@ import type { DevframeNodeContext } from 'devframe/types' import type { OgFetch, OgSnapshot } from '../../types' import { createDefineWrapperWithContext } from 'devframe/rpc' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { diagnostics } from '../../diagnostics' import { fetchOgMetadata } from '../../node/metadata' @@ -18,18 +18,18 @@ const EMPTY_SNAPSHOT: OgSnapshot = { tags: [], } -const tagSchema = v.object({ - tag: v.picklist(['html', 'link', 'meta', 'title']), - name: v.string(), - value: v.string(), +const tagSchema = s.object({ + tag: s.picklist(['html', 'link', 'meta', 'title']), + name: s.string(), + value: s.string(), }) -const snapshotSchema = v.object({ - requestedUrl: v.string(), - url: v.string(), - status: v.number(), - fetchedAt: v.number(), - tags: v.array(tagSchema), +const snapshotSchema = s.object({ + requestedUrl: s.string(), + url: s.string(), + status: s.number(), + fetchedAt: s.number(), + tags: s.array(tagSchema), }) const defineOgRpc = createDefineWrapperWithContext() @@ -39,7 +39,7 @@ export function createResolveMetadataRpc(options: ResolveMetadataOptions = {}) { name: 'devframes:plugin:og:resolve-metadata', type: 'query', jsonSerializable: true, - args: [v.object({ url: v.optional(v.string()) })], + args: [s.object({ url: s.optional(s.string()) })], returns: snapshotSchema, agent: { title: 'Inspect Open Graph metadata', diff --git a/plugins/terminals/package.json b/plugins/terminals/package.json index b0de54f5..b07e3e94 100644 --- a/plugins/terminals/package.json +++ b/plugins/terminals/package.json @@ -62,7 +62,6 @@ "cac": "catalog:deps", "nostics": "catalog:deps", "pathe": "catalog:deps", - "valibot": "catalog:deps", "zigpty": "catalog:deps" }, "devDependencies": { diff --git a/plugins/terminals/src/rpc/functions/clear-exited.ts b/plugins/terminals/src/rpc/functions/clear-exited.ts index 83c302d4..5753716b 100644 --- a/plugins/terminals/src/rpc/functions/clear-exited.ts +++ b/plugins/terminals/src/rpc/functions/clear-exited.ts @@ -1,5 +1,5 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const clearExited = defineRpcFunction({ @@ -7,7 +7,7 @@ export const clearExited = defineRpcFunction({ type: 'action', jsonSerializable: true, args: [], - returns: v.void(), + returns: s.void(), agent: { description: 'Discard every stopped (exited or errored) terminal session at once. Running sessions are left untouched.', safety: 'destructive', diff --git a/plugins/terminals/src/rpc/functions/list.ts b/plugins/terminals/src/rpc/functions/list.ts index 1f01bcf2..759bf3e9 100644 --- a/plugins/terminals/src/rpc/functions/list.ts +++ b/plugins/terminals/src/rpc/functions/list.ts @@ -1,5 +1,5 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' import { sessionInfoSchema } from '../schemas' @@ -9,7 +9,7 @@ export const list = defineRpcFunction({ jsonSerializable: true, snapshot: true, args: [], - returns: v.array(sessionInfoSchema), + returns: s.array(sessionInfoSchema), agent: { description: 'List the current terminal sessions with their status, mode, and command.', safety: 'read', diff --git a/plugins/terminals/src/rpc/functions/presets.ts b/plugins/terminals/src/rpc/functions/presets.ts index e5c71fee..518f05f5 100644 --- a/plugins/terminals/src/rpc/functions/presets.ts +++ b/plugins/terminals/src/rpc/functions/presets.ts @@ -1,5 +1,5 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' import { presetSchema } from '../schemas' @@ -9,7 +9,7 @@ export const presets = defineRpcFunction({ jsonSerializable: true, snapshot: true, args: [], - returns: v.array(presetSchema), + returns: s.array(presetSchema), setup: ctx => ({ handler: () => getTerminalManager(ctx).getPresets().map(p => ({ id: p.id, diff --git a/plugins/terminals/src/rpc/functions/remove.ts b/plugins/terminals/src/rpc/functions/remove.ts index be91aa1c..4bf31a6e 100644 --- a/plugins/terminals/src/rpc/functions/remove.ts +++ b/plugins/terminals/src/rpc/functions/remove.ts @@ -1,13 +1,13 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const remove = defineRpcFunction({ name: 'devframes:plugin:terminals:remove', type: 'action', jsonSerializable: true, - args: [v.object({ id: v.string() })], - returns: v.void(), + args: [s.object({ id: s.string() })], + returns: s.void(), agent: { description: 'Kill a terminal session and discard it (process, stream, and scrollback).', safety: 'destructive', diff --git a/plugins/terminals/src/rpc/functions/rename.ts b/plugins/terminals/src/rpc/functions/rename.ts index 8eac1d0c..4239a2b4 100644 --- a/plugins/terminals/src/rpc/functions/rename.ts +++ b/plugins/terminals/src/rpc/functions/rename.ts @@ -1,13 +1,13 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const rename = defineRpcFunction({ name: 'devframes:plugin:terminals:rename', type: 'action', jsonSerializable: true, - args: [v.object({ id: v.string(), title: v.string() })], - returns: v.void(), + args: [s.object({ id: s.string(), title: s.string() })], + returns: s.void(), setup: ctx => ({ handler: ({ id, title }) => { getTerminalManager(ctx).rename(id, title) diff --git a/plugins/terminals/src/rpc/functions/resize.ts b/plugins/terminals/src/rpc/functions/resize.ts index e92e0e0e..7c29285d 100644 --- a/plugins/terminals/src/rpc/functions/resize.ts +++ b/plugins/terminals/src/rpc/functions/resize.ts @@ -1,17 +1,17 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const resize = defineRpcFunction({ name: 'devframes:plugin:terminals:resize', type: 'action', jsonSerializable: true, - args: [v.object({ - id: v.string(), - cols: v.pipe(v.number(), v.integer(), v.minValue(1)), - rows: v.pipe(v.number(), v.integer(), v.minValue(1)), + args: [s.object({ + id: s.string(), + cols: s.number(), + rows: s.number(), })], - returns: v.void(), + returns: s.void(), setup: ctx => ({ handler: ({ id, cols, rows }) => { getTerminalManager(ctx).resize(id, cols, rows) diff --git a/plugins/terminals/src/rpc/functions/restart.ts b/plugins/terminals/src/rpc/functions/restart.ts index eb8f9f9c..5fe4d46e 100644 --- a/plugins/terminals/src/rpc/functions/restart.ts +++ b/plugins/terminals/src/rpc/functions/restart.ts @@ -1,5 +1,5 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' import { sessionInfoSchema } from '../schemas' @@ -7,7 +7,7 @@ export const restart = defineRpcFunction({ name: 'devframes:plugin:terminals:restart', type: 'action', jsonSerializable: true, - args: [v.object({ id: v.string() })], + args: [s.object({ id: s.string() })], returns: sessionInfoSchema, setup: ctx => ({ handler: ({ id }) => getTerminalManager(ctx).restart(id), diff --git a/plugins/terminals/src/rpc/functions/terminate.ts b/plugins/terminals/src/rpc/functions/terminate.ts index b3fc0dc6..e58c8c33 100644 --- a/plugins/terminals/src/rpc/functions/terminate.ts +++ b/plugins/terminals/src/rpc/functions/terminate.ts @@ -1,13 +1,13 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const terminate = defineRpcFunction({ name: 'devframes:plugin:terminals:terminate', type: 'action', jsonSerializable: true, - args: [v.object({ id: v.string() })], - returns: v.void(), + args: [s.object({ id: s.string() })], + returns: s.void(), agent: { description: 'Terminate a terminal session\'s running process. The session and its scrollback are kept; use restart to run it again.', safety: 'destructive', diff --git a/plugins/terminals/src/rpc/functions/write.ts b/plugins/terminals/src/rpc/functions/write.ts index 147acbc3..c175e2a9 100644 --- a/plugins/terminals/src/rpc/functions/write.ts +++ b/plugins/terminals/src/rpc/functions/write.ts @@ -1,13 +1,13 @@ import { defineRpcFunction } from 'devframe' -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' import { getTerminalManager } from '../../node/context' export const write = defineRpcFunction({ name: 'devframes:plugin:terminals:write', type: 'action', jsonSerializable: true, - args: [v.object({ id: v.string(), data: v.string() })], - returns: v.void(), + args: [s.object({ id: s.string(), data: s.string() })], + returns: s.void(), setup: ctx => ({ handler: ({ id, data }) => { getTerminalManager(ctx).write(id, data) diff --git a/plugins/terminals/src/rpc/schemas.ts b/plugins/terminals/src/rpc/schemas.ts index 96d9b17d..d368edc3 100644 --- a/plugins/terminals/src/rpc/schemas.ts +++ b/plugins/terminals/src/rpc/schemas.ts @@ -1,45 +1,45 @@ -import * as v from 'valibot' +import { s } from 'devframe/utils/simple-schema' -export const terminalModeSchema = v.picklist(['interactive', 'readonly']) +export const terminalModeSchema = s.picklist(['interactive', 'readonly']) -export const spawnRequestSchema = v.object({ - presetId: v.optional(v.string()), - command: v.optional(v.string()), - args: v.optional(v.array(v.string())), - cwd: v.optional(v.string()), - mode: v.optional(terminalModeSchema), - title: v.optional(v.string()), - cols: v.optional(v.number()), - rows: v.optional(v.number()), - env: v.optional(v.record(v.string(), v.string())), +export const spawnRequestSchema = s.object({ + presetId: s.optional(s.string()), + command: s.optional(s.string()), + args: s.optional(s.array(s.string())), + cwd: s.optional(s.string()), + mode: s.optional(terminalModeSchema), + title: s.optional(s.string()), + cols: s.optional(s.number()), + rows: s.optional(s.number()), + env: s.optional(s.record(s.string(), s.string())), }) -export const sessionInfoSchema = v.object({ - id: v.string(), - title: v.string(), - processName: v.optional(v.string()), - customTitle: v.optional(v.string()), +export const sessionInfoSchema = s.object({ + id: s.string(), + title: s.string(), + processName: s.optional(s.string()), + customTitle: s.optional(s.string()), mode: terminalModeSchema, - status: v.picklist(['running', 'exited', 'error']), - backend: v.picklist(['pty', 'pipe']), - command: v.string(), - args: v.array(v.string()), - cwd: v.string(), - cols: v.number(), - rows: v.number(), - pid: v.optional(v.number()), - exitCode: v.optional(v.number()), - icon: v.optional(v.string()), - channel: v.optional(v.string()), - presetId: v.optional(v.string()), - createdAt: v.number(), + status: s.picklist(['running', 'exited', 'error']), + backend: s.picklist(['pty', 'pipe']), + command: s.string(), + args: s.array(s.string()), + cwd: s.string(), + cols: s.number(), + rows: s.number(), + pid: s.optional(s.number()), + exitCode: s.optional(s.number()), + icon: s.optional(s.string()), + channel: s.optional(s.string()), + presetId: s.optional(s.string()), + createdAt: s.number(), }) -export const presetSchema = v.object({ - id: v.string(), - title: v.string(), - command: v.string(), - args: v.array(v.string()), +export const presetSchema = s.object({ + id: s.string(), + title: s.string(), + command: s.string(), + args: s.array(s.string()), mode: terminalModeSchema, - icon: v.optional(v.string()), + icon: s.optional(s.string()), }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3be2edcc..9957fc33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,6 +49,9 @@ catalogs: '@modelcontextprotocol/server': specifier: ^2.0.0 version: 2.0.0 + '@standard-schema/spec': + specifier: ^1.1.0 + version: 1.1.0 '@valibot/to-json-schema': specifier: ^1.7.1 version: 1.7.1 @@ -343,8 +346,23 @@ catalogs: version: 8.18.1 overrides: + '@devframe/hub': workspace:* + '@devframe/json-render': workspace:* + '@devframe/json-render-ui': workspace:* + '@devframe/next': workspace:* + '@devframe/nuxt': workspace:* + '@devframe/plugin-a11y': workspace:* + '@devframe/plugin-assets': workspace:* + '@devframe/plugin-code-server': workspace:* + '@devframe/plugin-data-inspector': workspace:* + '@devframe/plugin-git': workspace:* + '@devframe/plugin-inspect': workspace:* + '@devframe/plugin-messages': workspace:* + '@devframe/plugin-og': workspace:* + '@devframe/plugin-terminals': workspace:* chokidar: ^5.0.0 crossws: ^0.4.10 + devframe: workspace:* semver: ^7.8.5 shell-quote: ^1.10.0 @@ -785,9 +803,9 @@ importers: packages/devframe: dependencies: - '@valibot/to-json-schema': + '@standard-schema/spec': specifier: catalog:deps - version: 1.7.1(valibot@1.4.2(typescript@6.0.3)) + version: 1.1.0 birpc: specifier: catalog:deps version: 4.0.0 @@ -812,9 +830,6 @@ importers: ufo: specifier: catalog:deps version: 1.6.4 - valibot: - specifier: catalog:deps - version: 1.4.2(typescript@6.0.3) devDependencies: '@modelcontextprotocol/client': specifier: catalog:deps @@ -864,6 +879,9 @@ importers: ua-parser-modern: specifier: catalog:inlined version: 0.1.1 + valibot: + specifier: catalog:deps + version: 1.4.2(typescript@6.0.3) whenexpr: specifier: catalog:deps version: 0.1.2 @@ -1020,7 +1038,7 @@ importers: version: link:../devframe nuxt: specifier: catalog:build - version: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) + version: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) tsdown: specifier: catalog:build version: 0.22.14(@volar/typescript@2.4.28)(oxc-resolver@11.21.3)(tsx@4.23.1)(typescript@6.0.3) @@ -1103,9 +1121,6 @@ importers: ufo: specifier: catalog:deps version: 1.6.4 - valibot: - specifier: catalog:deps - version: 1.4.2(typescript@6.0.3) devDependencies: '@antfu/design': specifier: catalog:frontend @@ -1556,9 +1571,6 @@ importers: parse5: specifier: catalog:deps version: 8.0.1 - valibot: - specifier: catalog:deps - version: 1.4.2(typescript@6.0.3) devDependencies: '@antfu/design': specifier: catalog:frontend @@ -1620,9 +1632,6 @@ importers: pathe: specifier: catalog:deps version: 2.0.3 - valibot: - specifier: catalog:deps - version: 1.4.2(typescript@6.0.3) zigpty: specifier: catalog:deps version: 0.2.1 @@ -2045,13 +2054,13 @@ packages: '@devframes/hub@0.7.14': resolution: {integrity: sha512-Ym3YHkBnpdwhPw7y4YgURZYntQPShb9raRfo60D1Yk4jb1OlnL2GGHw6pt4iLZqHL4vp1P4T6YpBFPPVx4G38A==} peerDependencies: - devframe: 0.7.14 + devframe: workspace:* '@devframes/json-render@0.7.14': resolution: {integrity: sha512-Bo+IiRpEdceQjLr/tcFNXFYlBkSeUv7PWsFc4Fu5PLUyxnnqciLVyFjZz6IlEtKrBIA667L4QbQe5ZExlPhlPA==} peerDependencies: '@devframes/hub': 0.7.14 - devframe: 0.7.14 + devframe: workspace:* peerDependenciesMeta: '@devframes/hub': optional: true @@ -2378,12 +2387,6 @@ packages: '@floating-ui/vue@1.1.11': resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} - '@hono/node-server@1.19.14': - resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -2664,16 +2667,6 @@ packages: resolution: {integrity: sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==} engines: {node: '>=20'} - '@modelcontextprotocol/sdk@1.30.0': - resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - '@modelcontextprotocol/server@2.0.0': resolution: {integrity: sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==} engines: {node: '>=20'} @@ -5223,10 +5216,6 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -5251,20 +5240,9 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - alien-signals@3.2.1: resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} @@ -5468,10 +5446,6 @@ packages: birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -5514,10 +5488,6 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - c12@3.3.4: resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: @@ -5680,14 +5650,6 @@ packages: constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - convert-hrtime@5.0.0: resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} engines: {node: '>=12'} @@ -5704,24 +5666,12 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -6053,17 +6003,6 @@ packages: devalue@5.8.2: resolution: {integrity: sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA==} - devframe@0.7.14: - resolution: {integrity: sha512-AtGfI3LKjZL11eBcGArZn6QMZTrmGZY7DCwJ9Wot8Vt6/jqaV4wv/Z/VsYneGc4Z/OmRmHucfMB0xlDrE6GYJw==} - peerDependencies: - '@modelcontextprotocol/sdk': ^1.0.0 - cac: ^7.0.0 - peerDependenciesMeta: - '@modelcontextprotocol/sdk': - optional: true - cac: - optional: true - devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -6475,16 +6414,6 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@8.5.1: - resolution: {integrity: sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - exsolve@1.1.0: resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} @@ -6518,9 +6447,6 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} @@ -6550,10 +6476,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -6592,10 +6514,6 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -6771,10 +6689,6 @@ packages: resolution: {integrity: sha512-H7ph5MF3lrc8BE47hhyHi+ZgoRiGi5kqxnA5Ou6rg9dVHtPnmUU8/Man19X/H3Cj1C/DF+jsN/ch9eV7nfpzMQ==} engines: {node: '>=8.0.0'} - hono@4.12.18: - resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==} - engines: {node: '>=16.9.0'} - hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -6813,10 +6727,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - identifier-regex@1.1.0: resolution: {integrity: sha512-SLX4H/vtcYlYnL7XqnuJKHU7Z8517TgsW9nmQiGOgMCjQ8V/deLYu6bEmbGoXe7WMMhc9+EUGyFFneHja8KabA==} engines: {node: '>=18'} @@ -6881,14 +6791,6 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -6955,9 +6857,6 @@ packages: is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -7043,12 +6942,6 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -7346,18 +7239,10 @@ packages: mdn-data@2.28.1: resolution: {integrity: sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7548,10 +7433,6 @@ packages: resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} engines: {node: '>=18'} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - next@16.2.12: resolution: {integrity: sha512-iD59eYQWmbFcEbX7v/acG5DRym9iw1DdaPoD0WTA920naWsE25wShzJW4+UvAs8MK9EC2kBfIH6vtto1H1PHGw==} engines: {node: '>=20.9.0'} @@ -7670,10 +7551,6 @@ packages: object-identity@0.2.3: resolution: {integrity: sha512-2J8Joz2Tf7aaylhqFvIUJHNgpuGR38Hh75Voq9GzTbStBxJUaOtN0K1aOd3cV5qp+ij1pMqRbPrGCGMOyX303w==} - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} @@ -7695,9 +7572,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -7830,9 +7704,6 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - path-to-regexp@8.4.2: - resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -8111,10 +7982,6 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - pug-attrs@3.0.0: resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} @@ -8155,10 +8022,6 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.1: - resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} - engines: {node: '>=0.6'} - quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -8179,10 +8042,6 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - rc9@3.0.1: resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} @@ -8267,10 +8126,6 @@ packages: peerDependencies: vue: '>= 3.4.0' - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - reserved-identifiers@1.2.0: resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} engines: {node: '>=18'} @@ -8360,10 +8215,6 @@ packages: roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -8454,22 +8305,6 @@ packages: resolution: {integrity: sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==} engines: {node: '>=20'} - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -8903,10 +8738,6 @@ packages: resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} engines: {node: '>=20'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - type-level-regexp@0.1.17: resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} @@ -9029,10 +8860,6 @@ packages: '@unocss/webpack': optional: true - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unplugin-utils@0.3.2: resolution: {integrity: sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==} engines: {node: '>=20.19.0'} @@ -9182,10 +9009,6 @@ packages: typescript: optional: true - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - verkit@0.1.2: resolution: {integrity: sha512-WqkT8n3hqizuCu71W3bUzf5fjBmkbXcudsehe/NbxA8PgqoKnSOY5K0Ba2ckg1qaRaSpSz7as/n9K1R9JXjQKg==} engines: {node: '>=18.12.0'} @@ -9528,9 +9351,6 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.21.1: resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} engines: {node: '>=10.0.0'} @@ -9620,11 +9440,6 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -9990,25 +9805,25 @@ snapshots: '@colordx/core@5.4.3': {} - '@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3))': + '@devframes/hub@0.7.14(devframe@packages+devframe)': dependencies: birpc: 4.0.0 destr: 2.0.5 - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3) + devframe: link:packages/devframe nostics: 1.2.0 pathe: 2.0.3 perfect-debounce: 2.1.0 tinyexec: 1.2.4 zigpty: 0.2.1 - '@devframes/json-render@0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3))': + '@devframes/json-render@0.7.14(@devframes/hub@0.7.14(devframe@packages+devframe))(devframe@packages+devframe)': dependencies: '@json-render/core': 0.19.0(zod@4.4.3) - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3) + devframe: link:packages/devframe nostics: 1.2.0 zod: 4.4.3 optionalDependencies: - '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)) + '@devframes/hub': 0.7.14(devframe@packages+devframe) '@discoveryjs/discovery@1.0.0-beta.99': dependencies: @@ -10332,11 +10147,6 @@ snapshots: - '@vue/composition-api' - vue - '@hono/node-server@1.19.14(hono@4.12.18)': - dependencies: - hono: 4.12.18 - optional: true - '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -10598,29 +10408,6 @@ snapshots: dependencies: zod: 4.4.3 - '@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3)': - dependencies: - '@hono/node-server': 1.19.14(hono@4.12.18) - ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.8 - express: 5.2.1(supports-color@10.2.2) - express-rate-limit: 8.5.1(express@5.2.1(supports-color@10.2.2)) - hono: 4.12.18 - jose: 6.2.3 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 4.4.3 - zod-to-json-schema: 3.25.2(zod@4.4.3) - transitivePeerDependencies: - - supports-color - optional: true - '@modelcontextprotocol/server@2.0.0': dependencies: '@modelcontextprotocol/core': 2.0.0 @@ -10888,11 +10675,11 @@ snapshots: - rolldown - unplugin - '@nuxt/nitro-server@4.5.1(e7761c5a620feb94b1a6c4dc96de07af)': + '@nuxt/nitro-server@4.5.1(71bc86bb730f85a69e3066bf13024c10)': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 4.5.1(magic-string@1.0.0)(magicast@0.5.2)(oxc-parser@0.140.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))) - '@unhead/vue': 3.2.3(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) + '@unhead/vue': 3.2.3(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) '@vue/shared': 3.5.40 consola: 3.4.2 defu: 6.1.7 @@ -10907,7 +10694,7 @@ snapshots: mocked-exports: 0.1.1 nitropack: 2.13.4(oxc-parser@0.140.0)(rolldown@1.2.0)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) nostics: 1.2.0 - nuxt: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) + nuxt: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) nypm: 0.6.8 ohash: 2.0.11 pathe: 2.0.3 @@ -10933,7 +10720,6 @@ snapshots: - '@electric-sql/pglite' - '@farmfe/core' - '@libsql/client' - - '@modelcontextprotocol/sdk' - '@netlify/blobs' - '@planetscale/database' - '@rspack/core' @@ -10947,7 +10733,6 @@ snapshots: - bare-buffer - better-sqlite3 - bun-types-no-globals - - cac - db0 - drizzle-orm - encoding @@ -10991,7 +10776,7 @@ snapshots: rc9: 3.0.1 std-env: 4.2.0 - '@nuxt/vite-builder@4.5.1(38c9b88e29bb939367de5d602b22a832)': + '@nuxt/vite-builder@4.5.1(abf4b1bdbb10956a12cdcb700c0fc641)': dependencies: '@nuxt/kit': 4.5.1(magic-string@1.0.0)(magicast@0.5.2)(oxc-parser@0.140.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))) '@vitejs/plugin-vue': 6.0.8(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) @@ -11009,7 +10794,7 @@ snapshots: knitwork: 1.3.0 mlly: 1.8.2 mocked-exports: 0.1.1 - nuxt: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) + nuxt: 4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0) nypm: 0.6.8 pathe: 2.0.3 pkg-types: 2.3.1 @@ -12583,9 +12368,9 @@ snapshots: '@ungap/structured-clone@1.3.1': {} - '@unhead/bundler@3.2.3(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(srvx@0.11.22)(typescript@6.0.3)(unhead@3.2.3(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))': + '@unhead/bundler@3.2.3(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(unhead@3.2.3(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))': dependencies: - '@vitejs/devtools-kit': 0.4.9(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) + '@vitejs/devtools-kit': 0.4.9(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) magic-string: 1.0.0 oxc-parser: 0.140.0 oxc-walker: 1.0.0(esbuild@0.28.0)(oxc-parser@0.140.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) @@ -12599,18 +12384,14 @@ snapshots: vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - - '@modelcontextprotocol/sdk' - '@rspack/core' - bun-types-no-globals - - cac - rollup - - srvx - - typescript - unloader - '@unhead/vue@3.2.3(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))': + '@unhead/vue@3.2.3(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))': dependencies: - '@unhead/bundler': 3.2.3(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(srvx@0.11.22)(typescript@6.0.3)(unhead@3.2.3(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) + '@unhead/bundler': 3.2.3(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(unhead@3.2.3(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) hookable: 6.1.1 unhead: 3.2.3(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) unplugin: 3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) @@ -12619,17 +12400,13 @@ snapshots: vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - - '@modelcontextprotocol/sdk' - '@rspack/core' - '@unhead/cli' - bun-types-no-globals - - cac - esbuild - lightningcss - rolldown - rollup - - srvx - - typescript - unloader '@unocss/cli@66.7.5': @@ -12798,21 +12575,16 @@ snapshots: - rollup - supports-color - '@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))': + '@vitejs/devtools-kit@0.4.9(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))': dependencies: - '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)) - '@devframes/json-render': 0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3)) - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3) + '@devframes/hub': 0.7.14(devframe@packages+devframe) + '@devframes/json-render': 0.7.14(@devframes/hub@0.7.14(devframe@packages+devframe))(devframe@packages+devframe) + devframe: link:packages/devframe local-pkg: 1.2.1 mlly: 1.8.2 nostics: 1.2.0 nypm: 0.6.8 vite: 8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0) - transitivePeerDependencies: - - '@modelcontextprotocol/sdk' - - cac - - srvx - - typescript '@vitejs/plugin-react-oxc@0.4.3(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))': dependencies: @@ -13166,12 +12938,6 @@ snapshots: dependencies: event-target-shim: 5.0.1 - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - optional: true - acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -13186,11 +12952,6 @@ snapshots: agent-base@7.1.4: {} - ajv-formats@3.0.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - optional: true - ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -13198,14 +12959,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - optional: true - alien-signals@3.2.1: {} ansi-regex@5.0.1: {} @@ -13385,21 +13138,6 @@ snapshots: birpc@4.0.0: {} - body-parser@2.2.2(supports-color@10.2.2): - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3(supports-color@10.2.2) - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.1 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - optional: true - boolbase@1.0.0: {} brace-expansion@2.1.0: @@ -13449,9 +13187,6 @@ snapshots: dependencies: run-applescript: 7.1.0 - bytes@3.1.2: - optional: true - c12@3.3.4(magicast@0.5.2): dependencies: chokidar: 5.0.0 @@ -13600,12 +13335,6 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - content-disposition@1.1.0: - optional: true - - content-type@1.0.5: - optional: true - convert-hrtime@5.0.0: {} convert-source-map@2.0.0: {} @@ -13616,24 +13345,12 @@ snapshots: cookie-es@3.1.1: {} - cookie-signature@1.2.2: - optional: true - - cookie@0.7.2: - optional: true - core-js-compat@3.49.0: dependencies: browserslist: 4.28.6 core-util-is@1.0.3: {} - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - optional: true - cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -13973,24 +13690,6 @@ snapshots: devalue@5.8.2: {} - devframe@0.7.14(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(srvx@0.11.22)(typescript@6.0.3): - dependencies: - '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) - birpc: 4.0.0 - crossws: 0.4.10(srvx@0.11.22) - destr: 2.0.5 - h3: 2.0.1-rc.26(crossws@0.4.10(srvx@0.11.22)) - mrmime: 2.0.1 - nostics: 1.2.0 - pathe: 2.0.3 - ufo: 1.6.4 - valibot: 1.4.2(typescript@6.0.3) - optionalDependencies: - '@modelcontextprotocol/sdk': 1.30.0(supports-color@10.2.2)(zod@4.4.3) - transitivePeerDependencies: - - srvx - - typescript - devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -14457,46 +14156,6 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@8.5.1(express@5.2.1(supports-color@10.2.2)): - dependencies: - express: 5.2.1(supports-color@10.2.2) - ip-address: 10.2.0 - optional: true - - express@5.2.1(supports-color@10.2.2): - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2(supports-color@10.2.2) - content-disposition: 1.1.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3(supports-color@10.2.2) - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1(supports-color@10.2.2) - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.1 - range-parser: 1.2.1 - router: 2.2.0(supports-color@10.2.2) - send: 1.2.1(supports-color@10.2.2) - serve-static: 2.2.1(supports-color@10.2.2) - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - optional: true - exsolve@1.1.0: {} extend-shallow@2.0.1: @@ -14527,9 +14186,6 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: - optional: true - fast-wrap-ansi@0.2.0: dependencies: fast-string-width: 3.0.2 @@ -14556,18 +14212,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1(supports-color@10.2.2): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - optional: true - find-up-simple@1.0.1: {} find-up@5.0.0: @@ -14608,9 +14252,6 @@ snapshots: format@0.2.2: {} - forwarded@0.2.0: - optional: true - fraction.js@5.3.4: {} fresh@2.0.0: {} @@ -14748,13 +14389,6 @@ snapshots: transitivePeerDependencies: - srvx - h3@2.0.1-rc.26(crossws@0.4.10(srvx@0.11.22)): - dependencies: - rou3: 0.9.1 - srvx: 0.12.4 - optionalDependencies: - crossws: 0.4.10(srvx@0.11.22) - h3@2.0.1-rc.26(crossws@0.4.10(srvx@0.12.4)): dependencies: rou3: 0.9.1 @@ -14800,9 +14434,6 @@ snapshots: dependencies: ansi-styles: 3.2.1 - hono@4.12.18: - optional: true - hookable@5.5.3: {} hookable@6.1.1: {} @@ -14838,11 +14469,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - optional: true - identifier-regex@1.1.0: dependencies: reserved-identifiers: 1.2.0 @@ -14909,12 +14535,6 @@ snapshots: transitivePeerDependencies: - supports-color - ip-address@10.2.0: - optional: true - - ipaddr.js@1.9.1: - optional: true - iron-webcrypto@1.2.1: {} is-builtin-module@5.0.0: @@ -14966,9 +14586,6 @@ snapshots: is-promise@2.2.2: {} - is-promise@4.0.0: - optional: true - is-reference@1.2.1: dependencies: '@types/estree': 1.0.9 @@ -15039,12 +14656,6 @@ snapshots: json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: - optional: true - - json-schema-typed@8.0.2: - optional: true - json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} @@ -15420,16 +15031,10 @@ snapshots: mdn-data@2.28.1: {} - media-typer@1.1.0: - optional: true - merge-anything@5.1.7: dependencies: is-what: 4.1.16 - merge-descriptors@2.0.0: - optional: true - merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -15732,9 +15337,6 @@ snapshots: natural-orderby@5.0.0: {} - negotiator@1.0.0: - optional: true - next@16.2.12(@babel/core@7.29.0(supports-color@10.2.2))(@playwright/test@1.62.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@next/env': 16.2.12 @@ -15916,17 +15518,17 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt@4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0): + nuxt@4.5.1(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@26.1.2)(@vue/compiler-sfc@3.5.40)(db0@0.3.4)(esbuild@0.28.0)(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.2)(optionator@0.9.4)(oxc-parser@0.140.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.0)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.1)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(yaml@2.9.0): dependencies: '@dxup/nuxt': 0.5.3(esbuild@0.28.0)(magicast@0.5.2)(oxc-parser@0.140.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)) '@nuxt/cli': 3.37.0(@nuxt/schema@4.5.1)(magicast@0.5.2)(supports-color@10.2.2) '@nuxt/devtools': 3.3.1(db0@0.3.4)(ioredis@5.10.1(supports-color@10.2.2))(magic-string@1.0.0)(oxc-parser@0.140.0)(rolldown@1.2.0)(srvx@0.11.22)(supports-color@10.2.2)(unplugin@3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) '@nuxt/kit': 4.5.1(magic-string@1.0.0)(magicast@0.5.2)(oxc-parser@0.140.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))) - '@nuxt/nitro-server': 4.5.1(e7761c5a620feb94b1a6c4dc96de07af) + '@nuxt/nitro-server': 4.5.1(71bc86bb730f85a69e3066bf13024c10) '@nuxt/schema': 4.5.1 '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.5.1(magic-string@1.0.0)(magicast@0.5.2)(oxc-parser@0.140.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0)))) - '@nuxt/vite-builder': 4.5.1(38c9b88e29bb939367de5d602b22a832) - '@unhead/vue': 3.2.3(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3))(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) + '@nuxt/vite-builder': 4.5.1(abf4b1bdbb10956a12cdcb700c0fc641) + '@unhead/vue': 3.2.3(esbuild@0.28.0)(lightningcss@1.32.0)(rolldown@1.2.0)(rollup@4.60.3)(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.1)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3)) '@vue/shared': 3.5.40 chokidar: 5.0.0 compatx: 0.2.0 @@ -15996,7 +15598,6 @@ snapshots: - '@electric-sql/pglite' - '@farmfe/core' - '@libsql/client' - - '@modelcontextprotocol/sdk' - '@netlify/blobs' - '@pinia/colada' - '@planetscale/database' @@ -16068,9 +15669,6 @@ snapshots: object-identity@0.2.3: {} - object-inspect@1.13.4: - optional: true - obug@2.1.4: {} ofetch@1.5.1: @@ -16089,11 +15687,6 @@ snapshots: dependencies: ee-first: 1.1.1 - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optional: true - onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -16336,9 +15929,6 @@ snapshots: lru-cache: 11.3.6 minipass: 7.1.3 - path-to-regexp@8.4.2: - optional: true - pathe@1.1.2: {} pathe@2.0.3: {} @@ -16593,12 +16183,6 @@ snapshots: property-information@7.1.0: {} - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - optional: true - pug-attrs@3.0.0: dependencies: constantinople: 4.0.1 @@ -16668,11 +16252,6 @@ snapshots: punycode@2.3.1: {} - qs@6.15.1: - dependencies: - side-channel: 1.1.0 - optional: true - quansync@0.2.11: {} quansync@1.0.0: {} @@ -16685,14 +16264,6 @@ snapshots: range-parser@1.2.1: {} - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - optional: true - rc9@3.0.1: dependencies: defu: 6.1.7 @@ -16827,9 +16398,6 @@ snapshots: transitivePeerDependencies: - '@vue/composition-api' - require-from-string@2.0.2: - optional: true - reserved-identifiers@1.2.0: {} resolve-from@5.0.0: {} @@ -16977,17 +16545,6 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 - router@2.2.0(supports-color@10.2.2): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.4.2 - transitivePeerDependencies: - - supports-color - optional: true - run-applescript@7.1.0: {} run-parallel@1.2.0: @@ -17111,38 +16668,6 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - optional: true - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - optional: true - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - optional: true - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - optional: true - siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -17626,13 +17151,6 @@ snapshots: dependencies: tagged-tag: 1.0.0 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - optional: true - type-level-regexp@0.1.17: {} typescript@5.9.3: {} @@ -17790,9 +17308,6 @@ snapshots: transitivePeerDependencies: - vite - unpipe@1.0.0: - optional: true - unplugin-utils@0.3.2: dependencies: pathe: 2.0.3 @@ -17884,9 +17399,6 @@ snapshots: optionalDependencies: typescript: 6.0.3 - vary@1.1.2: - optional: true - verkit@0.1.2: {} verkit@0.2.0: {} @@ -18305,9 +17817,6 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 - wrappy@1.0.2: - optional: true - ws@8.21.1: {} wsl-utils@0.1.0: @@ -18411,11 +17920,6 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod-to-json-schema@3.25.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - optional: true - zod@4.4.3: {} zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b6b4fb75..22fa7cb4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -37,8 +37,23 @@ refs: vueuse: &vueuse ^14.3.0 overrides: + '@devframe/hub': 'workspace:*' + '@devframe/json-render': 'workspace:*' + '@devframe/json-render-ui': 'workspace:*' + '@devframe/next': 'workspace:*' + '@devframe/nuxt': 'workspace:*' + '@devframe/plugin-a11y': 'workspace:*' + '@devframe/plugin-assets': 'workspace:*' + '@devframe/plugin-code-server': 'workspace:*' + '@devframe/plugin-data-inspector': 'workspace:*' + '@devframe/plugin-git': 'workspace:*' + '@devframe/plugin-inspect': 'workspace:*' + '@devframe/plugin-messages': 'workspace:*' + '@devframe/plugin-og': 'workspace:*' + '@devframe/plugin-terminals': 'workspace:*' chokidar: ^5.0.0 crossws: ^0.4.10 + devframe: 'workspace:*' semver: ^7.8.5 shell-quote: ^1.10.0 @@ -59,6 +74,7 @@ catalogs: '@json-render/core': ^0.19.0 '@modelcontextprotocol/client': ^2.0.0 '@modelcontextprotocol/server': ^2.0.0 + '@standard-schema/spec': ^1.1.0 '@valibot/to-json-schema': ^1.7.1 birpc: ^4.0.0 cac: ^7.0.0 diff --git a/tests/__snapshots__/tsnapi/@devframes/plugin-assets/rpc.snapshot.d.ts b/tests/__snapshots__/tsnapi/@devframes/plugin-assets/rpc.snapshot.d.ts index 245abdd6..0c20b598 100644 --- a/tests/__snapshots__/tsnapi/@devframes/plugin-assets/rpc.snapshot.d.ts +++ b/tests/__snapshots__/tsnapi/@devframes/plugin-assets/rpc.snapshot.d.ts @@ -17,8 +17,8 @@ export declare const alwaysFunctions: readonly [{ name: "devframes:plugin:assets:open-in-editor"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").StringSchema]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -31,8 +31,8 @@ export declare const alwaysFunctions: readonly [{ name: "devframes:plugin:assets:reveal-in-folder"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").StringSchema]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -42,22 +42,31 @@ export declare const alwaysFunctions: readonly [{ __cache?: WeakMap>> | undefined; __promise?: import("devframe/rpc").Thenable> | undefined; }]; -export declare const assetInfoSchema: v.ObjectSchema<{ - readonly path: v.StringSchema; - readonly type: v.PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: v.StringSchema; - readonly size: v.NumberSchema; - readonly mtime: v.NumberSchema; -}, undefined>; +export declare const assetInfoSchema: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; +}, { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; +}>; export declare const capabilities: { name: "devframes:plugin:assets:capabilities"; type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: v.ObjectSchema<{ - readonly write: v.BooleanSchema; - readonly uploadExtensions: v.UnionSchema<[v.ArraySchema, undefined>, v.LiteralSchema<"*", undefined>], undefined>; - }, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + write: boolean; + uploadExtensions: string[] | "*"; + }, { + write: boolean; + uploadExtensions: string[] | "*"; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable, undefined>; - }, undefined>]; - returns: v.ObjectSchema<{ - readonly deleted: v.ArraySchema, undefined>; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + paths: string[]; + }, { + paths: string[]; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + deleted: string[]; + }, { + deleted: string[]; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable; - readonly type: v.PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: v.StringSchema; - readonly size: v.NumberSchema; - readonly mtime: v.NumberSchema; - }, undefined>, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[], { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[]>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: v.VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: v.VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -219,13 +240,19 @@ export declare const readFunctions: readonly [{ type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: import("valibot").ArraySchema; - readonly type: import("valibot").PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: import("valibot").StringSchema; - readonly size: import("valibot").NumberSchema; - readonly mtime: import("valibot").NumberSchema; - }, undefined>, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[], { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[]>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: import("valibot").NullableSchema, undefined>; - readonly height: import("valibot").OptionalSchema, undefined>; - readonly orientation: import("valibot").OptionalSchema, undefined>; - }, undefined>, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null, { + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, import("valibot").OptionalSchema, undefined>]; - returns: import("valibot").NullableSchema, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema, import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -321,10 +352,13 @@ export declare const readFunctions: readonly [{ type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: import("valibot").ObjectSchema<{ - readonly write: import("valibot").BooleanSchema; - readonly uploadExtensions: import("valibot").UnionSchema<[import("valibot").ArraySchema, undefined>, import("valibot").LiteralSchema<"*", undefined>], undefined>; - }, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + write: boolean; + uploadExtensions: string[] | "*"; + }, { + write: boolean; + uploadExtensions: string[] | "*"; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: v.NullableSchema, undefined>; - readonly height: v.OptionalSchema, undefined>; - readonly orientation: v.OptionalSchema, undefined>; - }, undefined>, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null, { + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable, v.OptionalSchema, undefined>]; - returns: v.NullableSchema, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema, import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -407,17 +445,26 @@ export declare const rename: { name: "devframes:plugin:assets:rename"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.ObjectSchema<{ - readonly path: v.StringSchema; - readonly newName: v.StringSchema; - }, undefined>]; - returns: v.ObjectSchema<{ - readonly path: v.StringSchema; - readonly type: v.PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: v.StringSchema; - readonly size: v.NumberSchema; - readonly mtime: v.NumberSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + newName: string; + }, { + path: string; + newName: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }, { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: v.VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -492,13 +539,19 @@ export declare const serverFunctions: readonly [{ type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: import("valibot").ArraySchema; - readonly type: import("valibot").PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: import("valibot").StringSchema; - readonly size: import("valibot").NumberSchema; - readonly mtime: import("valibot").NumberSchema; - }, undefined>, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[], { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }[]>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: import("valibot").NullableSchema, undefined>; - readonly height: import("valibot").OptionalSchema, undefined>; - readonly orientation: import("valibot").OptionalSchema, undefined>; - }, undefined>, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null, { + width?: number | undefined; + height?: number | undefined; + orientation?: number | undefined; + } | null>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, import("valibot").OptionalSchema, undefined>]; - returns: import("valibot").NullableSchema, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema, import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -594,10 +651,13 @@ export declare const serverFunctions: readonly [{ type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: import("valibot").ObjectSchema<{ - readonly write: import("valibot").BooleanSchema; - readonly uploadExtensions: import("valibot").UnionSchema<[import("valibot").ArraySchema, undefined>, import("valibot").LiteralSchema<"*", undefined>], undefined>; - }, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + write: boolean; + uploadExtensions: string[] | "*"; + }, { + write: boolean; + uploadExtensions: string[] | "*"; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -639,8 +699,8 @@ export declare const serverFunctions: readonly [{ name: "devframes:plugin:assets:reveal-in-folder"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").StringSchema]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; @@ -653,12 +713,16 @@ export declare const serverFunctions: readonly [{ name: "devframes:plugin:assets:upload"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").ObjectSchema<{ - readonly path: import("valibot").StringSchema; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly uploadId: import("valibot").StringSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + uploadId: string; + }, { + uploadId: string; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - readonly newName: import("valibot").StringSchema; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly path: import("valibot").StringSchema; - readonly type: import("valibot").PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: import("valibot").StringSchema; - readonly size: import("valibot").NumberSchema; - readonly mtime: import("valibot").NumberSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + newName: string; + }, { + path: string; + newName: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }, { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, undefined>; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly deleted: import("valibot").ArraySchema, undefined>; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + paths: string[]; + }, { + paths: string[]; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + deleted: string[]; + }, { + deleted: string[]; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: v.ObjectSchema<{ - readonly uploadId: v.StringSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + uploadId: string; + }, { + uploadId: string; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly uploadId: import("valibot").StringSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + uploadId: string; + }, { + uploadId: string; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - readonly newName: import("valibot").StringSchema; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly path: import("valibot").StringSchema; - readonly type: import("valibot").PicklistSchema<["image", "font", "video", "audio", "text", "other"], undefined>; - readonly publicPath: import("valibot").StringSchema; - readonly size: import("valibot").NumberSchema; - readonly mtime: import("valibot").NumberSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + newName: string; + }, { + path: string; + newName: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }, { + path: string; + type: "image" | "font" | "video" | "audio" | "text" | "other"; + publicPath: string; + size: number; + mtime: number; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, undefined>; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly deleted: import("valibot").ArraySchema, undefined>; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + paths: string[]; + }, { + paths: string[]; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + deleted: string[]; + }, { + deleted: string[]; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + path: string; + }, { + path: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, undefined>; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly requestedUrl: import("valibot").StringSchema; - readonly url: import("valibot").StringSchema; - readonly status: import("valibot").NumberSchema; - readonly fetchedAt: import("valibot").NumberSchema; - readonly tags: import("valibot").ArraySchema; - readonly name: import("valibot").StringSchema; - readonly value: import("valibot").StringSchema; - }, undefined>, undefined>; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + url?: string | undefined; + }, { + url?: string | undefined; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + requestedUrl: string; + url: string; + status: number; + fetchedAt: number; + tags: { + tag: "html" | "link" | "meta" | "title"; + name: string; + value: string; + }[]; + }, { + requestedUrl: string; + url: string; + status: number; + fetchedAt: number; + tags: { + tag: "html" | "link" | "meta" | "title"; + name: string; + value: string; + }[]; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - readonly title: import("valibot").StringSchema; - readonly processName: import("valibot").OptionalSchema, undefined>; - readonly customTitle: import("valibot").OptionalSchema, undefined>; - readonly mode: import("valibot").PicklistSchema<["interactive", "readonly"], undefined>; - readonly status: import("valibot").PicklistSchema<["running", "exited", "error"], undefined>; - readonly backend: import("valibot").PicklistSchema<["pty", "pipe"], undefined>; - readonly command: import("valibot").StringSchema; - readonly args: import("valibot").ArraySchema, undefined>; - readonly cwd: import("valibot").StringSchema; - readonly cols: import("valibot").NumberSchema; - readonly rows: import("valibot").NumberSchema; - readonly pid: import("valibot").OptionalSchema, undefined>; - readonly exitCode: import("valibot").OptionalSchema, undefined>; - readonly icon: import("valibot").OptionalSchema, undefined>; - readonly channel: import("valibot").OptionalSchema, undefined>; - readonly presetId: import("valibot").OptionalSchema, undefined>; - readonly createdAt: import("valibot").NumberSchema; - }, undefined>, undefined>; - jsonSerializable?: boolean; - agent?: import("devframe").RpcFunctionAgentOptions; - setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; + jsonSerializable?: boolean; + agent?: import("devframe").RpcFunctionAgentOptions; + setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; handler?: (() => { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -62,18 +79,18 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }[]) | undefined; dump?: import("devframe/rpc").RpcDump<[], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -82,19 +99,19 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }[], import("devframe").DevframeNodeContext> | undefined; snapshot?: boolean; __cache?: WeakMap>> | undefined; __promise?: import("devframe/rpc").Thenable> | undefined; }, { name: "devframes:plugin:terminals:presets"; type?: "query" | undefined; cacheable?: boolean; args: readonly []; - returns: import("valibot").ArraySchema; - readonly title: import("valibot").StringSchema; - readonly command: import("valibot").StringSchema; - readonly args: import("valibot").ArraySchema, undefined>; - readonly mode: import("valibot").PicklistSchema<["interactive", "readonly"], undefined>; - readonly icon: import("valibot").OptionalSchema, undefined>; - }, undefined>, undefined>; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + title: string; + command: string; + args: string[]; + mode: "interactive" | "readonly"; + icon?: string | undefined; + }[], { + id: string; + title: string; + command: string; + args: string[]; + mode: "interactive" | "readonly"; + icon?: string | undefined; + }[]>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable, undefined>; - readonly command: import("valibot").OptionalSchema, undefined>; - readonly args: import("valibot").OptionalSchema, undefined>, undefined>; - readonly cwd: import("valibot").OptionalSchema, undefined>; - readonly mode: import("valibot").OptionalSchema, undefined>; - readonly title: import("valibot").OptionalSchema, undefined>; - readonly cols: import("valibot").OptionalSchema, undefined>; - readonly rows: import("valibot").OptionalSchema, undefined>; - readonly env: import("valibot").OptionalSchema, import("valibot").StringSchema, undefined>, undefined>; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly id: import("valibot").StringSchema; - readonly title: import("valibot").StringSchema; - readonly processName: import("valibot").OptionalSchema, undefined>; - readonly customTitle: import("valibot").OptionalSchema, undefined>; - readonly mode: import("valibot").PicklistSchema<["interactive", "readonly"], undefined>; - readonly status: import("valibot").PicklistSchema<["running", "exited", "error"], undefined>; - readonly backend: import("valibot").PicklistSchema<["pty", "pipe"], undefined>; - readonly command: import("valibot").StringSchema; - readonly args: import("valibot").ArraySchema, undefined>; - readonly cwd: import("valibot").StringSchema; - readonly cols: import("valibot").NumberSchema; - readonly rows: import("valibot").NumberSchema; - readonly pid: import("valibot").OptionalSchema, undefined>; - readonly exitCode: import("valibot").OptionalSchema, undefined>; - readonly icon: import("valibot").OptionalSchema, undefined>; - readonly channel: import("valibot").OptionalSchema, undefined>; - readonly presetId: import("valibot").OptionalSchema, undefined>; - readonly createdAt: import("valibot").NumberSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + presetId?: string | undefined; + command?: string | undefined; + args?: string[] | undefined; + cwd?: string | undefined; + mode?: "interactive" | "readonly" | undefined; + title?: string | undefined; + cols?: number | undefined; + rows?: number | undefined; + env?: Record | undefined; + }, { + presetId?: string | undefined; + command?: string | undefined; + args?: string[] | undefined; + cwd?: string | undefined; + mode?: "interactive" | "readonly" | undefined; + title?: string | undefined; + cols?: number | undefined; + rows?: number | undefined; + env?: Record | undefined; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + title: string; + mode: "interactive" | "readonly"; + status: "running" | "exited" | "error"; + backend: "pty" | "pipe"; + command: string; + args: string[]; + cwd: string; + cols: number; + rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; + pid?: number | undefined; + exitCode?: number | undefined; + icon?: string | undefined; + channel?: string | undefined; + presetId?: string | undefined; + }, { + id: string; + title: string; + mode: "interactive" | "readonly"; + status: "running" | "exited" | "error"; + backend: "pty" | "pipe"; + command: string; + args: string[]; + cwd: string; + cols: number; + rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; + pid?: number | undefined; + exitCode?: number | undefined; + icon?: string | undefined; + channel?: string | undefined; + presetId?: string | undefined; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable | undefined; }], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -248,12 +299,14 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }>>) | undefined; handler?: ((args_0: { presetId?: string | undefined; @@ -264,14 +317,10 @@ export declare const serverFunctions: readonly [{ title?: string | undefined; cols?: number | undefined; rows?: number | undefined; - env?: { - [x: string]: string; - } | undefined; + env?: Record | undefined; }) => { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -280,12 +329,14 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }) | undefined; dump?: import("devframe/rpc").RpcDump<[{ presetId?: string | undefined; @@ -296,14 +347,10 @@ export declare const serverFunctions: readonly [{ title?: string | undefined; cols?: number | undefined; rows?: number | undefined; - env?: { - [x: string]: string; - } | undefined; + env?: Record | undefined; }], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -312,12 +359,14 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }, import("devframe").DevframeNodeContext> | undefined; snapshot?: boolean; __cache?: WeakMap | undefined; }], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -345,12 +390,14 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }>>> | undefined; __promise?: import("devframe/rpc").Thenable | undefined; }], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -377,22 +420,27 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }>> | undefined; }, { name: "devframes:plugin:terminals:write"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").ObjectSchema<{ - readonly id: import("valibot").StringSchema; - readonly data: import("valibot").StringSchema; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + data: string; + }, { + id: string; + data: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - readonly cols: import("valibot").SchemaWithPipe, import("valibot").IntegerAction, import("valibot").MinValueAction]>; - readonly rows: import("valibot").SchemaWithPipe, import("valibot").IntegerAction, import("valibot").MinValueAction]>; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + cols: number; + rows: number; + }, { + id: string; + cols: number; + rows: number; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + }, { + id: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").ObjectSchema<{ - readonly id: import("valibot").StringSchema; - readonly title: import("valibot").StringSchema; - readonly processName: import("valibot").OptionalSchema, undefined>; - readonly customTitle: import("valibot").OptionalSchema, undefined>; - readonly mode: import("valibot").PicklistSchema<["interactive", "readonly"], undefined>; - readonly status: import("valibot").PicklistSchema<["running", "exited", "error"], undefined>; - readonly backend: import("valibot").PicklistSchema<["pty", "pipe"], undefined>; - readonly command: import("valibot").StringSchema; - readonly args: import("valibot").ArraySchema, undefined>; - readonly cwd: import("valibot").StringSchema; - readonly cols: import("valibot").NumberSchema; - readonly rows: import("valibot").NumberSchema; - readonly pid: import("valibot").OptionalSchema, undefined>; - readonly exitCode: import("valibot").OptionalSchema, undefined>; - readonly icon: import("valibot").OptionalSchema, undefined>; - readonly channel: import("valibot").OptionalSchema, undefined>; - readonly presetId: import("valibot").OptionalSchema, undefined>; - readonly createdAt: import("valibot").NumberSchema; - }, undefined>; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + }, { + id: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + title: string; + mode: "interactive" | "readonly"; + status: "running" | "exited" | "error"; + backend: "pty" | "pipe"; + command: string; + args: string[]; + cwd: string; + cols: number; + rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; + pid?: number | undefined; + exitCode?: number | undefined; + icon?: string | undefined; + channel?: string | undefined; + presetId?: string | undefined; + }, { + id: string; + title: string; + mode: "interactive" | "readonly"; + status: "running" | "exited" | "error"; + backend: "pty" | "pipe"; + command: string; + args: string[]; + cwd: string; + cols: number; + rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; + pid?: number | undefined; + exitCode?: number | undefined; + icon?: string | undefined; + channel?: string | undefined; + presetId?: string | undefined; + }>; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; handler?: ((args_0: { id: string; }) => { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -546,20 +619,20 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }) | undefined; dump?: import("devframe/rpc").RpcDump<[{ id: string; }], { id: string; title: string; - processName?: string | undefined; - customTitle?: string | undefined; mode: "interactive" | "readonly"; status: "running" | "exited" | "error"; backend: "pty" | "pipe"; @@ -568,12 +641,14 @@ export declare const serverFunctions: readonly [{ cwd: string; cols: number; rows: number; + createdAt: number; + processName?: string | undefined; + customTitle?: string | undefined; pid?: number | undefined; exitCode?: number | undefined; icon?: string | undefined; channel?: string | undefined; presetId?: string | undefined; - createdAt: number; }, import("devframe").DevframeNodeContext> | undefined; snapshot?: boolean; __cache?: WeakMap>> | undefined; __promise?: import("devframe/rpc").Thenable> | undefined; }, { name: "devframes:plugin:terminals:rename"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [import("valibot").ObjectSchema<{ - readonly id: import("valibot").StringSchema; - readonly title: import("valibot").StringSchema; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + title: string; + }, { + id: string; + title: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; - }, undefined>]; - returns: import("valibot").VoidSchema; + args: readonly [import("devframe/utils/simple-schema").SimpleSchema<{ + id: string; + }, { + id: string; + }>]; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable; + returns: import("devframe/utils/simple-schema").SimpleSchema; jsonSerializable?: boolean; agent?: import("devframe").RpcFunctionAgentOptions; setup?: ((context: import("devframe").DevframeNodeContext) => import("devframe/rpc").Thenable>) | undefined; diff --git a/tests/__snapshots__/tsnapi/devframe/recipes/common-rpc-functions.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/recipes/common-rpc-functions.snapshot.d.ts index 7114a897..6c50a713 100644 --- a/tests/__snapshots__/tsnapi/devframe/recipes/common-rpc-functions.snapshot.d.ts +++ b/tests/__snapshots__/tsnapi/devframe/recipes/common-rpc-functions.snapshot.d.ts @@ -10,8 +10,8 @@ export declare const commonRpcFunctions: readonly [{ name: "devframe:open-in-editor"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema, v.OptionalSchema, undefined>]; - returns: v.VoidSchema; + args: readonly [SimpleSchema, SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; @@ -24,8 +24,8 @@ export declare const commonRpcFunctions: readonly [{ name: "devframe:open-in-finder"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema]; - returns: v.VoidSchema; + args: readonly [SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; @@ -40,8 +40,8 @@ export declare const openInEditor: { name: "devframe:open-in-editor"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema, v.OptionalSchema, undefined>]; - returns: v.VoidSchema; + args: readonly [SimpleSchema, SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; @@ -55,8 +55,8 @@ export declare const openInFinder: { name: "devframe:open-in-finder"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema]; - returns: v.VoidSchema; + args: readonly [SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; diff --git a/tests/__snapshots__/tsnapi/devframe/recipes/open-helpers.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/recipes/open-helpers.snapshot.d.ts index 436d011f..b1198606 100644 --- a/tests/__snapshots__/tsnapi/devframe/recipes/open-helpers.snapshot.d.ts +++ b/tests/__snapshots__/tsnapi/devframe/recipes/open-helpers.snapshot.d.ts @@ -8,8 +8,8 @@ export declare const openInEditor: { name: "devframe:open-in-editor"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema, v.OptionalSchema, undefined>]; - returns: v.VoidSchema; + args: readonly [SimpleSchema, SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; @@ -23,8 +23,8 @@ export declare const openInFinder: { name: "devframe:open-in-finder"; type?: "action" | undefined; cacheable?: boolean; - args: readonly [v.StringSchema]; - returns: v.VoidSchema; + args: readonly [SimpleSchema]; + returns: SimpleSchema; jsonSerializable?: boolean; agent?: RpcFunctionAgentOptions; setup?: ((context: undefined) => Thenable>) | undefined; diff --git a/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.d.ts index f4c2a8b6..0bd4e7ac 100644 --- a/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.d.ts +++ b/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.d.ts @@ -52,4 +52,6 @@ export { STRUCTURED_CLONE_PREFIX } export { Thenable } export { validateDefinition } export { validateDefinitions } +export { validateRpcArgs } +export { validateRpcReturn } // #endregion \ No newline at end of file diff --git a/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.js b/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.js index f7ed8933..6b1b818e 100644 --- a/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.js +++ b/tests/__snapshots__/tsnapi/devframe/rpc.snapshot.js @@ -55,4 +55,6 @@ export { strictJsonStringify } export { STRUCTURED_CLONE_PREFIX } export { validateDefinition } export { validateDefinitions } +export { validateRpcArgs } +export { validateRpcReturn } // #endregion \ No newline at end of file diff --git a/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.d.ts new file mode 100644 index 00000000..849c1046 --- /dev/null +++ b/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.d.ts @@ -0,0 +1,21 @@ +/** + * Generated by tsnapi — public API snapshot of `devframe/utils/simple-schema` + */ +// #region Other +export { array } +export { boolean } +export { describe } +export { literal } +export { nullable } +export { nullType } +export { number } +export { object } +export { optional } +export { picklist } +export { record } +export { s } +export { SimpleSchema } +export { string } +export { union } +export { voidType } +// #endregion \ No newline at end of file diff --git a/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.js b/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.js new file mode 100644 index 00000000..cac1376f --- /dev/null +++ b/tests/__snapshots__/tsnapi/devframe/utils/simple-schema.snapshot.js @@ -0,0 +1,23 @@ +/** + * Generated by tsnapi — public API snapshot of `devframe/utils/simple-schema` + */ +// #region Functions +export function array(_) {} +export function boolean() {} +export function describe(_, _) {} +export function literal(_) {} +export function nullable(_) {} +export function nullType() {} +export function number() {} +export function object(_) {} +export function optional(_) {} +export function picklist(_) {} +export function record(_, _) {} +export function string() {} +export function union(_) {} +export function voidType() {} +// #endregion + +// #region Variables +export var s /* const */ +// #endregion \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index 87e66489..4e2e01f3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -64,6 +64,9 @@ "devframe/utils/promise": [ "./packages/devframe/src/utils/promise.ts" ], + "devframe/utils/simple-schema": [ + "./packages/devframe/src/utils/simple-schema.ts" + ], "devframe/utils/scope": [ "./packages/devframe/src/utils/scope.ts" ],