@silkweave/core 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,6 +69,7 @@ Returns a builder with `.adapter()`, `.action()`, `.actions()`, `.set()`, and `.
69
69
  | `path` | `string` | Optional REST route template, may contain `:param` placeholders (e.g. `'spaces/:spaceId/users'`). Each placeholder must be a key of `input`. See [REST routing](#rest-routing). |
70
70
  | `queryParams` | `(keyof I)[]` | Optional input fields read from the URL query string instead of the body (e.g. `['offset', 'limit']`). See [REST routing](#rest-routing). |
71
71
  | `args` | `(keyof I)[]` | Fields to expose as CLI positional arguments |
72
+ | `disposition` | `'json' \| 'smart'` | Optional default MCP result format - `'json'` ⇒ `jsonToolResult`, `'smart'` (default) ⇒ `smartToolResult`. A client's `_meta.disposition` overrides it. MCP adapters only. |
72
73
  | `isEnabled` | `(context) => boolean` | Gate action availability per adapter |
73
74
  | `run` | `(input, context) => Promise<O>` *or* `async function*(input, context): AsyncGenerator<Chunk>` | The action implementation. Use a regular `async` function for buffered request/response; use an `async function*` and declare `chunk` to stream. |
74
75
  | `toolResult` | `(response, context) => CallToolResult \| undefined` | Custom MCP result formatting (optional). For streaming actions, `response` is the buffered array of chunks (used when the client did not request streaming). |
package/build/index.d.mts CHANGED
@@ -53,6 +53,15 @@ interface Action<I extends object = any, O extends object = any, N extends strin
53
53
  */
54
54
  queryParams?: (keyof I)[];
55
55
  args?: (keyof I)[];
56
+ /**
57
+ * Default MCP result disposition for this action - `'json'` formats the
58
+ * response with `jsonToolResult` (compact JSON text), `'smart'` (the default
59
+ * when unset) uses `smartToolResult` (inlines small payloads, offloads large
60
+ * ones to an embedded resource). This is only a default: a client that sends
61
+ * `_meta.disposition` on the tool call always wins. Ignored by non-MCP
62
+ * adapters.
63
+ */
64
+ disposition?: 'json' | 'smart';
56
65
  isEnabled?: (context: SilkweaveContext) => boolean;
57
66
  run: ActionRun<I, O> | ActionStreamRun<I, C>;
58
67
  toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined;
@@ -71,6 +80,7 @@ interface NonStreamingActionInput<I extends object, O extends object, N extends
71
80
  path?: string;
72
81
  queryParams?: (keyof I)[];
73
82
  args?: (keyof I)[];
83
+ disposition?: 'json' | 'smart';
74
84
  isEnabled?: (context: SilkweaveContext) => boolean;
75
85
  run: ActionRun<I, O>;
76
86
  toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined;
@@ -87,6 +97,7 @@ interface StreamingActionInput<I extends object, C, N extends string, K extends
87
97
  path?: string;
88
98
  queryParams?: (keyof I)[];
89
99
  args?: (keyof I)[];
100
+ disposition?: 'json' | 'smart';
90
101
  isEnabled?: (context: SilkweaveContext) => boolean;
91
102
  run: ActionStreamRun<I, C>;
92
103
  toolResult?: (response: C[], context: SilkweaveContext) => CallToolResult | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/util/context.ts","../src/util/action.ts","../src/util/adapter.ts","../src/lib/silkweave.ts","../src/util/error.ts","../src/util/http.ts","../src/util/streaming.ts","../src/util/zod.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/util/context.ts","../src/util/action.ts","../src/util/adapter.ts","../src/lib/silkweave.ts","../src/util/error.ts","../src/util/http.ts","../src/util/streaming.ts","../src/util/zod.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/util/context.ts","../src/lib/silkweave.ts","../src/util/action.ts","../src/util/error.ts","../src/util/zod.ts","../src/util/http.ts","../src/util/streaming.ts"],"sourcesContent":["export interface SilkweaveContext {\n keys: () => string[]\n has: (key: string) => boolean\n get: <T>(key: string) => T\n getOptional: <T>(key: string) => T | undefined\n set: <T>(key: string, value: T) => void\n fork: (store?: Record<string, unknown>) => SilkweaveContext\n}\n\nexport function createContext(store: Record<string, unknown> = {}): SilkweaveContext {\n return {\n keys: () => {\n return Object.keys(store)\n },\n has: (key: string): boolean => {\n return store[key] != null\n },\n get: <T>(key: string): T => {\n const value = store[key]\n if (value == null) { throw new Error(`Invalid context key: ${key}`) }\n return value as T\n },\n getOptional: <T>(key: string): T | undefined => {\n return store[key] as T | undefined\n },\n set: <T>(key: string, value: T) => {\n store[key] = value\n },\n fork: (value?: Record<string, unknown>) => {\n return createContext({ ...store, ...value })\n }\n }\n}\n","import { Action } from '../util/action.js'\nimport { Adapter, AdapterGenerator, SilkweaveOptions } from '../util/adapter.js'\nimport { createContext } from '../util/context.js'\n\nexport type { SilkweaveOptions } from '../util/adapter.js'\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface Silkweave<Actions extends Record<string, Action> = {}> {\n set: <T>(key: string, value: T) => Silkweave<Actions>\n adapter: (generator: AdapterGenerator) => Silkweave<Actions>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n action: <A extends Action<any, any, string, any>>(\n action: A\n ) => Silkweave<Actions & Record<A['name'], A>>\n actions: <Arr extends readonly Action[]>(\n actions: Arr\n ) => Silkweave<Actions & { [K in Arr[number] as K['name']]: K }>\n start: () => Promise<Silkweave<Actions>>\n}\n\nexport function silkweave(options: SilkweaveOptions): Silkweave {\n const adapters: Adapter[] = []\n const actions: Action[] = []\n const context = createContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const builder: Silkweave<any> = {\n set: (key, value) => {\n context.set(key, value)\n return builder\n },\n adapter: (generator) => {\n adapters.push(generator(options, context))\n return builder\n },\n action: (value) => {\n actions.push(value)\n return builder\n },\n actions: (values) => {\n actions.push(...values)\n return builder\n },\n start: async () => {\n await Promise.all(adapters.map((adapter) => {\n const filtered = adapter.allActions\n ? actions\n : actions.filter((action) => {\n if (!action.isEnabled) { return true }\n return action.isEnabled(adapter.context)\n })\n return adapter.start(filtered)\n }))\n return builder\n }\n }\n return builder\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport z from 'zod/v4'\nimport { SilkweaveContext } from './context.js'\n\nexport type ActionKind = 'query' | 'mutation'\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'\n\nexport type ActionRun<I, O> = (input: I, context: SilkweaveContext) => Promise<O>\nexport type ActionStreamRun<I, C> = (input: I, context: SilkweaveContext) => AsyncGenerator<C, void, void>\n\nexport interface Action<\n I extends object = any,\n O extends object = any,\n N extends string = string,\n K extends ActionKind = ActionKind,\n C = any\n> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n /**\n * Schema for individual chunks yielded by a streaming `run`. Required when\n * `run` is an async generator; adapters detect streaming actions by checking\n * `isStreamingAction(action)` at runtime, but type-aware tooling (inferRouter,\n * typegen) uses the presence of this field.\n */\n chunk?: z.ZodType<C>\n kind?: K\n /**\n * HTTP verb for REST-style adapters (fastify, nestjs `rest`). Defaults to\n * `POST`, or `GET` when `kind` is `'query'`. An explicit `method` always wins.\n */\n method?: HttpMethod\n /**\n * Route path for REST-style adapters. May contain `:param` placeholders\n * (e.g. `'spaces/:spaceId/users'`); each placeholder must be a key of the\n * input schema and is resolved from the URL path at runtime. When unset, the\n * adapter derives the path from `name`.\n */\n path?: string\n /**\n * Input fields sourced from the URL query string instead of the request body\n * (e.g. `['offset', 'limit']`). Each must be a key of the input schema; their\n * required/optional status is validated by the input schema as usual.\n */\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O> | ActionStreamRun<I, C>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface NonStreamingActionInput<I extends object, O extends object, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface StreamingActionInput<I extends object, C, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n chunk: z.ZodType<C>\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionStreamRun<I, C>\n toolResult?: (response: C[], context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport function createAction<\n I extends object,\n C,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: StreamingActionInput<I, C, N, K>): StreamingActionInput<I, C, N, K>\nexport function createAction<\n I extends object,\n O extends object,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: NonStreamingActionInput<I, O, N, K>): NonStreamingActionInput<I, O, N, K>\nexport function createAction(action: Action): Action {\n return action\n}\n\n/**\n * Returns `true` when `action.run` is an async generator function (declared\n * with `async function*`). Adapters use this to switch between buffered\n * request/response and streaming chunk delivery.\n */\nexport function isStreamingAction(action: Action): boolean {\n return action.run?.constructor?.name === 'AsyncGeneratorFunction'\n}\n","export class SilkweaveError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode = 500\n ) {\n super(message)\n this.name = 'SilkweaveError'\n }\n}\n\nexport function notFound(message = 'Not found') {\n return new SilkweaveError(message, 'not_found', 404)\n}\n\nexport function badRequest(message = 'Bad request') {\n return new SilkweaveError(message, 'bad_request', 400)\n}\n\nexport function forbidden(message = 'Forbidden') {\n return new SilkweaveError(message, 'forbidden', 403)\n}\n\nexport function internal(message = 'Internal error') {\n return new SilkweaveError(message, 'internal', 500)\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from 'zod/v4'\n\nexport interface UnwrapResult {\n defaultValue?: any\n isOptional?: boolean\n isNullable?: boolean\n isReadOnly?: boolean\n}\n\nexport function unwrap(\n type: z.ZodTypeAny,\n result: UnwrapResult = {}\n): [z.ZodTypeAny, UnwrapResult] {\n if (type instanceof z.ZodOptional) {\n result.isOptional = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodNullable) {\n result.isNullable = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodReadonly) {\n result.isReadOnly = true\n return unwrap(type.def.innerType as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodDefault) {\n result.defaultValue = typeof type.def.defaultValue === 'function'\n ? type.def.defaultValue()\n : type.def.defaultValue\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else {\n return [type, result]\n }\n}\n","import type z from 'zod/v4'\nimport { type Action, type HttpMethod } from './action.js'\nimport { SilkweaveError } from './error.js'\nimport { unwrap } from './zod.js'\n\nconst PATH_PARAM_RE = /:([A-Za-z0-9_]+)/g\n\n/**\n * Resolve the HTTP verb for an action. An explicit `method` always wins;\n * otherwise `kind: 'query'` maps to `GET` and everything else to `POST`.\n */\nexport function actionMethod(action: Pick<Action, 'method' | 'kind'>): HttpMethod {\n if (action.method) { return action.method }\n return action.kind === 'query' ? 'GET' : 'POST'\n}\n\n/** Whether a request with this method carries a body (everything except GET). */\nexport function methodHasBody(method: HttpMethod): boolean {\n return method !== 'GET'\n}\n\n/** Extract the `:param` placeholder names from a route path template. */\nexport function pathParamNames(path: string | undefined): string[] {\n if (!path) { return [] }\n return [...path.matchAll(PATH_PARAM_RE)].map((match) => match[1])\n}\n\n/**\n * Assert that every `:param` in `action.path` and every `queryParams` entry is a\n * field of the input schema. Throws a `SilkweaveError` at registration time so\n * misconfigured routing fails fast instead of silently dropping values.\n */\nexport function validateActionRouting(action: Action): void {\n const shape = action.input.shape\n for (const param of pathParamNames(action.path)) {\n if (!(param in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" path \"${action.path}\" references \":${param}\" but the input schema has no \"${param}\" field`,\n 'invalid_action_routing'\n )\n }\n }\n for (const key of action.queryParams ?? []) {\n if (!(String(key) in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" lists query param \"${String(key)}\" but the input schema has no such field`,\n 'invalid_action_routing'\n )\n }\n }\n}\n\n/**\n * Coerce a raw string (from the URL path or query string) to the primitive the\n * field's schema expects. Non-string values pass through untouched (REST\n * frameworks like Fastify may have already coerced via JSON Schema), and a\n * failed coercion returns the original value so Zod surfaces a proper error.\n */\nfunction coerceScalar(field: z.ZodTypeAny | undefined, value: unknown): unknown {\n if (!field || typeof value !== 'string') { return value }\n const [base] = unwrap(field)\n const type = (base as { def?: { type?: string } }).def?.type\n if (type === 'number') {\n const num = Number(value)\n return value.trim() === '' || Number.isNaN(num) ? value : num\n }\n if (type === 'boolean') {\n if (value === 'true') { return true }\n if (value === 'false') { return false }\n return value\n }\n if (type === 'bigint') {\n try { return BigInt(value) } catch { return value }\n }\n return value\n}\n\nexport interface ActionInputSources {\n /** Path parameters keyed by `:param` name (e.g. Express/Fastify `req.params`). */\n params?: Record<string, string | undefined>\n /** Parsed query string (string values, or arrays/coerced values from a framework). */\n query?: Record<string, unknown>\n /** Parsed request body (already-typed JSON for body methods). */\n body?: unknown\n}\n\n/**\n * Merge an action's path params, query params, and body into a single input\n * object honouring its `method`/`path`/`queryParams` routing config:\n *\n * - body fields form the base layer (only for body-carrying methods),\n * - declared query params override (on bodyless GET requests every input field\n * that is not a path param is read from the query string),\n * - path params override last.\n *\n * String values from the path/query are coerced to the primitive their schema\n * expects. The result is not validated here - callers pass it to\n * `action.input.parse()` (or let a framework validate it).\n */\nexport function resolveActionInput(action: Action, sources: ActionInputSources): Record<string, unknown> {\n const shape = action.input.shape\n const method = actionMethod(action)\n const hasBody = methodHasBody(method)\n const params = sources.params ?? {}\n const query = sources.query ?? {}\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n\n const merged: Record<string, unknown> = {}\n\n if (hasBody && sources.body && typeof sources.body === 'object') {\n Object.assign(merged, sources.body as Record<string, unknown>)\n }\n\n for (const [key, raw] of Object.entries(query)) {\n if (raw === undefined) { continue }\n const declared = hasBody ? queryKeys.has(key) : (key in shape && !pathParams.has(key))\n if (!declared) { continue }\n merged[key] = Array.isArray(raw) ? raw : coerceScalar(shape[key], raw)\n }\n\n for (const key of pathParams) {\n const raw = params[key]\n if (raw === undefined) { continue }\n merged[key] = coerceScalar(shape[key], raw)\n }\n\n return merged\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Action, ActionStreamRun, isStreamingAction } from './action.js'\nimport { SilkweaveContext } from './context.js'\n\n/**\n * Drive a streaming action's async generator. Calls `onChunk` once per yielded\n * value and awaits it before pulling the next value from the generator - this\n * is what wires transport-level backpressure (SSE drain, stdout flush, tRPC\n * subscription consumer) back to the action.\n *\n * Returns the buffered array of all chunks. Use this for non-streaming\n * adapters or when a client has opted out of streaming (e.g. no MCP\n * `progressToken`). Pass `onChunk` to also emit each chunk on the wire.\n */\nexport async function runStreamingAction<C>(\n action: Action<any, any, string, any, C>,\n input: object,\n context: SilkweaveContext,\n onChunk?: (chunk: C, index: number) => void | Promise<void>\n): Promise<C[]> {\n if (!isStreamingAction(action)) {\n throw new Error(`Action ${action.name} is not a streaming action`)\n }\n const run = action.run as ActionStreamRun<object, C>\n const iter = run(input, context)\n const chunks: C[] = []\n let index = 0\n for await (const chunk of iter) {\n chunks.push(chunk)\n if (onChunk) { await onChunk(chunk, index) }\n index += 1\n }\n return chunks\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/util/context.ts","../src/lib/silkweave.ts","../src/util/action.ts","../src/util/error.ts","../src/util/zod.ts","../src/util/http.ts","../src/util/streaming.ts"],"sourcesContent":["export interface SilkweaveContext {\n keys: () => string[]\n has: (key: string) => boolean\n get: <T>(key: string) => T\n getOptional: <T>(key: string) => T | undefined\n set: <T>(key: string, value: T) => void\n fork: (store?: Record<string, unknown>) => SilkweaveContext\n}\n\nexport function createContext(store: Record<string, unknown> = {}): SilkweaveContext {\n return {\n keys: () => {\n return Object.keys(store)\n },\n has: (key: string): boolean => {\n return store[key] != null\n },\n get: <T>(key: string): T => {\n const value = store[key]\n if (value == null) { throw new Error(`Invalid context key: ${key}`) }\n return value as T\n },\n getOptional: <T>(key: string): T | undefined => {\n return store[key] as T | undefined\n },\n set: <T>(key: string, value: T) => {\n store[key] = value\n },\n fork: (value?: Record<string, unknown>) => {\n return createContext({ ...store, ...value })\n }\n }\n}\n","import { Action } from '../util/action.js'\nimport { Adapter, AdapterGenerator, SilkweaveOptions } from '../util/adapter.js'\nimport { createContext } from '../util/context.js'\n\nexport type { SilkweaveOptions } from '../util/adapter.js'\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface Silkweave<Actions extends Record<string, Action> = {}> {\n set: <T>(key: string, value: T) => Silkweave<Actions>\n adapter: (generator: AdapterGenerator) => Silkweave<Actions>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n action: <A extends Action<any, any, string, any>>(\n action: A\n ) => Silkweave<Actions & Record<A['name'], A>>\n actions: <Arr extends readonly Action[]>(\n actions: Arr\n ) => Silkweave<Actions & { [K in Arr[number] as K['name']]: K }>\n start: () => Promise<Silkweave<Actions>>\n}\n\nexport function silkweave(options: SilkweaveOptions): Silkweave {\n const adapters: Adapter[] = []\n const actions: Action[] = []\n const context = createContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const builder: Silkweave<any> = {\n set: (key, value) => {\n context.set(key, value)\n return builder\n },\n adapter: (generator) => {\n adapters.push(generator(options, context))\n return builder\n },\n action: (value) => {\n actions.push(value)\n return builder\n },\n actions: (values) => {\n actions.push(...values)\n return builder\n },\n start: async () => {\n await Promise.all(adapters.map((adapter) => {\n const filtered = adapter.allActions\n ? actions\n : actions.filter((action) => {\n if (!action.isEnabled) { return true }\n return action.isEnabled(adapter.context)\n })\n return adapter.start(filtered)\n }))\n return builder\n }\n }\n return builder\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport z from 'zod/v4'\nimport { SilkweaveContext } from './context.js'\n\nexport type ActionKind = 'query' | 'mutation'\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'\n\nexport type ActionRun<I, O> = (input: I, context: SilkweaveContext) => Promise<O>\nexport type ActionStreamRun<I, C> = (input: I, context: SilkweaveContext) => AsyncGenerator<C, void, void>\n\nexport interface Action<\n I extends object = any,\n O extends object = any,\n N extends string = string,\n K extends ActionKind = ActionKind,\n C = any\n> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n /**\n * Schema for individual chunks yielded by a streaming `run`. Required when\n * `run` is an async generator; adapters detect streaming actions by checking\n * `isStreamingAction(action)` at runtime, but type-aware tooling (inferRouter,\n * typegen) uses the presence of this field.\n */\n chunk?: z.ZodType<C>\n kind?: K\n /**\n * HTTP verb for REST-style adapters (fastify, nestjs `rest`). Defaults to\n * `POST`, or `GET` when `kind` is `'query'`. An explicit `method` always wins.\n */\n method?: HttpMethod\n /**\n * Route path for REST-style adapters. May contain `:param` placeholders\n * (e.g. `'spaces/:spaceId/users'`); each placeholder must be a key of the\n * input schema and is resolved from the URL path at runtime. When unset, the\n * adapter derives the path from `name`.\n */\n path?: string\n /**\n * Input fields sourced from the URL query string instead of the request body\n * (e.g. `['offset', 'limit']`). Each must be a key of the input schema; their\n * required/optional status is validated by the input schema as usual.\n */\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n /**\n * Default MCP result disposition for this action - `'json'` formats the\n * response with `jsonToolResult` (compact JSON text), `'smart'` (the default\n * when unset) uses `smartToolResult` (inlines small payloads, offloads large\n * ones to an embedded resource). This is only a default: a client that sends\n * `_meta.disposition` on the tool call always wins. Ignored by non-MCP\n * adapters.\n */\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O> | ActionStreamRun<I, C>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface NonStreamingActionInput<I extends object, O extends object, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface StreamingActionInput<I extends object, C, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n chunk: z.ZodType<C>\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionStreamRun<I, C>\n toolResult?: (response: C[], context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport function createAction<\n I extends object,\n C,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: StreamingActionInput<I, C, N, K>): StreamingActionInput<I, C, N, K>\nexport function createAction<\n I extends object,\n O extends object,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: NonStreamingActionInput<I, O, N, K>): NonStreamingActionInput<I, O, N, K>\nexport function createAction(action: Action): Action {\n return action\n}\n\n/**\n * Returns `true` when `action.run` is an async generator function (declared\n * with `async function*`). Adapters use this to switch between buffered\n * request/response and streaming chunk delivery.\n */\nexport function isStreamingAction(action: Action): boolean {\n return action.run?.constructor?.name === 'AsyncGeneratorFunction'\n}\n","export class SilkweaveError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode = 500\n ) {\n super(message)\n this.name = 'SilkweaveError'\n }\n}\n\nexport function notFound(message = 'Not found') {\n return new SilkweaveError(message, 'not_found', 404)\n}\n\nexport function badRequest(message = 'Bad request') {\n return new SilkweaveError(message, 'bad_request', 400)\n}\n\nexport function forbidden(message = 'Forbidden') {\n return new SilkweaveError(message, 'forbidden', 403)\n}\n\nexport function internal(message = 'Internal error') {\n return new SilkweaveError(message, 'internal', 500)\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from 'zod/v4'\n\nexport interface UnwrapResult {\n defaultValue?: any\n isOptional?: boolean\n isNullable?: boolean\n isReadOnly?: boolean\n}\n\nexport function unwrap(\n type: z.ZodTypeAny,\n result: UnwrapResult = {}\n): [z.ZodTypeAny, UnwrapResult] {\n if (type instanceof z.ZodOptional) {\n result.isOptional = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodNullable) {\n result.isNullable = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodReadonly) {\n result.isReadOnly = true\n return unwrap(type.def.innerType as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodDefault) {\n result.defaultValue = typeof type.def.defaultValue === 'function'\n ? type.def.defaultValue()\n : type.def.defaultValue\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else {\n return [type, result]\n }\n}\n","import type z from 'zod/v4'\nimport { type Action, type HttpMethod } from './action.js'\nimport { SilkweaveError } from './error.js'\nimport { unwrap } from './zod.js'\n\nconst PATH_PARAM_RE = /:([A-Za-z0-9_]+)/g\n\n/**\n * Resolve the HTTP verb for an action. An explicit `method` always wins;\n * otherwise `kind: 'query'` maps to `GET` and everything else to `POST`.\n */\nexport function actionMethod(action: Pick<Action, 'method' | 'kind'>): HttpMethod {\n if (action.method) { return action.method }\n return action.kind === 'query' ? 'GET' : 'POST'\n}\n\n/** Whether a request with this method carries a body (everything except GET). */\nexport function methodHasBody(method: HttpMethod): boolean {\n return method !== 'GET'\n}\n\n/** Extract the `:param` placeholder names from a route path template. */\nexport function pathParamNames(path: string | undefined): string[] {\n if (!path) { return [] }\n return [...path.matchAll(PATH_PARAM_RE)].map((match) => match[1])\n}\n\n/**\n * Assert that every `:param` in `action.path` and every `queryParams` entry is a\n * field of the input schema. Throws a `SilkweaveError` at registration time so\n * misconfigured routing fails fast instead of silently dropping values.\n */\nexport function validateActionRouting(action: Action): void {\n const shape = action.input.shape\n for (const param of pathParamNames(action.path)) {\n if (!(param in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" path \"${action.path}\" references \":${param}\" but the input schema has no \"${param}\" field`,\n 'invalid_action_routing'\n )\n }\n }\n for (const key of action.queryParams ?? []) {\n if (!(String(key) in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" lists query param \"${String(key)}\" but the input schema has no such field`,\n 'invalid_action_routing'\n )\n }\n }\n}\n\n/**\n * Coerce a raw string (from the URL path or query string) to the primitive the\n * field's schema expects. Non-string values pass through untouched (REST\n * frameworks like Fastify may have already coerced via JSON Schema), and a\n * failed coercion returns the original value so Zod surfaces a proper error.\n */\nfunction coerceScalar(field: z.ZodTypeAny | undefined, value: unknown): unknown {\n if (!field || typeof value !== 'string') { return value }\n const [base] = unwrap(field)\n const type = (base as { def?: { type?: string } }).def?.type\n if (type === 'number') {\n const num = Number(value)\n return value.trim() === '' || Number.isNaN(num) ? value : num\n }\n if (type === 'boolean') {\n if (value === 'true') { return true }\n if (value === 'false') { return false }\n return value\n }\n if (type === 'bigint') {\n try { return BigInt(value) } catch { return value }\n }\n return value\n}\n\nexport interface ActionInputSources {\n /** Path parameters keyed by `:param` name (e.g. Express/Fastify `req.params`). */\n params?: Record<string, string | undefined>\n /** Parsed query string (string values, or arrays/coerced values from a framework). */\n query?: Record<string, unknown>\n /** Parsed request body (already-typed JSON for body methods). */\n body?: unknown\n}\n\n/**\n * Merge an action's path params, query params, and body into a single input\n * object honouring its `method`/`path`/`queryParams` routing config:\n *\n * - body fields form the base layer (only for body-carrying methods),\n * - declared query params override (on bodyless GET requests every input field\n * that is not a path param is read from the query string),\n * - path params override last.\n *\n * String values from the path/query are coerced to the primitive their schema\n * expects. The result is not validated here - callers pass it to\n * `action.input.parse()` (or let a framework validate it).\n */\nexport function resolveActionInput(action: Action, sources: ActionInputSources): Record<string, unknown> {\n const shape = action.input.shape\n const method = actionMethod(action)\n const hasBody = methodHasBody(method)\n const params = sources.params ?? {}\n const query = sources.query ?? {}\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n\n const merged: Record<string, unknown> = {}\n\n if (hasBody && sources.body && typeof sources.body === 'object') {\n Object.assign(merged, sources.body as Record<string, unknown>)\n }\n\n for (const [key, raw] of Object.entries(query)) {\n if (raw === undefined) { continue }\n const declared = hasBody ? queryKeys.has(key) : (key in shape && !pathParams.has(key))\n if (!declared) { continue }\n merged[key] = Array.isArray(raw) ? raw : coerceScalar(shape[key], raw)\n }\n\n for (const key of pathParams) {\n const raw = params[key]\n if (raw === undefined) { continue }\n merged[key] = coerceScalar(shape[key], raw)\n }\n\n return merged\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Action, ActionStreamRun, isStreamingAction } from './action.js'\nimport { SilkweaveContext } from './context.js'\n\n/**\n * Drive a streaming action's async generator. Calls `onChunk` once per yielded\n * value and awaits it before pulling the next value from the generator - this\n * is what wires transport-level backpressure (SSE drain, stdout flush, tRPC\n * subscription consumer) back to the action.\n *\n * Returns the buffered array of all chunks. Use this for non-streaming\n * adapters or when a client has opted out of streaming (e.g. no MCP\n * `progressToken`). Pass `onChunk` to also emit each chunk on the wire.\n */\nexport async function runStreamingAction<C>(\n action: Action<any, any, string, any, C>,\n input: object,\n context: SilkweaveContext,\n onChunk?: (chunk: C, index: number) => void | Promise<void>\n): Promise<C[]> {\n if (!isStreamingAction(action)) {\n throw new Error(`Action ${action.name} is not a streaming action`)\n }\n const run = action.run as ActionStreamRun<object, C>\n const iter = run(input, context)\n const chunks: C[] = []\n let index = 0\n for await (const chunk of iter) {\n chunks.push(chunk)\n if (onChunk) { await onChunk(chunk, index) }\n index += 1\n }\n return chunks\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silkweave/core",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Silkweave Core",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@modelcontextprotocol/sdk": "^1.29.0",
25
- "@silkweave/logger": "2.2.0"
25
+ "@silkweave/logger": "2.3.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "zod": "^3.25.0"