stitchkit 0.25.0 → 0.27.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.
Files changed (59) hide show
  1. package/dist/browser/client-multipart.d.ts +22 -0
  2. package/dist/browser/client-multipart.d.ts.map +1 -0
  3. package/dist/browser/client.d.ts.map +1 -1
  4. package/dist/browser/http.d.ts +7 -1
  5. package/dist/browser/http.d.ts.map +1 -1
  6. package/dist/cli.js +2 -2
  7. package/dist/contract/define.d.ts +79 -2
  8. package/dist/contract/define.d.ts.map +1 -1
  9. package/dist/contract/factory.d.ts +1 -0
  10. package/dist/contract/factory.d.ts.map +1 -1
  11. package/dist/contract/index.js +1 -1
  12. package/dist/{index-h9d1fm0p.js → index-4whcb3c3.js} +64 -22
  13. package/dist/{index-a9n8m4ec.js → index-jvescqgr.js} +1 -1
  14. package/dist/{index-x62gnfsk.js → index-pmftwk2a.js} +19 -1
  15. package/dist/{index-g8kyab85.js → index-y4132gqh.js} +81 -12
  16. package/dist/{index-tje0q6gp.js → index-zfscdskj.js} +6 -1
  17. package/dist/{index-4gawbm74.js → index-zza375qp.js} +41 -3
  18. package/dist/index.js +39 -25
  19. package/dist/internal/errors.d.ts +6 -1
  20. package/dist/internal/errors.d.ts.map +1 -1
  21. package/dist/internal/write-download.d.ts +17 -0
  22. package/dist/internal/write-download.d.ts.map +1 -0
  23. package/dist/node.js +3 -3
  24. package/dist/server/create.d.ts.map +1 -1
  25. package/dist/server/error-hook.d.ts +14 -3
  26. package/dist/server/error-hook.d.ts.map +1 -1
  27. package/dist/server/implement.d.ts.map +1 -1
  28. package/dist/server/index.d.ts +2 -1
  29. package/dist/server/index.d.ts.map +1 -1
  30. package/dist/server/index.js +21 -8
  31. package/dist/server/middleware/cors.d.ts +19 -0
  32. package/dist/server/middleware/cors.d.ts.map +1 -1
  33. package/dist/server/openapi.d.ts.map +1 -1
  34. package/dist/server/router.d.ts +27 -0
  35. package/dist/server/router.d.ts.map +1 -1
  36. package/dist/server/types.d.ts +44 -1
  37. package/dist/server/types.d.ts.map +1 -1
  38. package/dist/tools/agent.d.ts +2 -0
  39. package/dist/tools/agent.d.ts.map +1 -1
  40. package/dist/tools/cli.d.ts.map +1 -1
  41. package/dist/tools/execute.d.ts +1 -1
  42. package/dist/tools/execute.d.ts.map +1 -1
  43. package/dist/tools/list-names.d.ts +2 -1
  44. package/dist/tools/list-names.d.ts.map +1 -1
  45. package/dist/tools/mcp.d.ts +10 -3
  46. package/dist/tools/mcp.d.ts.map +1 -1
  47. package/dist/tools/mount-download.d.ts.map +1 -1
  48. package/dist/tools/mount-upload.d.ts.map +1 -1
  49. package/dist/tools/mount-wait.d.ts.map +1 -1
  50. package/dist/tools/mount.d.ts +13 -0
  51. package/dist/tools/mount.d.ts.map +1 -1
  52. package/dist/tools/names.d.ts +34 -0
  53. package/dist/tools/names.d.ts.map +1 -1
  54. package/dist/tools/remote.d.ts.map +1 -1
  55. package/dist/tools/transports.d.ts.map +1 -1
  56. package/dist/tools.js +69 -49
  57. package/llms-full.txt +223 -12
  58. package/llms.txt +1 -1
  59. package/package.json +1 -1
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Multipart field encoding for the client — the platform-sensitive corner of
3
+ * `client.ts`, split out so the request-building logic there reads without it.
4
+ *
5
+ * Internal: none of this is public surface. The React Native descriptor path is
6
+ * the only genuinely subtle part, and keeping it together with its two guards
7
+ * makes that subtlety readable in one screen.
8
+ */
9
+ import type { MultipartFile } from '../contract';
10
+ /** A multipart file field — a `Blob` (web / Bun) or a platform descriptor (RN). */
11
+ export declare function isMultipartFile(value: unknown): value is MultipartFile;
12
+ /**
13
+ * Append the file part. `FormData.append` is typed `(name, value: string | Blob)`
14
+ * by the DOM lib, but on React Native attaching a `{ uri, name, type }`
15
+ * descriptor is the native way to send a file (RN streams it from disk). Route
16
+ * through a structural type whose `append` also accepts a `FileDescriptor` —
17
+ * method-parameter bivariance lets the real `FormData` satisfy it, so the
18
+ * descriptor path stays cast-free. Web / Bun still pass a `Blob`.
19
+ */
20
+ export declare function appendMultipartFile(form: FormData, field: string, file: MultipartFile): void;
21
+ export declare function appendFormFields(formData: FormData, values: Record<string, unknown>, skipKeys: Set<string>): void;
22
+ //# sourceMappingURL=client-multipart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-multipart.d.ts","sourceRoot":"","sources":["../../src/browser/client-multipart.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,aAAa,CAAC;AAqBjE,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAG5F;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GACpB,IAAI,CAKN"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAGX,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;AA+EhB,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC1D,OAAO,GACP;KAAG,CAAC,IAAI,CAAC,GAAG,MAAM;CAAE,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK;IAC5D,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC;IAClE,eAAe,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAE9B,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,cAAc,EAAE,YAAY,GAAG,WAAW,EAC1C,cAAc,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GACvC,gBAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAepC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,EAC1E,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;CAAE,CAKzF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAI/F,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;AAsFhB,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC1D,OAAO,GACP;KAAG,CAAC,IAAI,CAAC,GAAG,MAAM;CAAE,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK;IAC5D,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC;IAClE,eAAe,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAE9B,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,cAAc,EAAE,YAAY,GAAG,WAAW,EAC1C,cAAc,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GACvC,gBAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAepC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,EAC1E,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;CAAE,CAKzF"}
@@ -65,7 +65,13 @@ type ParamArrayValue = Array<string | number>;
65
65
  export interface RequestOptions {
66
66
  params?: Record<string, ParamValue | ParamArrayValue>;
67
67
  timeout?: number;
68
- responseType?: 'json' | 'blob';
68
+ /**
69
+ * How to read the body. `'response'` hands back the untouched `Response` —
70
+ * what a `raw` endpoint answers with, and strictly more than `'blob'`: the
71
+ * caller still gets `.blob()` / `.body`, plus the headers where
72
+ * `Content-Disposition` (the download filename) lives.
73
+ */
74
+ responseType?: 'json' | 'blob' | 'response';
69
75
  }
