stitchkit 0.9.0 → 0.10.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/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  emitResult,
5
5
  parseCliArgs,
6
6
  pollUntilDone
7
- } from "./index-13psnhhe.js";
7
+ } from "./index-f39j6twc.js";
8
8
  import"./index-0ed3bx43.js";
9
9
  import"./index-jgpsd7dy.js";
10
10
  import"./index-tm7dqzxc.js";
@@ -5,9 +5,9 @@ export type Transport = (typeof ALL_TRANSPORTS)[number];
5
5
  /**
6
6
  * The transport tag on `ctx.source`. The four built-ins keep autocomplete, but
7
7
  * the union is **open** (`string & {}`) so a bring-your-own transport — e.g. a
8
- * raw-WebSocket lane driving a contract through `createContractDispatcher` can
9
- * tag its own calls (`source: 'local-ws'`). `source` is transport-only and
10
- * carries no framework behaviour (→ ADR 0002 / ADR 0027).
8
+ * raw-WebSocket lane that runs a contract through the app's own dispatch loop
9
+ * can tag its own calls (`source: 'local-ws'`). `source` is transport-only and
10
+ * carries no framework behaviour (→ ADR 0002).
11
11
  */
12
12
  export type TransportSource = 'http' | 'mcp' | 'agent' | 'cli' | (string & {});
