stitchkit 0.8.1 → 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.
@@ -1 +1 @@
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;AAG/F,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;AA8ChB,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,EACV,WAAW,EACX,WAAW,EAGX,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;AA8ChB,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"}
@@ -29,7 +29,7 @@ import type { EventsMap } from '@socket.io/component-emitter';
29
29
  * public `on` / `emit` signatures.
30
30
  */
31
31
  export type SocketEventMap = EventsMap;
32
- export interface SocketIOClientConfig {
32
+ export interface SocketIOClientConfig<TServerEvents extends SocketEventMap = SocketEventMap> {
33
33
  /** Server origin, e.g. `https://api.example.com`. */
34
34
  url: string;
35
35
  /** Socket.IO endpoint path. Default `/socket.io/`. */
@@ -63,6 +63,15 @@ export interface SocketIOClientConfig {
63
63
  reconnectionDelayMax?: number;
64
64
  /** Connection timeout (ms). Default `20000`. */
65
65
  timeout?: number;
66
+ /**
67
+ * Server → client events to **retain** ("sticky events"). The client keeps the
68
+ * last payload of each listed event and replays it to any handler subscribed
69
+ * afterwards (and on the next subscribe after a re-render), so a late
70
+ * subscriber catches up to the current state at once instead of waiting for the
71
+ * next emission. The retained value survives a `disconnect()` / `connect()`
72
+ * cycle. Only the first emitted argument of an event is retained.
73
+ */
74
+ retain?: Array<keyof TServerEvents & string>;
66
75
  }
67
76
  export interface SocketIOClient<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap> {
68
77
  /** Create the socket (if absent) and connect. Idempotent. */
@@ -82,5 +91,5 @@ export interface SocketIOClient<TServerEvents extends SocketEventMap, TClientEve
82
91
  /** Subscribe to connection up/down changes. Returns an unsubscribe. */
83
92
  onConnectionChange(listener: (connected: boolean) => void): () => void;
84
93
  }
85
- export declare function createSocketIOClient<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap>(config: SocketIOClientConfig): SocketIOClient<TServerEvents, TClientEvents>;
94
+ export declare function createSocketIOClient<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap>(config: SocketIOClientConfig<TServerEvents>): SocketIOClient<TServerEvents, TClientEvents>;
86
95
  //# sourceMappingURL=socket-io.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AA0B9D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,IAAI,CAAC,EACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC5C,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc,CAC7B,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc;IAEpC,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAC;IAChB,+CAA+C;IAC/C,UAAU,IAAI,IAAI,CAAC;IACnB,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,aAAa,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAC5F,8DAA8D;IAC9D,IAAI,CAAC,CAAC,SAAS,MAAM,aAAa,GAAG,MAAM,EACzC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GACpC,IAAI,CAAC;IACR,uEAAuE;IACvE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACxE;AAED,wBAAgB,oBAAoB,CAClC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,MAAM,EAAE,oBAAoB,GAAG,cAAc,CAAC,aAAa,EAAE,aAAa,CAAC,CAuF5E"}
1
+ {"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AA2B9D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC,MAAM,WAAW,oBAAoB,CAAC,aAAa,SAAS,cAAc,GAAG,cAAc;IACzF,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,IAAI,CAAC,EACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC5C,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,cAAc,CAC7B,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc;IAEpC,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAC;IAChB,+CAA+C;IAC/C,UAAU,IAAI,IAAI,CAAC;IACnB,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,aAAa,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAC5F,8DAA8D;IAC9D,IAAI,CAAC,CAAC,SAAS,MAAM,aAAa,GAAG,MAAM,EACzC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GACpC,IAAI,CAAC;IACR,uEAAuE;IACvE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACxE;AAED,wBAAgB,oBAAoB,CAClC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,MAAM,EAAE,oBAAoB,CAAC,aAAa,CAAC,GAAG,cAAc,CAAC,aAAa,EAAE,aAAa,CAAC,CA8G3F"}
@@ -2,7 +2,14 @@ import type { ZodType, z } from 'zod';
2
2
  export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3
3
  export declare const ALL_TRANSPORTS: readonly ["HTTP", "MCP", "AGENT", "CLI"];
4
4
  export type Transport = (typeof ALL_TRANSPORTS)[number];
5
- export type TransportSource = 'http' | 'mcp' | 'agent' | 'cli';
5
+ /**
6
+ * The transport tag on `ctx.source`. The four built-ins keep autocomplete, but
7
+ * the union is **open** (`string & {}`) so a bring-your-own transport — e.g. a
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
+ */
12
+ export type TransportSource = 'http' | 'mcp' | 'agent' | 'cli' | (string & {});
6
13
  interface EndpointDefBase {
7
14
  method: HttpMethod;
8
15
  path: string;
@@ -25,6 +32,20 @@ interface EndpointDefBase {
25
32
  * property of the endpoint — declared once, the typed client applies it.
26
33
  */
27
34
  timeout?: number;
35
+ /**
36
+ * Whether calling this operation twice with the same input is safe (the
37
+ * second call yields the same result and no extra side effect) — a
38
+ * transport-neutral property of the operation, like HTTP `PUT`/`DELETE`.
39
+ *
40
+ * The core attaches **no** behaviour to it (it stays generic — ADR 0002): it
41
+ * rides through to `MethodDef.idempotent`, where a transport that can retry
42
+ * reads it. A reliable bring-your-own-transport lane (e.g. a raw-WebSocket
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
+ */
48
+ idempotent?: boolean;
28
49
  /**
29
50
  * Opaque, app-defined per-endpoint metadata. The core attaches **no** meaning
30
51
  * to it (like `scope`, it is a free escape-hatch — ADR 0002/0021): it rides
@@ -108,6 +129,17 @@ export interface RuntimeContext {
108
129
  input: unknown;
109
130
  file?: File;
110
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;
111
143
  traceId?: string;
112
144
  spanId?: string;
113
145
  ipAddress?: string;
@@ -119,6 +151,11 @@ export interface HandlerContext<TParams = undefined, TInput = undefined> {
119
151
  input: TInput;
120
152
  file?: File;
121
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;
122
159
  traceId?: string;
123
160
  spanId?: string;
124
161
  ipAddress?: string;
@@ -127,10 +164,31 @@ export interface HandlerContext<TParams = undefined, TInput = undefined> {
127
164
  }
128
165
  type Prop<T, K extends string> = K extends keyof T ? T[K] : undefined;
129
166
  type InferInput<S> = S extends ZodType ? z.input<S> : unknown;
167
+ /**
168
+ * A platform file descriptor accepted by the typed client's multipart methods
169
+ * where a file is not a `Blob`. React Native / Expo represent a file as
170
+ * `{ uri, name, type }` and their `FormData.append` streams it from disk by
171
+ * `uri`; reading it into a `Blob` first (`fetch(uri).blob()`) would load the
172
+ * whole media into memory. The web / Bun path still uses `Blob`.
173
+ */
174
+ export interface FileDescriptor {
175
+ /** Local file URI the platform streams from (e.g. `file:///…`). */
176
+ uri: string;
177
+ /** File name for the multipart part. */
178
+ name: string;
179
+ /** MIME type for the multipart part. */
180
+ type: string;
181
+ }
182
+ /**
183
+ * What a `multipart` endpoint's file field accepts on the typed client — a
184
+ * `Blob` (web / Bun) or a platform {@link FileDescriptor} (React Native / Expo).
185
+ * Exported so a consumer can type its own upload helpers without a cast.
186
+ */
187
+ export type MultipartFile = Blob | FileDescriptor;
130
188
  type MultipartArgs<E> = E extends {
131
189
  multipart: infer K extends string;
132
190
  } ? {
133
- [P in K]: Blob;
191
+ [P in K]: MultipartFile;
134
192
  } : unknown;
135
193
  type EndpointArgs<E> = InferInput<Prop<E, 'params'>> & InferInput<Prop<E, 'input'>> & MultipartArgs<E>;
136
194
  type EndpointOutput<E> = Prop<E, 'output'> extends ZodType<infer O> ? O : undefined;
@@ -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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"}
@@ -1,4 +1,4 @@
1
- export { ALL_TRANSPORTS, type ContractDef, type ContractMeta, defineContract, type EndpointDef, type EndpointFn, type EndpointToolAnnotations, type EndpointUiMeta, type HandlerContext, type HttpMethod, type RuntimeContext, type ScopedEndpointFn, type ScopedHttpClient, type Transport, type TransportSource, type TypedClient, type TypedHttpClient, } from './define';
1
+ export { ALL_TRANSPORTS, type ContractDef, type ContractMeta, defineContract, type EndpointDef, type EndpointFn, type EndpointToolAnnotations, type EndpointUiMeta, type FileDescriptor, type HandlerContext, type HttpMethod, type MultipartFile, type RuntimeContext, type ScopedEndpointFn, type ScopedHttpClient, type Transport, type TransportSource, type TypedClient, type TypedHttpClient, } from './define';
2
2
  export { AppError, appError, badRequest, conflict, type ErrorEnvelope, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from './errors';
3
3
  export { decodeCursor, encodeCursor, type Paginated, paginatedSchema, } from './pagination';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,KAAK,SAAS,EACd,eAAe,GAChB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,KAAK,SAAS,EACd,eAAe,GAChB,MAAM,cAAc,CAAC"}
@@ -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
  }
@@ -729,6 +728,7 @@ function implement(contract, handlers) {
729
728
  outputSchema: endpoint.output,
730
729
  multipart: endpoint.multipart,
731
730
  maxUploadBytes: endpoint.maxUploadBytes,
731
+ idempotent: endpoint.idempotent,
732
732
  ui: "ui" in endpoint ? endpoint.ui : undefined,
733
733
  annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
734
734
  meta: endpoint.meta,
package/dist/index.d.ts CHANGED
@@ -4,4 +4,5 @@ export type { SocketEventMap, SocketIOClient, SocketIOClientConfig, } from './br
4
4
  export { createSocketIOClient } from './browser/socket-io';
5
5
  export { type ParseSSEOptions, parseSSE } from './browser/stream';
6
6
  export * from './contract';
7
+ export { createRetainedTopics, type RetainedTopics } from './retained';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,YAAY,EACZ,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClE,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,YAAY,EACZ,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClE,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -263,11 +263,11 @@ function createHttpMethod(endpoint, prefix, client, config) {
263
263
  url = url.slice(0, -1);
264
264
  if (endpoint.multipart) {
265
265
  const file = firstArg[endpoint.multipart];
266
- if (!(file instanceof Blob)) {
266
+ if (!isMultipartFile(file)) {
267
267
  throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
268
268
  }
269
269
  const formData = new FormData;
270
- formData.append(endpoint.multipart, file);
270
+ appendMultipartFile(formData, endpoint.multipart, file);
271
271
  appendFormFields(formData, firstArg, new Set([...prefixKeys, endpoint.multipart]));
272
272
  return client.post(url, formData, withTimeout(undefined, endpoint.timeout));
273
273
  }
@@ -324,11 +324,11 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
324
324
  headers["Content-Type"] = "application/json";
325
325
  if (endpoint.multipart && args) {
326
326
  const file = args[endpoint.multipart];
327
- if (!(file instanceof Blob)) {
327
+ if (!isMultipartFile(file)) {
328
328
  throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
329
329
  }
330
330
  const formData = new FormData;
331
- formData.append(endpoint.multipart, file);
331
+ appendMultipartFile(formData, endpoint.multipart, file);
332
332
  appendFormFields(formData, stripParams(args, endpoint.path, prefixKeys), new Set([endpoint.multipart]));
333
333
  const res2 = await fetch(url, {
334
334
  method: endpoint.method,
@@ -361,6 +361,16 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
361
361
  return endpoint.output ? endpoint.output.parse(json) : json;
362
362
  };
363
363
  }
364
+ function isFileDescriptor(value) {
365
+ return typeof value === "object" && value !== null && !(value instanceof Blob) && "uri" in value && typeof value.uri === "string" && "name" in value && typeof value.name === "string" && "type" in value && typeof value.type === "string";
366
+ }
367
+ function isMultipartFile(value) {
368
+ return value instanceof Blob || isFileDescriptor(value);
369
+ }
370
+ function appendMultipartFile(form, field, file) {
371
+ const sink = form;
372
+ sink.append(field, file);
373
+ }
364
374
  function appendFormFields(formData, values, skipKeys) {
365
375
  for (const [key, value] of Object.entries(values)) {
366
376
  if (skipKeys.has(key) || value === undefined || value === null)
@@ -409,6 +419,34 @@ function stripParams(args, path, extra) {
409
419
  }
410
420
  // src/browser/socket-io.ts
411
421
  import { io } from "socket.io-client";
422
+
423
+ // src/retained.ts
424
+ function createRetainedTopics() {
425
+ const last = {};
426
+ return {
427
+ record(topic, payload) {
428
+ last[topic] = payload;
429
+ },
430
+ replay(topic, handler) {
431
+ const value = last[topic];
432
+ if (value !== undefined)
433
+ handler(value);
434
+ },
435
+ get(topic) {
436
+ return last[topic];
437
+ },
438
+ clear(topic) {
439
+ if (topic !== undefined) {
440
+ delete last[topic];
441
+ return;
442
+ }
443
+ for (const key of Object.keys(last))
444
+ Reflect.deleteProperty(last, key);
445
+ }
446
+ };
447
+ }
448
+
449
+ // src/browser/socket-io.ts
412
450
  function toIoAuth(auth) {
413
451
  if (typeof auth !== "function")
414
452
  return auth;
@@ -420,6 +458,9 @@ function createSocketIOClient(config) {
420
458
  let socket = null;
421
459
  const connectionListeners = new Set;
422
460
  const subscriptions = new Set;
461
+ const retainNames = config.retain ? config.retain.map(String) : [];
462
+ const retainSet = new Set(retainNames);
463
+ const retained = retainNames.length > 0 ? createRetainedTopics() : null;
423
464
  function notifyConnection(connected) {
424
465
  for (const listener of connectionListeners)
425
466
  listener(connected);
@@ -447,6 +488,11 @@ function createSocketIOClient(config) {
447
488
  });
448
489
  socket.on("connect", () => notifyConnection(true));
449
490
  socket.on("disconnect", () => notifyConnection(false));
491
+ if (retained) {
492
+ for (const name of retainNames) {
493
+ socket.on(name, (payload) => retained.record(name, payload));
494
+ }
495
+ }
450
496
  for (const attach of subscriptions)
451
497
  attach(socket);
452
498
  socket.connect();
@@ -469,6 +515,10 @@ function createSocketIOClient(config) {
469
515
  subscriptions.add(attach);
470
516
  if (socket)
471
517
  attach(socket);
518
+ if (retained && retainSet.has(name)) {
519
+ const fn = handler;
520
+ retained.replay(name, (payload) => fn(payload));
521
+ }
472
522
  return () => {
473
523
  subscriptions.delete(attach);
474
524
  socket?.off(name, handler);
@@ -535,6 +585,7 @@ export {
535
585
  defineContract,
536
586
  decodeCursor,
537
587
  createSocketIOClient,
588
+ createRetainedTopics,
538
589
  createHttpClient,
539
590
  createClients,
540
591
  createClient,
package/dist/node.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createImplement,
4
4
  createSocketIOServer,
5
5
  implement
6
- } from "./index-svvpy5bz.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,
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Retained-last-value memory for pub/sub topics — "sticky events".
3
+ *
4
+ * A subscriber that connects (or a component that mounts / re-renders) *after* an
5
+ * event was published would otherwise miss it and show stale state until the next
6
+ * publish. Record each topic's last payload and replay it to a fresh subscriber,
7
+ * so a late one catches up at once — the pub/sub analogue of MQTT's "retained"
8
+ * message or an RxJS `BehaviorSubject`.
9
+ *
10
+ * Transport-agnostic: wrap it around any pub/sub. `createSocketIOClient`'s
11
+ * `retain` option uses it internally, and a bring-your-own-transport lane (a raw
12
+ * WebSocket driving a contract through the app's own dispatch loop) can use it
13
+ * directly for its own event channel. Browser-safe — no Node built-ins.
14
+ */
15
+ export interface RetainedTopics<Events extends Record<string, unknown>> {
16
+ /** Record a topic's latest payload — call on every publish / receive. */
17
+ record<K extends keyof Events & string>(topic: K, payload: Events[K]): void;
18
+ /** Replay the retained payload, if any, to a just-subscribed handler. */
19
+ replay<K extends keyof Events & string>(topic: K, handler: (payload: Events[K]) => void): void;
20
+ /** The retained payload for a topic, or `undefined` if none recorded yet. */
21
+ get<K extends keyof Events & string>(topic: K): Events[K] | undefined;
22
+ /** Forget a topic's retained value, or every topic when `topic` is omitted. */
23
+ clear(topic?: keyof Events & string): void;
24
+ }
25
+ /**
26
+ * Create a {@link RetainedTopics} store. `Events` maps each topic name to its
27
+ * payload type, so `record` / `replay` / `get` are typed per topic.
28
+ */
29
+ export declare function createRetainedTopics<Events extends Record<string, unknown>>(): RetainedTopics<Events>;
30
+ //# sourceMappingURL=retained.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retained.d.ts","sourceRoot":"","sources":["../src/retained.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpE,yEAAyE;IACzE,MAAM,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5E,yEAAyE;IACzE,MAAM,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EACpC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,GACpC,IAAI,CAAC;IACR,6EAA6E;IAC7E,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACtE,+EAA+E;IAC/E,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,cAAc,CAAC,MAAM,CAAC,CAqB1B"}
@@ -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"}
@@ -1 +1 @@
1
- {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CA6C3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,MACjD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,UAAU,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,UAAU,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,KAC1B,UAAU,CACd"}
1
+ {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CA+C3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,MACjD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,UAAU,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,UAAU,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,KAC1B,UAAU,CACd"}
@@ -12,7 +12,7 @@ import {
12
12
  socketIoLane,
13
13
  staticRoute,
14
14
  webSocketLane
15
- } from "../index-svvpy5bz.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"}
@@ -37,6 +37,13 @@ export interface MethodDef<TParams = unknown, TInput = unknown, TOutput = unknow
37
37
  /** Per-route upload ceiling (bytes) for a multipart endpoint — overrides the
38
38
  * server `maxUploadBytes` default; from `EndpointDef.maxUploadBytes`. */
39
39
  maxUploadBytes?: number;
40
+ /**
41
+ * Whether the operation is safe to call twice with the same input — from
42
+ * `EndpointDef.idempotent`. The core attaches no behaviour; a retrying
43
+ * transport reads it to decide whether to replay a call after a reconnect.
44
+ * → ADR 0027.
45
+ */
46
+ idempotent?: boolean;
40
47
  /** MCP Apps widget metadata — carried onto the MCP tool's `_meta.ui`. */
41
48
  ui?: EndpointUiMeta;
42
49
  /** MCP behavioural hints — carried onto the MCP tool's `annotations`. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/tools/remote.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAc7D,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CACd,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnE,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,UAAU,CAmEZ"}
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/tools/remote.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAc7D,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CACd,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnE,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,UAAU,CAqEZ"}
package/dist/tools.js CHANGED
@@ -923,11 +923,11 @@ function createHttpMethod(endpoint, prefix, client, config) {
923
923
  url = url.slice(0, -1);
924
924
  if (endpoint.multipart) {
925
925
  const file = firstArg[endpoint.multipart];
926
- if (!(file instanceof Blob)) {
926
+ if (!isMultipartFile(file)) {
927
927
  throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
928
928
  }
929
929
  const formData = new FormData;
930
- formData.append(endpoint.multipart, file);
930
+ appendMultipartFile(formData, endpoint.multipart, file);
931
931
  appendFormFields(formData, firstArg, new Set([...prefixKeys, endpoint.multipart]));
932
932
  return client.post(url, formData, withTimeout(undefined, endpoint.timeout));
933
933
  }
@@ -984,11 +984,11 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
984
984
  headers["Content-Type"] = "application/json";
985
985
  if (endpoint.multipart && args) {
986
986
  const file = args[endpoint.multipart];
987
- if (!(file instanceof Blob)) {
987
+ if (!isMultipartFile(file)) {
988
988
  throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
989
989
  }
990
990
  const formData = new FormData;
991
- formData.append(endpoint.multipart, file);
991
+ appendMultipartFile(formData, endpoint.multipart, file);
992
992
  appendFormFields(formData, stripParams(args, endpoint.path, prefixKeys), new Set([endpoint.multipart]));
993
993
  const res2 = await fetch(url, {
994
994
  method: endpoint.method,
@@ -1021,6 +1021,16 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
1021
1021
  return endpoint.output ? endpoint.output.parse(json2) : json2;
1022
1022
  };
1023
1023
  }
1024
+ function isFileDescriptor(value) {
1025
+ return typeof value === "object" && value !== null && !(value instanceof Blob) && "uri" in value && typeof value.uri === "string" && "name" in value && typeof value.name === "string" && "type" in value && typeof value.type === "string";
1026
+ }
1027
+ function isMultipartFile(value) {
1028
+ return value instanceof Blob || isFileDescriptor(value);
1029
+ }
1030
+ function appendMultipartFile(form, field, file) {
1031
+ const sink = form;
1032
+ sink.append(field, file);
1033
+ }
1024
1034
  function appendFormFields(formData, values, skipKeys) {
1025
1035
  for (const [key, value] of Object.entries(values)) {
1026
1036
  if (skipKeys.has(key) || value === undefined || value === null)
@@ -1097,6 +1107,7 @@ function implementRemote(contract, http, options) {
1097
1107
  inputSchema: endpoint.input,
1098
1108
  outputSchema: endpoint.output,
1099
1109
  multipart: endpoint.multipart,
1110
+ idempotent: endpoint.idempotent,
1100
1111
  handler: async (ctx) => {
1101
1112
  const call = client[key];
1102
1113
  if (!call) {
package/llms-full.txt CHANGED
@@ -236,6 +236,7 @@ export const users = defineContract({ prefix: 'users' }, {
236
236
  | `toolName` | no | explicit MCP / agent tool name (defaults to `prefix_key`) |
237
237
  | `multipart` | no | field name of a file upload — see [below](#file-uploads) |
238
238
  | `timeout` | no | per-endpoint client timeout in ms, for slow endpoints |
239
+ | `idempotent` | no | safe to call twice with the same input (like `PUT`/`DELETE`); a retrying transport reads it — see [Realtime](./realtime.md#bring-your-own-transport) |
239
240
  | `meta` | no | opaque app metadata — read in hooks / on tool mounts, never in OpenAPI ([below](#endpoint-metadata-meta)) |
240
241
 
241
242
  ## `params` vs `input` vs `output`
@@ -861,7 +862,10 @@ contract:
861
862
  - for `GET` / `DELETE`, the remaining fields become the **query string**
862
863
  (arrays become repeated keys),
863
864
  - for `POST` / `PUT` / `PATCH`, they become the **JSON body**,
864
- - a `multipart` field must be a `Blob` and is sent as `form-data`.
865
+ - a `multipart` field is a `Blob` (web / Bun) or a platform `FileDescriptor`
866
+ (`{ uri, name, type }`, for React Native / Expo) and is sent as `form-data`.
867
+ The exported `MultipartFile` / `FileDescriptor` types let you annotate your own
868
+ upload helpers.
865
869
 
866
870
  ### Many contracts at once
867
871
 
@@ -1668,7 +1672,41 @@ subscribe once; reconnection is the wrapper's problem, not yours.
1668
1672
 
1669
1673
  `SocketIOClientConfig` takes `url`, `path`, `withCredentials` (cookies on the
1670
1674
  handshake — default `true`), `auth`, `query`, `extraHeaders`, `transports`,
1671
- `reconnectionAttempts` and `reconnectionDelay`.
1675
+ `reconnectionAttempts`, `reconnectionDelay` and `retain` (below).
1676
+
1677
+ ### Sticky events
1678
+
1679
+ A handler that subscribes **after** an event was emitted misses it — the UI stays
1680
+ on stale state until the next emission. List those events in **`retain`** and the
1681
+ client keeps each one's last payload and replays it to a handler the moment it
1682
+ subscribes (and on the next subscribe after a re-render). It is the pub/sub
1683
+ analogue of an MQTT *retained* message or an RxJS `BehaviorSubject`.
1684
+
1685
+ ```ts
1686
+ const client = createSocketIOClient<ServerEvents, ClientEvents>({
1687
+ url,
1688
+ retain: ['presence:changed', 'job:state'], // events to keep the last value of
1689
+ })
1690
+ client.connect()
1691
+
1692
+ // Later — even after the event already fired — this handler fires at once with
1693
+ // the last value, then on every future change:
1694
+ client.on('job:state', (s) => render(s))
1695
+ ```
1696
+
1697
+ The retained value survives a `disconnect()` / `connect()` cycle (the store lives
1698
+ outside the socket). Only an event's **first** argument is retained.
1699
+
1700
+ For a pub/sub channel that is **not** Socket.IO (your own transport — see
1701
+ [below](#bring-your-own-transport)), use the same memory directly:
1702
+
1703
+ ```ts
1704
+ import { createRetainedTopics } from 'stitchkit'
1705
+
1706
+ const topics = createRetainedTopics<{ 'job:state': JobState }>()
1707
+ topics.record('job:state', state) // on every publish
1708
+ topics.replay('job:state', (s) => render(s)) // for a late subscriber
1709
+ ```
1672
1710
 
1673
1711
  ### Handshake auth — cookie or token
1674
1712
 
@@ -1834,6 +1872,53 @@ Notes:
1834
1872
  - For high throughput, handle backpressure in the raw lane: `ws.send()` returns
1835
1873
  `-1` under pressure; resume on the `drain` callback.
1836
1874
 
1875
+ ## Bring-your-own transport
1876
+
1877
+ Sometimes the transport is neither HTTP nor Socket.IO — a desktop app whose UI
1878
+ webview talks to its own local Bun sidecar over a raw WebSocket, an IPC channel,
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.
1886
+
1887
+ Two pieces of the contract carry straight over to a bring-your-own lane:
1888
+
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.
1893
+
1894
+ ### Durability — `idempotent` + replay
1895
+
1896
+ If the sidecar can restart mid-call, the client decides what to do with an
1897
+ in-flight request on reconnect from the operation's **idempotency**, declared on
1898
+ the contract:
1899
+
1900
+ ```ts
1901
+ export const runtimeContract = defineContract({ prefix: 'runtime' }, {
1902
+ 'tasks.setDone': { method: 'POST', path: '/done', desc: '…',
1903
+ idempotent: true, input: taskDone, output: ok }, // re-send after reconnect — same result
1904
+ 'capture.start': { method: 'POST', path: '/start', desc: '…',
1905
+ output: snapshot }, // unset → one-shot, do not re-send
1906
+ })
1907
+ ```
1908
+
1909
+ `idempotent` rides through to `MethodDef.idempotent`; the core attaches no
1910
+ behaviour. Your reconnect logic reads it: replay an idempotent call (the
1911
+ durability guarantee — the user's action is not lost), reject a non-idempotent
1912
+ one rather than fire a second side effect. Pair it with
1913
+ [sticky events](#sticky-events) (`createRetainedTopics`) so a reconnected client
1914
+ also catches up on the latest pushed state.
1915
+
1916
+ This is deliberately *not* a reliable-RPC engine — that would be a competing
1917
+ WebSocket transport ([ADR 0008](../decisions/0008-thin-wrappers.md)). stitchkit
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).
1921
+
1837
1922
 
1838
1923
  ==============================================================================
1839
1924
  # Guide: Auth & errors (docs/guide/auth-and-errors.md)
@@ -2718,10 +2803,12 @@ The browser-and-server entrypoint. Re-exports everything from
2718
2803
  | Export | Kind | Summary |
2719
2804
  |--------|------|---------|
2720
2805
  | `createSocketIOClient` | function | the typed Socket.IO client — [guide](../guide/realtime.md#client--createsocketioclient) |
2806
+ | `createRetainedTopics` | function | retained last-value store for sticky events — [guide](../guide/realtime.md#sticky-events) |
2721
2807
  | `parseSSE` | function | parse an SSE `Response` into an async generator — [guide](../guide/client.md#sse) |
2722
2808
  | `SocketIOClient` | _type_ | the client handle |
2723
- | `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` |
2809
+ | `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` (incl. `retain`) |
2724
2810
  | `SocketEventMap` | _type_ | the shape of an event map |
2811
+ | `RetainedTopics` | _type_ | the `createRetainedTopics` handle |
2725
2812
  | `ParseSSEOptions` | _type_ | options for `parseSSE` |
2726
2813
 
2727
2814
  ---
@@ -2750,6 +2837,8 @@ from the root `stitchkit`.
2750
2837
  | `TypedHttpClient` | _type_ | the typed client, HTTP endpoints only (`= ScopedHttpClient<C, unknown>`) |
2751
2838
  | `ScopedHttpClient` | _type_ | a client whose `stripPrefixKeys` become required args ([guide](../guide/multi-tenant.md)) |
2752
2839
  | `ScopedEndpointFn` | _type_ | one method's signature with the consumed keys folded in |
2840
+ | `MultipartFile` | _type_ | a `multipart` file field — `Blob \| FileDescriptor` |
2841
+ | `FileDescriptor` | _type_ | a React Native / Expo file — `{ uri, name, type }` |
2753
2842
 
2754
2843
  ### Errors
2755
2844
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.8.1",
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",