70
76
  /** The HTTP transport adapter `createClient` builds typed methods on. */
71
77
  export interface HttpClient {
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  emitResult,
5
5
  parseCliArgs,
6
6
  pollUntilDone
7
- } from "./index-h9d1fm0p.js";
7
+ } from "./index-4whcb3c3.js";
8
8
  import"./index-0ed3bx43.js";
9
- import"./index-4gawbm74.js";
9
+ import"./index-zza375qp.js";
10
10
  import"./index-c7nyw0yt.js";
11
11
  export {
12
12
  pollUntilDone,
@@ -93,6 +93,7 @@ export interface EndpointToolAnnotations {
93
93
  interface HttpOnlyEndpointDef extends EndpointDefBase {
94
94
  expose: readonly ['HTTP'];
95
95
  toolName?: never;
96
+ rawResponse?: never;
96
97
  }
97
98
  interface ToolEndpointDef extends EndpointDefBase {
98
99
  toolName?: string;
@@ -101,11 +102,70 @@ interface ToolEndpointDef extends EndpointDefBase {
101
102
  ui?: EndpointUiMeta;
102
103
  /** MCP behavioural hints (read-only / destructive / title) for hosts. */
103
104
  annotations?: EndpointToolAnnotations;
105
+ rawResponse?: never;
104
106
  }
105
- export type EndpointDef = HttpOnlyEndpointDef | ToolEndpointDef;
107
+ /**
108
+ * An endpoint whose handler returns the **`Response` itself** instead of data —
109
+ * a file download, a PDF, an SSE stream, a redirect. → ADR 0038.
110
+ *
111
+ * ```ts
112
+ * pdf: {
113
+ * method: 'GET', path: '/:id/pdf', desc: 'Download the offer as a PDF',
114
+ * params: z.object({ id: z.uuid() }),
115
+ * rawResponse: true, contentType: 'application/pdf',
116
+ * }
117
+ * ```
118
+ *
119
+ * Only the **response** is raw — hence the name, and the difference from
120
+ * `rawRoutes`, which sit outside the contract entirely. Here the request half is
121
+ * unchanged: `params` / `input` / `multipart` parse and validate exactly as
122
+ * elsewhere, and `beforeHandle` runs, so the auth gate applies with no guard in
123
+ * the handler. What is handed over is the response, so there is no `output` to
124
+ * validate, nothing to serialize into a tool result, and the endpoint is
125
+ * **HTTP-only**: never an MCP tool, an agent tool or a CLI command.
126
+ * `afterHandle` is skipped (it transforms data; there is none).
127
+ */
128
+ interface RawResponseEndpointDef extends EndpointDefBase {
129
+ /**
130
+ * Marks the response as raw. Must be the literal `true` — it is the
131
+ * discriminant of the union, so `rawResponse: false` is not a way to say
132
+ * "normal".
133
+ */
134
+ rawResponse: true;
135
+ /**
136
+ * The `Content-Type` this endpoint answers with, for documentation only —
137
+ * the handler still sets the real header (`serveFile` detects it from the
138
+ * path). Drives the OpenAPI response media type; without it the endpoint
139
+ * documents as `application/octet-stream`.
140
+ */
141
+ contentType?: string;
142
+ /** There is no output schema — the handler owns the whole response. */
143
+ output?: never;
144
+ /** Never a tool, so a tool name would be dead metadata. */
145
+ toolName?: never;
146
+ /** MCP-only decoration; a raw endpoint never reaches MCP. */
147
+ ui?: never;
148
+ /** MCP-only decoration; a raw endpoint never reaches MCP. */
149
+ annotations?: never;
150
+ /** Redundant but allowed, so `expose: ['HTTP']` survives a migration. */
151
+ expose?: readonly ['HTTP'];
152
+ }
153
+ export type EndpointDef = HttpOnlyEndpointDef | ToolEndpointDef | RawResponseEndpointDef;
106
154
  export interface ContractMeta<TScope extends string = string> {
107
155
  prefix: string;
108
156
  scope?: TScope;
157
+ /**
158
+ * Contract-wide default for every endpoint's opaque `meta` (→ ADR 0021).
159
+ * Endpoints **shallow-merge** over it, key by key — so a contract-wide
160
+ * `{ public: true }` survives an endpoint that adds `{ rateTier: 2 }`. One
161
+ * level only, no deep merge. An explicit `key: undefined` on the endpoint is
162
+ * the opt-out: it shadows the contract's value, so `meta?.key` readers see
163
+ * nothing — test values, not key membership. → ADR 0036.
164
+ *
165
+ * `expose` deliberately has no equivalent — see ADR 0036 for why, and pin
166
+ * `listToolNames` in a snapshot to catch an endpoint that forgot it.
167
+ */
168
+ meta?: Record<string, unknown>;
109
169
  }
110
170
  export interface ContractDef<T extends Record<string, EndpointDef> = Record<string, EndpointDef>, TScope extends string = string> {
111
171
  meta: ContractMeta<TScope>;
@@ -119,11 +179,21 @@ export interface ContractDef<T extends Record<string, EndpointDef> = Record<stri
119
179
  */
120
180
  export declare function defineContract<const T extends Record<string, EndpointDef>>(meta: {
121
181
  prefix: string;
182
+ meta?: Record<string, unknown>;
122
183
  }, endpoints: T): ContractDef<T, 'public'>;
123
184
  export declare function defineContract<TScope extends string, const T extends Record<string, EndpointDef>>(meta: {
124
185
  prefix: string;
125
186
  scope: TScope;
187
+ meta?: Record<string, unknown>;
126
188
  }, endpoints: T): ContractDef<T, TScope>;
189
+ /**
190
+ * Shallow-merge a contract-wide `meta` default with an endpoint's own — endpoint
191
+ * keys win. Returns `undefined` when neither side declares anything, because
192
+ * readers test `method.meta?.x` and an empty object would read as "declared".
193
+ * One level deep by design: a deep merge invites "how do I unset an inherited
194
+ * key", which has no answer without a sentinel. → ADR 0036.
195
+ */
196
+ export declare function mergeMeta(contractMeta: Record<string, unknown> | undefined, endpointMeta: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
127
197
  export interface RuntimeContext {
128
198
  params: unknown;
129
199
  input: unknown;
@@ -191,7 +261,14 @@ type MultipartArgs<E> = E extends {
191
261
  [P in K]: MultipartFile;
192
262
  } : unknown;
193
263
  type EndpointArgs<E> = InferInput<Prop<E, 'params'>> & InferInput<Prop<E, 'input'>> & MultipartArgs<E>;
194
- type EndpointOutput<E> = Prop<E, 'output'> extends ZodType<infer O> ? O : undefined;
264
+ /**
265
+ * What the typed client resolves to. A `raw` endpoint hands back the untouched
266
+ * `Response` — its body is bytes, and the headers carry what the caller needs
267
+ * (`Content-Disposition`, `Content-Range`, `ETag`). → ADR 0038.
268
+ */
269
+ type EndpointOutput<E> = E extends {
270
+ rawResponse: true;
271
+ } ? Response : Prop<E, 'output'> extends ZodType<infer O> ? O : undefined;
195
272
  export type EndpointFn<E> = [keyof EndpointArgs<E>] extends [never] ? () => Promise<EndpointOutput<E>> : (args: EndpointArgs<E>) => Promise<EndpointOutput<E>>;
196
273
  export type TypedClient<C extends Record<string, EndpointDef>> = {
197
274
  [K in keyof C]: EndpointFn<C[K]>;
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,eAAO,MAAM,cAAc,0CAA2C,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE/E,UAAU,eAAe;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;CAC3C;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,mBAAoB,SAAQ,eAAe;IACnD,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB;AAED,UAAU,eAAgB,SAAQ,eAAe;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,oEAAoE;IACpE,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAEhE,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW,CAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnE,MAAM,SAAS,MAAM,GAAG,MAAM;IAE9B,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACxE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACxB,SAAS,EAAE,CAAC,GACX,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC5B,wBAAgB,cAAc,CAC5B,MAAM,SAAS,MAAM,EACrB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,SAAS,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAmDjF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,eAAe,CAAC;IACxB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,MAAM,WAAW,cAAc,CAAC,OAAO,GAAG,SAAS,EAAE,MAAM,GAAG,SAAS;IACrE,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,eAAe,CAAC;IACxB;+DAC2D;IAC3D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AAYtE,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,cAAc,CAAC;AAElD,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAC,SAAS,MAAM,CAAA;CAAE,GACnE;KAAG,CAAC,IAAI,CAAC,GAAG,aAAa;CAAE,GAC3B,OAAO,CAAC;AAEZ,KAAK,YAAY,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,GAClD,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAC5B,aAAa,CAAC,CAAC,CAAC,CAAC;AAEnB,KAAK,cAAc,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAEpF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC/D,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAChC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI;KAC9D,CAAC,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACjC,CAAC;AAEF,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,MAAM,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GAC5D,MAAM,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAChC,IAAI,GACJ,KAAK,GACP,IAAI,CAAC;AAST,KAAK,QAAQ,CAAC,CAAC,EAAE,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAElD,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC/E,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAChC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,KAAK,IAAI;KAC1E,CAAC,IAAI,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;CAC5F,CAAC;AAIF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,gBAAgB,CACnF,CAAC,EACD,OAAO,CACR,CAAC"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,7 @@ import type { ContractDef, EndpointDef } from './define';
25
25
  export type ScopedDefineContract<TScope extends string> = <const T extends Record<string, EndpointDef>>(meta: {
26
26
  prefix: string;
27
27
  scope: TScope;
28
+ meta?: Record<string, unknown>;
28
29
  }, endpoints: T) => ContractDef<T, TScope>;
29
30
  /**
30
31
  * Build a `defineContract` that requires a `scope` from the application's own
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGzD,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACvC,SAAS,EAAE,CAAC,KACT,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,KAAK;IAC9D,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C,CAcA"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGzD,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACvE,SAAS,EAAE,CAAC,KACT,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,KAAK;IAC9D,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C,CAiBA"}
@@ -16,7 +16,7 @@ import {
16
16
  paginatedSchema,
17
17
  rateLimited,
18
18
  unauthorized
19
- } from "../index-x62gnfsk.js";
19
+ } from "../index-pmftwk2a.js";
20
20
  import"../index-809wc1tt.js";
21
21
  export {
22
22
  unauthorized,
@@ -7,7 +7,7 @@ import {
7
7
  isWithinDir,
8
8
  normalizeError,
9
9
  validateHandlerOutput
10
- } from "./index-4gawbm74.js";
10
+ } from "./index-zza375qp.js";
11
11
  import {
12
12
  isRecord,
13
13
  isUnsafeKey,
@@ -346,7 +346,7 @@ function toolResultFromError(err) {
346
346
  ...appErr.hint && { hint: appErr.hint }
347
347
  };
348
348
  }
349
- async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false) {
349
+ async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false, onOutputStrip) {
350
350
  const startedAt = Date.now();
351
351
  const finish = async (result) => {
352
352
  await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context, method);
@@ -410,7 +410,7 @@ async function executeToolMethod(method, toolName, rawArgs, context, hooks, life
410
410
  data = transformed;
411
411
  }
412
412
  if (method.outputSchema) {
413
- const checked = validateHandlerOutput(method.outputSchema, data);
413
+ const checked = validateHandlerOutput(method.outputSchema, data, onOutputStrip);
414
414
  if (!checked.ok) {
415
415
  return finish({
416
416
  ok: false,
@@ -437,6 +437,13 @@ var SINGULAR_EXCEPTIONS = new Set([
437
437
  "progress",
438
438
  "news"
439
439
  ]);
440
+ var TOOL_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
441
+ function normalizeService(value) {
442
+ return value.replace(/[^a-zA-Z0-9_]/g, "_");
443
+ }
444
+ function normalizeMethod(value) {
445
+ return value.replace(/[^a-zA-Z0-9_-]/g, "_");
446
+ }
440
447
  function singularize(name) {
441
448
  if (SINGULAR_EXCEPTIONS.has(name))
442
449
  return name;
@@ -446,22 +453,44 @@ function singularize(name) {
446
453
  return name.slice(0, -1);
447
454
  return name;
448
455
  }
456
+ function singularizeTail(name) {
457
+ const cut = name.lastIndexOf("_");
458
+ if (cut === -1)
459
+ return singularize(name);
460
+ return `${name.slice(0, cut + 1)}${singularize(name.slice(cut + 1))}`;
461
+ }
462
+ function hasUsableChars(value) {
463
+ return /[a-zA-Z0-9]/.test(value);
464
+ }
465
+ function assertToolName(name, serviceName, key) {
466
+ const where = `service "${serviceName}", method "${key}"`;
467
+ if (!TOOL_NAME_RE.test(name)) {
468
+ const why = name.length > 64 ? `is ${name.length} characters (max 64) — set an explicit \`toolName\`` : "must match [a-zA-Z0-9_-]";
469
+ throw new Error(`Tool name "${name}" (${where}) ${why}`);
470
+ }
471
+ }
449
472
  function toToolName(serviceName, methodName) {
450
- const normalized = serviceName.replace(/-/g, "_");
451
- const singular = singularize(normalized);
452
- if (methodName === "list")
473
+ const normalized = normalizeService(serviceName);
474
+ const singular = singularizeTail(normalized);
475
+ const method = normalizeMethod(methodName);
476
+ if (method === "list")
453
477
  return `list_${normalized}`;
454
- if (methodName === "get")
478
+ if (method === "get")
455
479
  return `get_${singular}`;
456
- if (methodName === "create")
480
+ if (method === "create")
457
481
  return `create_${singular}`;
458
- if (methodName === "update")
482
+ if (method === "update")
459
483
  return `update_${singular}`;
460
- if (methodName === "delete")
484
+ if (method === "delete")
461
485
  return `delete_${singular}`;
462
- const snake = methodName.replace(/([A-Z])/g, "_$1").toLowerCase();
486
+ const snake = method.replace(/([A-Z])/g, "_$1").toLowerCase();
463
487
  return `${snake}_${singular}`.replace(/^_/, "");
464
488
  }
489
+ function assertUniqueToolName(name, taken, surface) {
490
+ if (taken) {
491
+ throw new Error(`Duplicate ${surface} "${name}" across mounted services`);
492
+ }
493
+ }
465
494
 
466
495
  // src/tools/mount.ts
467
496
  function applyExtend(base, extra) {
@@ -475,7 +504,7 @@ function applyExtend(base, extra) {
475
504
  return z4.intersection(z4.object(extra), base);
476
505
  }
477
506
  function collectTools(service, transport, config = {}) {
478
- const { extend, flattenUnionInput = false } = config;
507
+ const { extend, flattenUnionInput = false, assertNames = true } = config;
479
508
  const tools = [];
480
509
  for (const [methodName, method] of Object.entries(service.methods)) {
481
510
  if (transport === "CLI") {
@@ -486,7 +515,15 @@ function collectTools(service, transport, config = {}) {
486
515
  }
487
516
  if (method.multipart)
488
517
  continue;
518
+ if (method.rawResponse)
519
+ continue;
489
520
  const name = method.toolName ?? toToolName(service.name, methodName);
521
+ if (assertNames && transport !== "CLI") {
522
+ if (!method.toolName && !hasUsableChars(service.name)) {
523
+ throw new Error(`Service prefix "${service.name}" (method "${methodName}") has no characters usable in a tool name — set an explicit \`toolName\` or rename the prefix`);
524
+ }
525
+ assertToolName(name, service.name, methodName);
526
+ }
490
527
  const baseSchema = flattenUnionInput ? mergeSchemas(method.paramsSchema ? flattenUnionsDeep(method.paramsSchema) : undefined, method.inputSchema ? flattenUnionsDeep(method.inputSchema) : undefined) : mergeSchemas(method.paramsSchema, method.inputSchema);
491
528
  const shouldExtend = !!extend && (!extend.filter || extend.filter(service, method));
492
529
  const schema = shouldExtend && extend ? applyExtend(baseSchema, extend.schema) : baseSchema;
@@ -502,7 +539,7 @@ function createToolRunner(config) {
502
539
  extraContext = await config.extend.resolve(rawArgs);
503
540
  }
504
541
  const cleanArgs = tool.shouldExtend && extendKeys ? Object.fromEntries(Object.entries(rawArgs).filter(([key]) => !extendKeys.has(key))) : rawArgs;
505
- return executeToolMethod(tool.method, tool.name, cleanArgs, { ...config.context, ...extraContext, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true);
542
+ return executeToolMethod(tool.method, tool.name, cleanArgs, { ...config.context, ...extraContext, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(tool.name, paths) : undefined);
506
543
  };
507
544
  }
508
545
  function formatToolError(result, toolName, errorHint) {
@@ -845,7 +882,6 @@ async function pollUntilDone(params) {
845
882
  }
846
883
 
847
884
  // src/tools/cli.ts
848
- import { mkdir, writeFile } from "node:fs/promises";
849
885
  import { basename, resolve } from "node:path";
850
886
  import process from "node:process";
851
887
 
@@ -962,6 +998,17 @@ async function readCapped(res, max) {
962
998
  return Buffer.concat(chunks);
963
999
  }
964
1000
 
1001
+ // src/internal/write-download.ts
1002
+ import { mkdir, writeFile } from "node:fs/promises";
1003
+ import { dirname } from "node:path";
1004
+ async function writeDownload(root, target, data) {
1005
+ if (!isWithinDir(root, target)) {
1006
+ throw new Error("download name escapes the output dir");
1007
+ }
1008
+ await mkdir(dirname(target), { recursive: true });
1009
+ await writeFile(target, data);
1010
+ }
1011
+
965
1012
  // src/tools/cli.ts
966
1013
  var GLOBAL_OPTIONS = [
967
1014
  ["--json", "Emit raw JSON on stdout (for piping / scripts)"],
@@ -1085,7 +1132,6 @@ function renderCommandHelp(name, command, tool) {
1085
1132
  var DEFAULT_DOWNLOAD_MAX_BYTES = 100 * 1024 * 1024;
1086
1133
  async function downloadResults(files, dir, stderr, quiet, allowPrivate, maxBytes) {
1087
1134
  const root = resolve(dir);
1088
- await mkdir(root, { recursive: true });
1089
1135
  for (const file of files) {
1090
1136
  try {
1091
1137
  const res = await fetchGuarded(new URL(file.url), allowPrivate);
@@ -1095,9 +1141,7 @@ async function downloadResults(files, dir, stderr, quiet, allowPrivate, maxBytes
1095
1141
  if (!buffer)
1096
1142
  throw new Error(`file exceeds the ${maxBytes}-byte cap`);
1097
1143
  const target = resolve(root, basename(file.name));
1098
- if (!isWithinDir(root, target))
1099
- throw new Error("download name escapes the output dir");
1100
- await writeFile(target, buffer);
1144
+ await writeDownload(root, target, buffer);
1101
1145
  if (!quiet)
1102
1146
  stderr(`saved ${target} (${(buffer.length / 1024).toFixed(0)}KB)
1103
1147
  `);
@@ -1119,9 +1163,7 @@ async function createCli(config) {
1119
1163
  const tools = new Map;
1120
1164
  for (const service of services) {
1121
1165
  for (const mountable of collectTools(service, "CLI")) {
1122
- if (tools.has(mountable.name)) {
1123
- throw new Error(`Duplicate CLI command "${mountable.name}" across mounted services`);
1124
- }
1166
+ assertUniqueToolName(mountable.name, tools.has(mountable.name), "CLI command");
1125
1167
  tools.set(mountable.name, mountable);
1126
1168
  }
1127
1169
  }
@@ -1216,4 +1258,4 @@ function safeInputSchema(tool) {
1216
1258
  }
1217
1259
  }
1218
1260
 
1219
- export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, flattenUnionsDeep, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
1261
+ export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, flattenUnionsDeep, assertToolName, assertUniqueToolName, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, writeDownload, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
@@ -3,7 +3,7 @@ import {
3
3
  bytesToBase64Url,
4
4
  forbidden,
5
5
  unauthorized
6
- } from "./index-4gawbm74.js";
6
+ } from "./index-zza375qp.js";
7
7
  import {
8
8
  isRecord,
9
9
  isUnsafeKey,
@@ -10,6 +10,8 @@ function defineContract(meta, endpoints) {
10
10
  if (ep.desc.trim() === "") {
11
11
  throw new Error(`Contract "${meta.prefix}": endpoint "${key}" has an empty desc`);
12
12
  }
13
+ if (ep.rawResponse)
14
+ assertRawEndpoint(meta.prefix, key, ep);
13
15
  if (!("toolName" in ep) || !ep.toolName)
14
16
  continue;
15
17
  const transports = new Set(ep.expose ? ep.expose.filter((t) => t !== "HTTP") : ["MCP", "AGENT"]);
@@ -30,6 +32,22 @@ function defineContract(meta, endpoints) {
30
32
  }
31
33
  return { meta, endpoints };
32
34
  }
35
+ function assertRawEndpoint(prefix, key, ep) {
36
+ const where = `Contract "${prefix}": raw endpoint "${key}"`;
37
+ if (ep.output)
38
+ throw new Error(`${where} cannot declare an output schema`);
39
+ if ("toolName" in ep && ep.toolName)
40
+ throw new Error(`${where} cannot set a toolName`);
41
+ if ("ui" in ep && ep.ui)
42
+ throw new Error(`${where} cannot set MCP ui metadata`);
43
+ if ("annotations" in ep && ep.annotations) {
44
+ throw new Error(`${where} cannot set MCP annotations`);
45
+ }
46
+ const nonHttp = (ep.expose ?? []).filter((t) => t !== "HTTP");
47
+ if (nonHttp.length > 0) {
48
+ throw new Error(`${where} is HTTP-only — remove ${nonHttp.join(", ")} from expose`);
49
+ }
50
+ }
33
51
  // src/contract/errors.ts
34
52
  var APP_ERROR_BRAND = Symbol.for("stitchkit.AppError");
35
53
 
@@ -116,7 +134,7 @@ function createContractFactory() {
116
134
  const validated = defineContract({ prefix: meta.prefix }, endpoints);
117
135
  return {
118
136
  endpoints: validated.endpoints,
119
- meta: { prefix: meta.prefix, scope: meta.scope }
137
+ meta: { ...meta, prefix: meta.prefix, scope: meta.scope }
120
138
  };
121
139
  }
122
140
  };
@@ -2,15 +2,16 @@ import {
2
2
  assertCorsConfig,
3
3
  corsHeaders,
4
4
  corsPreflightResponse
5
- } from "./index-tje0q6gp.js";
5
+ } from "./index-zfscdskj.js";
6
6
  import {
7
7
  AppError,
8
8
  badRequest,
9
9
  errorCode,
10
10
  isWithinDir,
11
+ mergeMeta,
11
12
  normalizeError,
12
13
  validateHandlerOutput
13
- } from "./index-4gawbm74.js";
14
+ } from "./index-zza375qp.js";
14
15
  import {
15
16
  extractIp,
16
17
  getClientInfo,
@@ -212,6 +213,26 @@ function validateRoutes(routeMap) {
212
213
  }
213
214
  }
214
215
  }
216
+ function findShadowedRoutes(routeMap, rawRoutes) {
217
+ if (!rawRoutes || rawRoutes.length === 0)
218
+ return [];
219
+ const shadowed = [];
220
+ for (const [httpMethod, entries] of routeMap) {
221
+ for (const entry of entries) {
222
+ const probe = `/${entry.segments.map((s) => s.startsWith(":") ? "__param__" : s).join("/")}`;
223
+ const match = matchRawRoute(rawRoutes, httpMethod, probe);
224
+ if (!match)
225
+ continue;
226
+ shadowed.push({
227
+ pattern: `${httpMethod} ${entry.pattern}`,
228
+ endpoint: `${entry.method.serviceName}.${entry.method.key}`,
229
+ rawRoute: `${match.route.method} ${match.route.path}`,
230
+ scope: entry.method.scope
231
+ });
232
+ }
233
+ }
234
+ return shadowed;
235
+ }
215
236
  function matchRawRoute(rawRoutes, httpMethod, pathname) {
216
237
  for (const route of rawRoutes) {
217
238
  if (route.method !== "ALL" && route.method !== httpMethod)
@@ -476,6 +497,14 @@ function createHandler(config) {
476
497
  const resolveId = config.traceId ?? resolveTraceId;
477
498
  const routeMap = buildRouteMap(normalizeGroups(config));
478
499
  validateRoutes(routeMap);
500
+ for (const shadow of findShadowedRoutes(routeMap, config.rawRoutes)) {
501
+ const gate = shadow.scope && shadow.scope !== "public" ? ` (scope "${shadow.scope}")` : "";
502
+ const line = `[stitchkit] raw route ${shadow.rawRoute} shadows contract route ${shadow.pattern}` + ` → ${shadow.endpoint}${gate} will never run, and its hooks never apply`;
503
+ if (customLogger)
504
+ customLogger.warn(line);
505
+ else
506
+ console.warn(line);
507
+ }
479
508
  async function dispatch(req, url, traceId, server, clientIp) {
480
509
  const shouldLogRequest = logging && shouldLog(url.pathname, req.method);
481
510
  const ipAddress = extractIp(req, clientIp) || undefined;
@@ -570,6 +599,14 @@ function createHandler(config) {
570
599
  await groupHooks.beforeHandle(ctx, method);
571
600
  }
572
601
  let result = await method.handler(ctx);
602
+ if (method.rawResponse) {
603
+ if (!(result instanceof Response)) {
604
+ throw new AppError("INTERNAL_SERVER_ERROR", `Raw endpoint ${method.serviceName}.${method.key} must return a Response`, 500);
605
+ }
606
+ const rawRes = applyCors(result, cors, req);
607
+ logDone(rawRes.status);
608
+ return rawRes;
609
+ }
573
610
  if (groupHooks?.afterHandle) {
574
611
  const transformed = await groupHooks.afterHandle(ctx, result, method);
575
612
  if (transformed !== undefined)
@@ -580,8 +617,17 @@ function createHandler(config) {
580
617
  if (transformed !== undefined)
581
618
  result = transformed;
582
619
  }
620
+ if (result instanceof Response) {
621
+ throw new AppError("INTERNAL_SERVER_ERROR", `${method.serviceName}.${method.key} produced a Response on the data path — only a \`rawResponse: true\` endpoint may return one (an afterHandle hook must return data)`, 500);
622
+ }
583
623
  if (method.outputSchema) {
584
- const checked = validateHandlerOutput(method.outputSchema, result);
624
+ const checked = validateHandlerOutput(method.outputSchema, result, config.warnOnOutputStrip ? (paths) => {
625
+ const line = `[stitchkit] output strip ${method.serviceName}.${method.key}: ${paths.join(", ")}`;
626
+ if (customLogger)
627
+ customLogger.warn(line);
628
+ else
629
+ console.warn(line);
630
+ } : undefined);
585
631
  if (!checked.ok) {
586
632
  throw new AppError("INTERNAL_SERVER_ERROR", checked.message, 500);
587
633
  }
@@ -656,20 +702,41 @@ function applyCors(res, cors, req) {
656
702
  const extra = corsHeaders2(cors, req);
657
703
  if (Object.keys(extra).length === 0)
658
704
  return res;
659
- const headers = new Headers(res.headers);
660
- for (const [key, value] of Object.entries(extra))
705
+ try {
706
+ for (const [key, value] of Object.entries(extra))
707
+ setCorsHeader(res.headers, key, value);
708
+ return res;
709
+ } catch {
710
+ const headers = new Headers(res.headers);
711
+ for (const [key, value] of Object.entries(extra))
712
+ setCorsHeader(headers, key, value);
713
+ return new Response(res.body, {
714
+ status: res.status,
715
+ statusText: res.statusText,
716
+ headers
717
+ });
718
+ }
719
+ }
720
+ function setCorsHeader(headers, key, value) {
721
+ if (key !== "Vary") {
661
722
  headers.set(key, value);
662
- return new Response(res.body, {
663
- status: res.status,
664
- statusText: res.statusText,
665
- headers
666
- });
723
+ return;
724
+ }
725
+ const existing = headers.get("Vary");
726
+ if (existing === null || existing.trim() === "") {
727
+ headers.set("Vary", value);
728
+ return;
729
+ }
730
+ const present = existing.split(",").some((field) => field.trim().toLowerCase() === "origin");
731
+ if (!present)
732
+ headers.set("Vary", `${existing}, ${value}`);
667
733
  }
668
734
  function json(data, status, cors, req) {
669
735
  return Response.json(data, { status, headers: corsHeaders2(cors, req) });
670
736
  }
671
737
 
672
738
  // src/server/implement.ts
739
+ var HTTP_ONLY = Object.freeze(["HTTP"]);
673
740
  function implement(contract, handlers) {
674
741
  const methods = {};
675
742
  const groupScope = contract.meta.scope ?? "public";
@@ -682,7 +749,7 @@ function implement(contract, handlers) {
682
749
  serviceName: contract.meta.prefix,
683
750
  key: String(key),
684
751
  toolName: "toolName" in endpoint ? endpoint.toolName : undefined,
685
- expose: endpoint.expose,
752
+ expose: endpoint.rawResponse ? HTTP_ONLY : endpoint.expose,
686
753
  scope: endpoint.scope ?? groupScope,
687
754
  paramsSchema: endpoint.params,
688
755
  inputSchema: endpoint.input,
@@ -692,7 +759,9 @@ function implement(contract, handlers) {
692
759
  idempotent: endpoint.idempotent,
693
760
  ui: "ui" in endpoint ? endpoint.ui : undefined,
694
761
  annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
695
- meta: endpoint.meta,
762
+ meta: mergeMeta(contract.meta.meta, endpoint.meta),
763
+ rawResponse: endpoint.rawResponse,
764
+ contentType: "contentType" in endpoint ? endpoint.contentType : undefined,
696
765
  handler: (ctx) => typedHandler(ctx)
697
766
  };
698
767
  }