13
13
  interface EndpointDefBase {
@@ -40,10 +40,10 @@ interface EndpointDefBase {
40
40
  * The core attaches **no** behaviour to it (it stays generic — ADR 0002): it
41
41
  * rides through to `MethodDef.idempotent`, where a transport that can retry
42
42
  * reads it. A reliable bring-your-own-transport lane (e.g. a raw-WebSocket
43
- * client over `createContractDispatcher`) replays an `idempotent` call after a
44
- * reconnect — that is the durability guarantee — while a non-idempotent one is
45
- * rejected rather than re-sent (a duplicate would be a second side effect).
46
- * Unset means "unknown" — a careful transport treats it as non-idempotent.
43
+ * client) replays an `idempotent` call after a reconnect — that is the
44
+ * durability guarantee — while a non-idempotent one is rejected rather than
45
+ * re-sent (a duplicate would be a second side effect). Unset means "unknown" —
46
+ * a careful transport treats it as non-idempotent.
47
47
  */
48
48
  idempotent?: boolean;
49
49
  /**
@@ -129,6 +129,17 @@ export interface RuntimeContext {
129
129
  input: unknown;
130
130
  file?: File;
131
131
  source: TransportSource;
132
+ /**
133
+ * The raw Web `Request`, its parsed `URL` and `Headers` — set on the HTTP
134
+ * transport (and reachable in every lifecycle hook, including `onError` on a
135
+ * validation failure). Absent on the non-HTTP transports (MCP / agent / CLI /
136
+ * a bring-your-own lane), which carry no `Request`, so they are optional and a
137
+ * reader narrows them. Web Fetch types only — the core stays Fetch-clean
138
+ * (→ ADR 0013).
139
+ */
140
+ req?: Request;
141
+ url?: URL;
142
+ headers?: Headers;
132
143
  traceId?: string;
133
144
  spanId?: string;
134
145
  ipAddress?: string;
@@ -140,6 +151,11 @@ export interface HandlerContext<TParams = undefined, TInput = undefined> {
140
151
  input: TInput;
141
152
  file?: File;
142
153
  source: TransportSource;
154
+ /** Raw Web `Request` / `URL` / `Headers` — set on the HTTP transport, absent
155
+ * on the tool transports (see {@link RuntimeContext}). */
156
+ req?: Request;
157
+ url?: URL;
158
+ headers?: Headers;
143
159
  traceId?: string;
144
160
  spanId?: string;
145
161
  ipAddress?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
@@ -1000,4 +1000,4 @@ function safeInputSchema(tool) {
1000
1000
  }
1001
1001
  }
1002
1002
 
1003
- export { coerceJsonArgs, toolResultFromError, executeToolMethod, flattenDiscriminatedUnion, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
1003
+ export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
@@ -343,38 +343,15 @@ async function readJsonBody(req) {
343
343
  badRequest("Invalid JSON body");
344
344
  }
345
345
  }
346
- async function buildContext(req, url, method, pathParams, traceId, clientIp, maxUploadBytes) {
347
- const parsedParams = method.paramsSchema ? method.paramsSchema.parse(pathParams) : undefined;
348
- let parsedInput;
349
- let file;
350
- if (method.multipart) {
351
- const cap = method.maxUploadBytes ?? maxUploadBytes;
352
- const multipart = await parseMultipart(req, method.multipart, method.inputSchema, cap);
353
- parsedInput = multipart.fields;
354
- file = multipart.file;
355
- } else if (method.inputSchema) {
356
- if (req.method === "GET") {
357
- parsedInput = method.inputSchema.parse(parseQueryParams(url));
358
- } else if (req.method === "DELETE") {
359
- const ct = req.headers.get("content-type");
360
- if (ct?.includes("application/json")) {
361
- parsedInput = method.inputSchema.parse(await readJsonBody(req));
362
- } else {
363
- parsedInput = method.inputSchema.parse(parseQueryParams(url));
364
- }
365
- } else {
366
- parsedInput = method.inputSchema.parse(await readJsonBody(req));
367
- }
368
- }
346
+ function buildBaseContext(req, url, pathParams, traceId, clientIp) {
369
347
  const safePathParams = {};
370
348
  for (const [k, v] of Object.entries(pathParams)) {
371
349
  if (!RESERVED_KEYS.has(k) && !isUnsafeKey(k))
372
350
  safePathParams[k] = v;
373
351
  }
374
352
  return {
375
- params: parsedParams,
376
- input: parsedInput,
377
- ...file && { file },
353
+ params: pathParams,
354
+ input: undefined,
378
355
  source: "http",
379
356
  req,
380
357
  url,
@@ -384,6 +361,27 @@ async function buildContext(req, url, method, pathParams, traceId, clientIp, max
384
361
  ...getClientInfo(req, clientIp)
385
362
  };
386
363
  }
364
+ async function parseRequestInto(ctx, req, url, method, maxUploadBytes) {
365
+ if (method.paramsSchema) {
366
+ ctx.params = method.paramsSchema.parse(ctx.params);
367
+ }
368
+ if (method.multipart) {
369
+ const cap = method.maxUploadBytes ?? maxUploadBytes;
370
+ const multipart = await parseMultipart(req, method.multipart, method.inputSchema, cap);
371
+ ctx.input = multipart.fields;
372
+ if (multipart.file)
373
+ ctx.file = multipart.file;
374
+ } else if (method.inputSchema) {
375
+ if (req.method === "GET") {
376
+ ctx.input = method.inputSchema.parse(parseQueryParams(url));
377
+ } else if (req.method === "DELETE") {
378
+ const ct = req.headers.get("content-type");
379
+ ctx.input = ct?.includes("application/json") ? method.inputSchema.parse(await readJsonBody(req)) : method.inputSchema.parse(parseQueryParams(url));
380
+ } else {
381
+ ctx.input = method.inputSchema.parse(await readJsonBody(req));
382
+ }
383
+ }
384
+ }
387
385
  function buildErrorContext(req, url, traceId, clientIp) {
388
386
  return {
389
387
  params: undefined,
@@ -447,8 +445,8 @@ function levelForStatus(status) {
447
445
  return "warn";
448
446
  return "info";
449
447
  }
450
- function buildLogFields(method, path, status, durationMs, traceId) {
451
- return { traceId, method, path, status, durationMs };
448
+ function buildLogFields(method, path, status, durationMs, traceId, errorCode) {
449
+ return { traceId, method, path, status, durationMs, ...errorCode && { errorCode } };
452
450
  }
453
451
  function formatMs(ms) {
454
452
  if (ms >= 1000)
@@ -492,20 +490,21 @@ function logIncoming(req, pathname, traceId, ipAddress) {
492
490
  }
493
491
  return log;
494
492
  }
495
- function logOutgoing(req, pathname, status, log, ipAddress) {
493
+ function logOutgoing(req, pathname, status, log, ipAddress, errorCode) {
496
494
  const ms = elapsedMs(log.startTime);
497
495
  if (isProd) {
498
496
  console.log(JSON.stringify({
499
497
  ts: new Date().toISOString(),
500
498
  level: levelForStatus(status),
501
499
  msg: `${req.method} ${pathname} ${status}`,
502
- ...buildLogFields(req.method, pathname, status, Math.round(ms), log.traceId),
500
+ ...buildLogFields(req.method, pathname, status, Math.round(ms), log.traceId, errorCode),
503
501
  ip: ipAddress
504
502
  }));
505
503
  return;
506
504
  }
507
505
  const mc = METHOD_COLOR[req.method] ?? c.dim;
508
- console.log(`${c.gray}[${timestamp()}]${c.reset} ${mc}${req.method}${c.reset} ${c.dim}${log.traceId}${c.reset} ${c.cyan}←${c.reset} ${safePath(pathname)} ${statusColor(status)}${status}${c.reset} ${durationColor(ms)}${formatMs(ms)}${c.reset} ${ipLabel(ipAddress ?? "")}`);
506
+ const code = errorCode ? ` ${c.red}${errorCode}${c.reset}` : "";
507
+ console.log(`${c.gray}[${timestamp()}]${c.reset} ${mc}${req.method}${c.reset} ${c.dim}${log.traceId}${c.reset} ${c.cyan}←${c.reset} ${safePath(pathname)} ${statusColor(status)}${status}${c.reset}${code} ${durationColor(ms)}${formatMs(ms)}${c.reset} ${ipLabel(ipAddress ?? "")}`);
509
508
  }
510
509
 
511
510
  // src/server/create.ts
@@ -534,15 +533,15 @@ function createHandler(config) {
534
533
  });
535
534
  reqLog = { traceId, startTime: performance.now() };
536
535
  }
537
- const logDone = (status) => {
536
+ const logDone = (status, errorCode) => {
538
537
  if (!reqLog)
539
538
  return;
540
539
  if (useDefaultLog)
541
- logOutgoing(req, url.pathname, status, reqLog, ipAddress);
540
+ logOutgoing(req, url.pathname, status, reqLog, ipAddress, errorCode);
542
541
  if (customLogger) {
543
542
  const durationMs = Math.round(elapsedMs(reqLog.startTime));
544
543
  const level = levelForStatus(status);
545
- customLogger[level](`${req.method} ${url.pathname} ${status} ${durationMs}ms`, buildLogFields(req.method, url.pathname, status, durationMs, reqLog.traceId));
544
+ customLogger[level](`${req.method} ${url.pathname} ${status}${errorCode ? ` ${errorCode}` : ""} ${durationMs}ms`, buildLogFields(req.method, url.pathname, status, durationMs, reqLog.traceId, errorCode));
546
545
  }
547
546
  };
548
547
  const respondError = async (err, errCtx, endpoint) => {
@@ -557,7 +556,7 @@ function createHandler(config) {
557
556
  } catch {}
558
557
  }
559
558
  const appErr = normalizeError(err);
560
- logDone(appErr.status);
559
+ logDone(appErr.status, appErr.code);
561
560
  return json(appErr.toJSON(), appErr.status, cors, req);
562
561
  };
563
562
  if (cors && req.method === "OPTIONS") {
@@ -600,9 +599,9 @@ function createHandler(config) {
600
599
  return respondError(new AppError("NOT_FOUND", "Not found", 404));
601
600
  }
602
601
  const { method, pathParams, groupHooks } = match;
603
- let ctx;
602
+ const ctx = buildBaseContext(req, url, pathParams, traceId, clientIp);
604
603
  try {
605
- ctx = await buildContext(req, url, method, pathParams, traceId, clientIp, config.maxUploadBytes);
604
+ await parseRequestInto(ctx, req, url, method, config.maxUploadBytes);
606
605
  if (hooks?.beforeHandle) {
607
606
  await hooks.beforeHandle(ctx, method);
608
607
  }
package/dist/node.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createImplement,
4
4
  createSocketIOServer,
5
5
  implement
6
- } from "./index-zshrc6kx.js";
6
+ } from "./index-s8gtzt8w.js";
7
7
  import {
8
8
  AppError,
9
9
  appError,
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/observability/audit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAe,KAAK,eAAe,EAAmB,MAAM,YAAY,CAAC;AAGhF,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,EACN,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KACpD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD;;;OAGG;IACH,QAAQ,EAAE,aAAa,CAAC;CACzB;AAmBD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CA+F9D"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/observability/audit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAe,KAAK,eAAe,EAAmB,MAAM,YAAY,CAAC;AAGhF,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,EACN,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KACpD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD;;;OAGG;IACH,QAAQ,EAAE,aAAa,CAAC;CACzB;AAmBD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAgG9D"}
@@ -1,4 +1,5 @@
1
1
  import type { TransportSource } from '../contract';
2
+ import type { JsonValue } from './sanitize';
2
3
  import { type TraceContext } from './trace';
3
4
  /** Everything known about the request in flight. */
4
5
  export interface RequestContext {
@@ -22,6 +23,7 @@ export interface RequestContext {
22
23
  error?: {
23
24
  code?: string;
24
25
  message?: string;
26
+ details?: JsonValue;
25
27
  };
26
28
  }
27
29
  /** Run `fn` with `ctx` as the active request context. */
@@ -40,11 +42,14 @@ export declare function getUserId(): string | undefined;
40
42
  export declare function setRequestUser(userId: string): void;
41
43
  /**
42
44
  * Record the error outcome on the active context. Call this from the error
43
- * handler — the audit hook reads it when the request completes.
45
+ * handler — the audit hook reads it when the request completes. Optional
46
+ * `details` carries structure the message string flattens (e.g. the failing
47
+ * Zod issues) onto `RequestEvent.errorDetail`.
44
48
  */
45
49
  export declare function setRequestError(error: {
46
50
  code?: string;
47
51
  message?: string;
52
+ details?: JsonValue;
48
53
  }): void;
49
54
  /** Options for `wrapInRequestContext`. */
50
55
  export interface WrapRequestContextOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjE,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,4CAA4C;IAC5C,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAID,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED,mEAAmE;AACnE,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGhF;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EACvD,OAAO,GAAE,yBAA8B,GACtC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAiBhD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjE,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,4CAA4C;IAC5C,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC;CAClE;AAID,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED,mEAAmE;AACnE,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,GAAG,IAAI,CAGP;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EACvD,OAAO,GAAE,yBAA8B,GACtC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAiBhD"}
@@ -31,6 +31,12 @@ export interface RequestEvent {
31
31
  errorCode?: string;
32
32
  /** Error message — failures only. */
33
33
  errorMessage?: string;
34
+ /**
35
+ * Structured error detail — failures only, when the error handler recorded it
36
+ * via `setRequestError({ details })` (e.g. the failing validation issues the
37
+ * `errorMessage` string flattens). HTTP path only.
38
+ */
39
+ errorDetail?: JsonValue;
34
40
  /** Sanitised request payload — the HTTP body or the tool arguments. */
35
41
  payload: JsonValue | null;
36
42
  /** Item count of the result, when it is a list. */
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/observability/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/observability/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,uEAAuE;IACvE,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -148,6 +148,7 @@ function createAuditHook(config) {
148
148
  durationMs,
149
149
  errorCode: ctx.error?.code,
150
150
  errorMessage: ctx.error?.message,
151
+ ...ctx.error?.details !== undefined && { errorDetail: ctx.error.details },
151
152
  payload: sanitizePayload(body, sanitize),
152
153
  resultSize: null,
153
154
  responseBytes: 0,
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Transport-agnostic: wrap it around any pub/sub. `createSocketIOClient`'s
11
11
  * `retain` option uses it internally, and a bring-your-own-transport lane (a raw
12
- * WebSocket driving a contract through `createContractDispatcher`) can use it
12
+ * WebSocket driving a contract through the app's own dispatch loop) can use it
13
13
  * directly for its own event channel. Browser-safe — no Node built-ins.
14
14
  */
15
15
  export interface RetainedTopics<Events extends Record<string, unknown>> {
@@ -5,6 +5,23 @@
5
5
  import { type RuntimeContext } from '../contract';
6
6
  import { type ClientIpOptions } from './request';
7
7
  import type { MethodDef } from './types';
8
- export declare function buildContext(req: Request, url: URL, method: MethodDef, pathParams: Record<string, string>, traceId: string, clientIp: ClientIpOptions, maxUploadBytes?: number): Promise<RuntimeContext>;
8
+ /**
9
+ * Assemble everything knowable from the URL alone — path params, the request,
10
+ * trace id and client info — **before** any schema parsing. Bound first so a
11
+ * later validation failure still hands `onError` the path params and the
12
+ * request (an empty context loses both); `parseRequestInto` then enriches it
13
+ * with the schema-validated `params` / `input`.
14
+ *
15
+ * `params` starts as the raw matched path params (a property of the URL, known
16
+ * the moment the route matched) and is replaced by the validated value when the
17
+ * endpoint declares a `paramsSchema`.
18
+ */
19
+ export declare function buildBaseContext(req: Request, url: URL, pathParams: Record<string, string>, traceId: string, clientIp: ClientIpOptions): RuntimeContext;
20
+ /**
21
+ * Parse `params` / `input` against the endpoint schemas and write them onto an
22
+ * already-assembled base context. A validation failure throws a `ZodError`
23
+ * here — the base context (path params, request) is preserved for `onError`.
24
+ */
25
+ export declare function parseRequestInto(ctx: RuntimeContext, req: Request, url: URL, method: MethodDef, maxUploadBytes?: number): Promise<void>;
9
26
  export declare function buildErrorContext(req: Request, url: URL, traceId: string, clientIp: ClientIpOptions): RuntimeContext;
10
27
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmCzC,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,EACzB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,cAAc,CAAC,CA8CzB;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,cAAc,CAWhB"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmCzC;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,cAAc,CAmBhB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAwBf;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,cAAc,CAWhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAgNxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAkNxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
@@ -12,7 +12,7 @@ import {
12
12
  socketIoLane,
13
13
  staticRoute,
14
14
  webSocketLane
15
- } from "../index-zshrc6kx.js";
15
+ } from "../index-s8gtzt8w.js";
16
16
  import {
17
17
  createAuthHook,
18
18
  createBearerResolver,
@@ -3,12 +3,13 @@ export declare function elapsedMs(startTime: number): number;
3
3
  /** Map an HTTP status to a log level. */
4
4
  export declare function levelForStatus(status: number): 'error' | 'warn' | 'info';
5
5
  /** The structured fields shared by every completed-request log line. */
6
- export declare function buildLogFields(method: string, path: string, status: number, durationMs: number, traceId: string): {
6
+ export declare function buildLogFields(method: string, path: string, status: number, durationMs: number, traceId: string, errorCode?: string): {
7
7
  traceId: string;
8
8
  method: string;
9
9
  path: string;
10
10
  status: number;
11
11
  durationMs: number;
12
+ errorCode?: string;
12
13
  };
13
14
  export interface RequestLog {
14
15
  traceId: string;
@@ -18,5 +19,5 @@ export declare function shouldLog(pathname: string, method: string): boolean;
18
19
  /** Open the timing window for a request. Development prints a `→` line. */
19
20
  export declare function logIncoming(req: Request, pathname: string, traceId: string, ipAddress?: string): RequestLog;
20
21
  /** Close a request. Development: `←` line. Production: one structured JSON line. */
21
- export declare function logOutgoing(req: Request, pathname: string, status: number, log: RequestLog, ipAddress?: string): void;
22
+ export declare function logOutgoing(req: Request, pathname: string, status: number, log: RequestLog, ipAddress?: string, errorCode?: string): void;
22
23
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoBD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEvF;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAoBN"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoBD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAEA;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CA4BN"}
package/dist/tools.d.ts CHANGED
@@ -4,7 +4,6 @@ export { type CliConfig, createCli } from './tools/cli';
4
4
  export type { ExitCodeMap } from './tools/cli-format';
5
5
  export type { CliWaitConfig } from './tools/cli-wait';
6
6
  export { coerceJsonArgs } from './tools/coerce';
7
- export { type ContractDispatcher, type ContractDispatcherConfig, createContractDispatcher, } from './tools/dispatch';
8
7
  export type { ToolCallHooks, ToolLifecycle, ToolResult } from './tools/execute';
9
8
  export { flattenDiscriminatedUnion } from './tools/flatten';
10
9
  export { buildToolManifest, type ToolManifestEntry } from './tools/manifest';
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/tools.js CHANGED
@@ -8,14 +8,13 @@ import {
8
8
  collectTools,
9
9
  createCli,
10
10
  createToolRunner,
11
- executeToolMethod,
12
11
  fetchGuarded,
13
12
  flattenDiscriminatedUnion,
14
13
  formatToolError,
15
14
  pollUntil,
16
15
  readCapped,
17
16
  toolResultFromError
18
- } from "./index-13psnhhe.js";
17
+ } from "./index-f39j6twc.js";
19
18
  import {
20
19
  toJsonSchema
21
20
  } from "./index-0ed3bx43.js";
@@ -69,30 +68,6 @@ function mountAgent(services, config = {}) {
69
68
  }
70
69
  return tools;
71
70
  }
72
- // src/tools/dispatch.ts
73
- function createContractDispatcher(services, config) {
74
- const list = Array.isArray(services) ? services : [services];
75
- const index = new Map;
76
- for (const service of list) {
77
- for (const [name, method] of Object.entries(service.methods)) {
78
- if (index.has(name)) {
79
- throw new Error(`createContractDispatcher: duplicate method "${name}" across services`);
80
- }
81
- index.set(name, method);
82
- }
83
- }
84
- return {
85
- methods: [...index.keys()],
86
- dispatch(method, args, context) {
87
- const target = index.get(method);
88
- if (!target) {
89
- return Promise.resolve(toolResultFromError(new AppError("NOT_FOUND", `Unknown method: ${method}`, 404)));
90
- }
91
- const ctx = { ...config.context, ...context, source: config.source };
92
- return executeToolMethod(target, method, args, ctx, config.hooks, config.lifecycle, config.coerceJsonArgs ?? false);
93
- }
94
- };
95
- }
96
71
  // src/tools/manifest.ts
97
72
  function buildToolManifest(tools) {
98
73
  return tools.map((t) => {
@@ -1311,7 +1286,6 @@ export {
1311
1286
  createToolkit,
1312
1287
  createStdioMcpServer,
1313
1288
  createMcpHandler,
1314
- createContractDispatcher,
1315
1289
  createCli,
1316
1290
  collectTools,
1317
1291
  coerceJsonArgs,
package/llms-full.txt CHANGED
@@ -1876,37 +1876,20 @@ Notes:
1876
1876
 
1877
1877
  Sometimes the transport is neither HTTP nor Socket.IO — a desktop app whose UI
1878
1878
  webview talks to its own local Bun sidecar over a raw WebSocket, an IPC channel,
1879
- a queue worker. You still want one contract: a `defineContract` with typed
1880
- client/server, Zod validation and a typed error envelope, not a hand-rolled
1881
- method registry alongside it.
1879
+ a queue worker. You can still drive it from one `defineContract`: share the
1880
+ contract's Zod schemas to validate each inbound frame, run your handlers, and
1881
+ reuse the contract metadata below. You own **both** the wire (framing,
1882
+ handshake, reconnect) *and* the per-call validate-run loop — stitchkit ships the
1883
+ contract and its metadata, not a transport engine. A reliable-RPC-over-raw-
1884
+ WebSocket engine would be a competing WebSocket transport
1885
+ ([ADR 0008](../decisions/0008-thin-wrappers.md)); the wire stays yours.
1882
1886
 
1883
- stitchkit ships the **executor**, not the transport. `createContractDispatcher`
1884
- runs a contract method by its key through the *same* core as the MCP / agent
1885
- mounts — same validation, the same `{ ok, data } | { ok: false, code, … }`
1886
- envelope, the same hooks and `beforeHandle` scope gate. You own the wire (framing,
1887
- handshake, reconnect) and call `dispatch` per inbound frame.
1887
+ Two pieces of the contract carry straight over to a bring-your-own lane:
1888
1888
 
1889
- ```ts
1890
- import { createContractDispatcher } from 'stitchkit/tools'
1891
- import { implement } from 'stitchkit/server'
1892
-
1893
- const service = implement(runtimeContract, { 'tasks.setDone': (ctx) => doIt(ctx.input), … })
1894
-
1895
- const dispatcher = createContractDispatcher(service, { source: 'local-ws' })
1896
-
1897
- // In your raw-WebSocket server, per `{ id, method, params }` frame:
1898
- ws.onmessage = async (frame) => {
1899
- const { id, method, params } = JSON.parse(frame.data)
1900
- const result = await dispatcher.dispatch(method, params) // validates + runs
1901
- ws.send(JSON.stringify({ id, ...result })) // { ok, data } | { ok:false, code, … }
1902
- }
1903
- ```
1904
-
1905
- `dispatch` never throws for a normal call — a handler error becomes a failed
1906
- result, and an unknown method is a `NOT_FOUND` result. Pass `hooks`
1907
- (`beforeToolCall` / `afterToolCall`) and `lifecycle.beforeHandle` to audit and
1908
- scope-guard exactly like the other transports. Tag calls with your own
1909
- `source` — `TransportSource` is an open union.
1889
+ - **`source` is an open tag.** `TransportSource` is `'http' | 'mcp' | 'agent' |
1890
+ 'cli' | (string & {})`, so a handler or hook can tell your transport's calls
1891
+ apart tag them `source: 'local-ws'` and read `ctx.source`.
1892
+ - **`idempotent` drives replay-on-reconnect** — see below.
1910
1893
 
1911
1894
  ### Durability — `idempotent` + replay
1912
1895
 
@@ -1932,8 +1915,9 @@ also catches up on the latest pushed state.
1932
1915
 
1933
1916
  This is deliberately *not* a reliable-RPC engine — that would be a competing
1934
1917
  WebSocket transport ([ADR 0008](../decisions/0008-thin-wrappers.md)). stitchkit
1935
- gives you the executor and the metadata; the wire stays yours. See
1936
- [ADR 0027](../decisions/0027-transport-neutral-contract-execution.md).
1918
+ gives you the contract and the metadata (`idempotent`, the open `source` tag,
1919
+ `createRetainedTopics`); the wire and the per-call execution stay yours. See
1920
+ [ADR 0028](../decisions/0028-revert-contract-dispatcher.md).
1937
1921
 
1938
1922
 
1939
1923
  ==============================================================================
@@ -3058,7 +3042,6 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
3058
3042
  | `mountMcp` | function | add contract tools to an existing `McpServer` — [guide](../guide/mcp-and-agents.md#mountmcp) |
3059
3043
  | `implementRemote` | function | bind a contract to a remote HTTP API — [guide](../guide/mcp-and-agents.md#proxying-a-remote-api--implementremote) |
3060
3044
  | `mountAgent` | function | a Vercel AI SDK `ToolSet` from a service — [guide](../guide/mcp-and-agents.md#ai-agents--mountagent) |
3061
- | `createContractDispatcher` | function | run a contract over a bring-your-own transport — [guide](../guide/realtime.md#bring-your-own-transport) |
3062
3045
  | `createCli` | function | a command-line program from contracts — [guide](../guide/cli.md) (also on `stitchkit/cli`) |
3063
3046
  | `createToolkit` | function | context-typed tool mounts — [guide](../guide/cli.md#typed-context) |
3064
3047
  | `mountViewFile` | function | a native multimodal "view file" MCP tool |
@@ -3070,8 +3053,6 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
3070
3053
  | `ImplementRemoteOptions` | _type_ | options for `implementRemote` |
3071
3054
  | `McpMountConfig` | _type_ | config for `mountMcp` |
3072
3055
  | `AgentMountConfig` | _type_ | config for `mountAgent` |
3073
- | `ContractDispatcher` | _type_ | the `createContractDispatcher` handle |
3074
- | `ContractDispatcherConfig` | _type_ | config for `createContractDispatcher` |
3075
3056
  | `AgentContext` | _type_ | the context merged into agent tool handlers |
3076
3057
  | `CliConfig` | _type_ | config for `createCli` |
3077
3058
  | `CliWaitConfig` | _type_ | `--wait` polling config |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",
@@ -155,8 +155,8 @@
155
155
  "@tanstack/react-query": "5.101.0",
156
156
  "@types/bun": "^1.3.14",
157
157
  "@types/json-schema": "^7.0.15",
158
- "@types/react": "^19.2.16",
159
- "ai": "^6.0.196",
158
+ "@types/react": "^19.2.17",
159
+ "ai": "^6.0.207",
160
160
  "react": "^19.2.7",
161
161
  "react-query-kit": "^3.3.4",
162
162
  "socket.io": "^4.8.3",
@@ -1,65 +0,0 @@
1
- /**
2
- * Drive a contract over a **bring-your-own transport**.
3
- *
4
- * The HTTP server, the MCP mount and the agent mount all run a contract method
5
- * the same way: slice the flat args, validate `params` / `input` against the Zod
6
- * schemas, run the handler, validate the output, and return a typed result
7
- * envelope. `createContractDispatcher` exposes exactly that core for a transport
8
- * stitchkit does not own — a raw WebSocket lane (webview ↔ a local sidecar), an
9
- * IPC channel, a queue worker. The transport owns the wire (framing, handshake,
10
- * reconnect); the dispatcher owns "given a method name and args, run it safely."
11
- *
12
- * This is the same execution path as `mountMcp` / `mountAgent` (it shares
13
- * `executeToolMethod`), so a bespoke transport gets identical validation and the
14
- * identical `{ ok, code, details, hint }` error envelope for free, instead of a
15
- * hand-rolled method registry. → ADR 0027. Upholds ADR 0008 (no competing
16
- * engine — the transport is the app's) and ADR 0002 (the core stays generic —
17
- * `source` is a free tag, `idempotent` carries no built-in behaviour).
18
- */
19
- import { type TransportSource } from '../contract';
20
- import type { ServiceDef } from '../server/types';
21
- import { type ToolCallHooks, type ToolLifecycle, type ToolResult } from './execute';
22
- export interface ContractDispatcherConfig {
23
- /** Transport tag written to every call's `ctx.source` — e.g. `'local-ws'`. */
24
- source: TransportSource;
25
- /** Static context merged into every call (overridden by per-call context). */
26
- context?: Record<string, unknown>;
27
- /**
28
- * Observability hooks — the same `beforeToolCall` / `afterToolCall` the MCP and
29
- * agent mounts fire, so a bespoke transport audits calls the same way.
30
- */
31
- hooks?: ToolCallHooks;
32
- /**
33
- * Auth / scope gate and result transform run for every call — pass a
34
- * `createAuthHook` result as `beforeHandle` to scope-guard the transport like
35
- * an HTTP route.
36
- */
37
- lifecycle?: ToolLifecycle;
38
- /**
39
- * Coerce JSON-stringified array / object arguments before validation. Off by
40
- * default — a structured transport (WebSocket JSON) sends real types; only an
41
- * LLM-style flat-string transport needs it.
42
- */
43
- coerceJsonArgs?: boolean;
44
- }
45
- export interface ContractDispatcher {
46
- /**
47
- * Run one contract method by its endpoint key (e.g. `'transcriptions.list'`)
48
- * with a flat argument object. Returns the `{ ok: true, data } | { ok: false,
49
- * code, details?, hint? }` envelope the MCP / agent transports use — it does
50
- * not throw for a normal call; a handler error becomes a failed result, and an
51
- * unknown method is a `NOT_FOUND` result. Per-call `context` is merged after
52
- * the static `config.context` (neither can shadow `source`).
53
- */
54
- dispatch(method: string, args: Record<string, unknown>, context?: Record<string, unknown>): Promise<ToolResult>;
55
- /** Every method key this dispatcher can run, across the given services. */
56
- readonly methods: readonly string[];
57
- }
58
- /**
59
- * Build a {@link ContractDispatcher} from one or more `implement()` services.
60
- * Every method of every service is dispatchable by its key — exposure is the
61
- * transport's choice (which services it dispatches), not the contract's `expose`
62
- * (that gates the built-in HTTP / MCP / agent / CLI transports).
63
- */
64
- export declare function createContractDispatcher(services: ServiceDef | ServiceDef[], config: ContractDispatcherConfig): ContractDispatcher;
65
- //# sourceMappingURL=dispatch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/tools/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,EAEhB,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,MAAM,EAAE,eAAe,CAAC;IACxB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE,EACnC,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAqCpB"}