stitchkit 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/socket-io.d.ts +11 -2
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/contract/define.d.ts +44 -2
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/{index-f39j6twc.js → index-13psnhhe.js} +1 -1
- package/dist/{index-svvpy5bz.js → index-zshrc6kx.js} +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -4
- package/dist/node.js +1 -1
- package/dist/retained.d.ts +30 -0
- package/dist/retained.d.ts.map +1 -0
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/types.d.ts +7 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/dispatch.d.ts +65 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +42 -5
- package/llms-full.txt +111 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
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;
|
|
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"}
|
package/dist/cli.js
CHANGED
|
@@ -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
|
-
|
|
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 driving a contract through `createContractDispatcher` — can
|
|
9
|
+
* tag its own calls (`source: 'local-ws'`). `source` is transport-only and
|
|
10
|
+
* carries no framework behaviour (→ ADR 0002 / ADR 0027).
|
|
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 over `createContractDispatcher`) replays an `idempotent` call after a
|
|
44
|
+
* reconnect — that is the durability guarantee — while a non-idempotent one is
|
|
45
|
+
* rejected rather than re-sent (a duplicate would be a second side effect).
|
|
46
|
+
* Unset means "unknown" — a careful transport treats it as non-idempotent.
|
|
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
|
|
@@ -127,10 +148,31 @@ export interface HandlerContext<TParams = undefined, TInput = undefined> {
|
|
|
127
148
|
}
|
|
128
149
|
type Prop<T, K extends string> = K extends keyof T ? T[K] : undefined;
|
|
129
150
|
type InferInput<S> = S extends ZodType ? z.input<S> : unknown;
|
|
151
|
+
/**
|
|
152
|
+
* A platform file descriptor accepted by the typed client's multipart methods
|
|
153
|
+
* where a file is not a `Blob`. React Native / Expo represent a file as
|
|
154
|
+
* `{ uri, name, type }` and their `FormData.append` streams it from disk by
|
|
155
|
+
* `uri`; reading it into a `Blob` first (`fetch(uri).blob()`) would load the
|
|
156
|
+
* whole media into memory. The web / Bun path still uses `Blob`.
|
|
157
|
+
*/
|
|
158
|
+
export interface FileDescriptor {
|
|
159
|
+
/** Local file URI the platform streams from (e.g. `file:///…`). */
|
|
160
|
+
uri: string;
|
|
161
|
+
/** File name for the multipart part. */
|
|
162
|
+
name: string;
|
|
163
|
+
/** MIME type for the multipart part. */
|
|
164
|
+
type: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* What a `multipart` endpoint's file field accepts on the typed client — a
|
|
168
|
+
* `Blob` (web / Bun) or a platform {@link FileDescriptor} (React Native / Expo).
|
|
169
|
+
* Exported so a consumer can type its own upload helpers without a cast.
|
|
170
|
+
*/
|
|
171
|
+
export type MultipartFile = Blob | FileDescriptor;
|
|
130
172
|
type MultipartArgs<E> = E extends {
|
|
131
173
|
multipart: infer K extends string;
|
|
132
174
|
} ? {
|
|
133
|
-
[P in K]:
|
|
175
|
+
[P in K]: MultipartFile;
|
|
134
176
|
} : unknown;
|
|
135
177
|
type EndpointArgs<E> = InferInput<Prop<E, 'params'>> & InferInput<Prop<E, 'input'>> & MultipartArgs<E>;
|
|
136
178
|
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":"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,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,CAAC;AAE/
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
|
package/dist/contract/index.d.ts
CHANGED
|
@@ -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"}
|
|
@@ -1000,4 +1000,4 @@ function safeInputSchema(tool) {
|
|
|
1000
1000
|
}
|
|
1001
1001
|
}
|
|
1002
1002
|
|
|
1003
|
-
export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
|
|
1003
|
+
export { coerceJsonArgs, toolResultFromError, executeToolMethod, flattenDiscriminatedUnion, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
|
|
@@ -729,6 +729,7 @@ function implement(contract, handlers) {
|
|
|
729
729
|
outputSchema: endpoint.output,
|
|
730
730
|
multipart: endpoint.multipart,
|
|
731
731
|
maxUploadBytes: endpoint.maxUploadBytes,
|
|
732
|
+
idempotent: endpoint.idempotent,
|
|
732
733
|
ui: "ui" in endpoint ? endpoint.ui : undefined,
|
|
733
734
|
annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
|
|
734
735
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
@@ -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 `createContractDispatcher`) 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"}
|
|
@@ -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,
|
|
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"}
|
package/dist/server/index.js
CHANGED
package/dist/server/types.d.ts
CHANGED
|
@@ -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":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,EACV,WAAW,EACX,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,UAAU,EACV,cAAc,EACd,SAAS,EACV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AACtE,KAAK,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AACjF,KAAK,UAAU,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAC/E,KAAK,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE7E,MAAM,MAAM,QAAQ,CAClB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,IAC1C;KACD,CAAC,IAAI,MAAM,CAAC,GAAG,CACd,GAAG,EAAE,IAAI,GAAG;QAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,KAC/D,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,OAAO,GACrC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAC9C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,SAAS,CAAC,OAAO,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAC/E,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8EAC0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC9D;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,WAAW,CAAC,EAAE,CACZ,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,KAChB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,CACR,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,SAAS,KACjB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;AAErD,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC;IAC3B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,eAAe,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1D;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAID,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,oBAAoB,GAAG,eAAe,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AACxF,KAAK,SAAS,GAAG,eAAe,SAAS;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAC1E,KAAK,qBAAqB,GAAG,eAAe,SAAS;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,eAAe,EACf,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAChF,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,GAAG;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive a contract over a **bring-your-own transport**.
|
|
3
|
+
*
|
|
4
|
+
* The HTTP server, the MCP mount and the agent mount all run a contract method
|
|
5
|
+
* the same way: slice the flat args, validate `params` / `input` against the Zod
|
|
6
|
+
* schemas, run the handler, validate the output, and return a typed result
|
|
7
|
+
* envelope. `createContractDispatcher` exposes exactly that core for a transport
|
|
8
|
+
* stitchkit does not own — a raw WebSocket lane (webview ↔ a local sidecar), an
|
|
9
|
+
* IPC channel, a queue worker. The transport owns the wire (framing, handshake,
|
|
10
|
+
* reconnect); the dispatcher owns "given a method name and args, run it safely."
|
|
11
|
+
*
|
|
12
|
+
* This is the same execution path as `mountMcp` / `mountAgent` (it shares
|
|
13
|
+
* `executeToolMethod`), so a bespoke transport gets identical validation and the
|
|
14
|
+
* identical `{ ok, code, details, hint }` error envelope for free, instead of a
|
|
15
|
+
* hand-rolled method registry. → ADR 0027. Upholds ADR 0008 (no competing
|
|
16
|
+
* engine — the transport is the app's) and ADR 0002 (the core stays generic —
|
|
17
|
+
* `source` is a free tag, `idempotent` carries no built-in behaviour).
|
|
18
|
+
*/
|
|
19
|
+
import { type TransportSource } from '../contract';
|
|
20
|
+
import type { ServiceDef } from '../server/types';
|
|
21
|
+
import { type ToolCallHooks, type ToolLifecycle, type ToolResult } from './execute';
|
|
22
|
+
export interface ContractDispatcherConfig {
|
|
23
|
+
/** Transport tag written to every call's `ctx.source` — e.g. `'local-ws'`. */
|
|
24
|
+
source: TransportSource;
|
|
25
|
+
/** Static context merged into every call (overridden by per-call context). */
|
|
26
|
+
context?: Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Observability hooks — the same `beforeToolCall` / `afterToolCall` the MCP and
|
|
29
|
+
* agent mounts fire, so a bespoke transport audits calls the same way.
|
|
30
|
+
*/
|
|
31
|
+
hooks?: ToolCallHooks;
|
|
32
|
+
/**
|
|
33
|
+
* Auth / scope gate and result transform run for every call — pass a
|
|
34
|
+
* `createAuthHook` result as `beforeHandle` to scope-guard the transport like
|
|
35
|
+
* an HTTP route.
|
|
36
|
+
*/
|
|
37
|
+
lifecycle?: ToolLifecycle;
|
|
38
|
+
/**
|
|
39
|
+
* Coerce JSON-stringified array / object arguments before validation. Off by
|
|
40
|
+
* default — a structured transport (WebSocket JSON) sends real types; only an
|
|
41
|
+
* LLM-style flat-string transport needs it.
|
|
42
|
+
*/
|
|
43
|
+
coerceJsonArgs?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface ContractDispatcher {
|
|
46
|
+
/**
|
|
47
|
+
* Run one contract method by its endpoint key (e.g. `'transcriptions.list'`)
|
|
48
|
+
* with a flat argument object. Returns the `{ ok: true, data } | { ok: false,
|
|
49
|
+
* code, details?, hint? }` envelope the MCP / agent transports use — it does
|
|
50
|
+
* not throw for a normal call; a handler error becomes a failed result, and an
|
|
51
|
+
* unknown method is a `NOT_FOUND` result. Per-call `context` is merged after
|
|
52
|
+
* the static `config.context` (neither can shadow `source`).
|
|
53
|
+
*/
|
|
54
|
+
dispatch(method: string, args: Record<string, unknown>, context?: Record<string, unknown>): Promise<ToolResult>;
|
|
55
|
+
/** Every method key this dispatcher can run, across the given services. */
|
|
56
|
+
readonly methods: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build a {@link ContractDispatcher} from one or more `implement()` services.
|
|
60
|
+
* Every method of every service is dispatchable by its key — exposure is the
|
|
61
|
+
* transport's choice (which services it dispatches), not the contract's `expose`
|
|
62
|
+
* (that gates the built-in HTTP / MCP / agent / CLI transports).
|
|
63
|
+
*/
|
|
64
|
+
export declare function createContractDispatcher(services: ServiceDef | ServiceDef[], config: ContractDispatcherConfig): ContractDispatcher;
|
|
65
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/tools/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,EAEhB,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,MAAM,EAAE,eAAe,CAAC;IACxB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE,EACnC,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAqCpB"}
|
|
@@ -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,
|
|
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.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { type CliConfig, createCli } from './tools/cli';
|
|
|
4
4
|
export type { ExitCodeMap } from './tools/cli-format';
|
|
5
5
|
export type { CliWaitConfig } from './tools/cli-wait';
|
|
6
6
|
export { coerceJsonArgs } from './tools/coerce';
|
|
7
|
+
export { type ContractDispatcher, type ContractDispatcherConfig, createContractDispatcher, } from './tools/dispatch';
|
|
7
8
|
export type { ToolCallHooks, ToolLifecycle, ToolResult } from './tools/execute';
|
|
8
9
|
export { flattenDiscriminatedUnion } from './tools/flatten';
|
|
9
10
|
export { buildToolManifest, type ToolManifestEntry } from './tools/manifest';
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/tools.js
CHANGED
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
collectTools,
|
|
9
9
|
createCli,
|
|
10
10
|
createToolRunner,
|
|
11
|
+
executeToolMethod,
|
|
11
12
|
fetchGuarded,
|
|
12
13
|
flattenDiscriminatedUnion,
|
|
13
14
|
formatToolError,
|
|
14
15
|
pollUntil,
|
|
15
16
|
readCapped,
|
|
16
17
|
toolResultFromError
|
|
17
|
-
} from "./index-
|
|
18
|
+
} from "./index-13psnhhe.js";
|
|
18
19
|
import {
|
|
19
20
|
toJsonSchema
|
|
20
21
|
} from "./index-0ed3bx43.js";
|
|
@@ -68,6 +69,30 @@ function mountAgent(services, config = {}) {
|
|
|
68
69
|
}
|
|
69
70
|
return tools;
|
|
70
71
|
}
|
|
72
|
+
// src/tools/dispatch.ts
|
|
73
|
+
function createContractDispatcher(services, config) {
|
|
74
|
+
const list = Array.isArray(services) ? services : [services];
|
|
75
|
+
const index = new Map;
|
|
76
|
+
for (const service of list) {
|
|
77
|
+
for (const [name, method] of Object.entries(service.methods)) {
|
|
78
|
+
if (index.has(name)) {
|
|
79
|
+
throw new Error(`createContractDispatcher: duplicate method "${name}" across services`);
|
|
80
|
+
}
|
|
81
|
+
index.set(name, method);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
methods: [...index.keys()],
|
|
86
|
+
dispatch(method, args, context) {
|
|
87
|
+
const target = index.get(method);
|
|
88
|
+
if (!target) {
|
|
89
|
+
return Promise.resolve(toolResultFromError(new AppError("NOT_FOUND", `Unknown method: ${method}`, 404)));
|
|
90
|
+
}
|
|
91
|
+
const ctx = { ...config.context, ...context, source: config.source };
|
|
92
|
+
return executeToolMethod(target, method, args, ctx, config.hooks, config.lifecycle, config.coerceJsonArgs ?? false);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
71
96
|
// src/tools/manifest.ts
|
|
72
97
|
function buildToolManifest(tools) {
|
|
73
98
|
return tools.map((t) => {
|
|
@@ -923,11 +948,11 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
923
948
|
url = url.slice(0, -1);
|
|
924
949
|
if (endpoint.multipart) {
|
|
925
950
|
const file = firstArg[endpoint.multipart];
|
|
926
|
-
if (!(file
|
|
951
|
+
if (!isMultipartFile(file)) {
|
|
927
952
|
throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
|
|
928
953
|
}
|
|
929
954
|
const formData = new FormData;
|
|
930
|
-
formData
|
|
955
|
+
appendMultipartFile(formData, endpoint.multipart, file);
|
|
931
956
|
appendFormFields(formData, firstArg, new Set([...prefixKeys, endpoint.multipart]));
|
|
932
957
|
return client.post(url, formData, withTimeout(undefined, endpoint.timeout));
|
|
933
958
|
}
|
|
@@ -984,11 +1009,11 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
984
1009
|
headers["Content-Type"] = "application/json";
|
|
985
1010
|
if (endpoint.multipart && args) {
|
|
986
1011
|
const file = args[endpoint.multipart];
|
|
987
|
-
if (!(file
|
|
1012
|
+
if (!isMultipartFile(file)) {
|
|
988
1013
|
throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
|
|
989
1014
|
}
|
|
990
1015
|
const formData = new FormData;
|
|
991
|
-
formData
|
|
1016
|
+
appendMultipartFile(formData, endpoint.multipart, file);
|
|
992
1017
|
appendFormFields(formData, stripParams(args, endpoint.path, prefixKeys), new Set([endpoint.multipart]));
|
|
993
1018
|
const res2 = await fetch(url, {
|
|
994
1019
|
method: endpoint.method,
|
|
@@ -1021,6 +1046,16 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
1021
1046
|
return endpoint.output ? endpoint.output.parse(json2) : json2;
|
|
1022
1047
|
};
|
|
1023
1048
|
}
|
|
1049
|
+
function isFileDescriptor(value) {
|
|
1050
|
+
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";
|
|
1051
|
+
}
|
|
1052
|
+
function isMultipartFile(value) {
|
|
1053
|
+
return value instanceof Blob || isFileDescriptor(value);
|
|
1054
|
+
}
|
|
1055
|
+
function appendMultipartFile(form, field, file) {
|
|
1056
|
+
const sink = form;
|
|
1057
|
+
sink.append(field, file);
|
|
1058
|
+
}
|
|
1024
1059
|
function appendFormFields(formData, values, skipKeys) {
|
|
1025
1060
|
for (const [key, value] of Object.entries(values)) {
|
|
1026
1061
|
if (skipKeys.has(key) || value === undefined || value === null)
|
|
@@ -1097,6 +1132,7 @@ function implementRemote(contract, http, options) {
|
|
|
1097
1132
|
inputSchema: endpoint.input,
|
|
1098
1133
|
outputSchema: endpoint.output,
|
|
1099
1134
|
multipart: endpoint.multipart,
|
|
1135
|
+
idempotent: endpoint.idempotent,
|
|
1100
1136
|
handler: async (ctx) => {
|
|
1101
1137
|
const call = client[key];
|
|
1102
1138
|
if (!call) {
|
|
@@ -1275,6 +1311,7 @@ export {
|
|
|
1275
1311
|
createToolkit,
|
|
1276
1312
|
createStdioMcpServer,
|
|
1277
1313
|
createMcpHandler,
|
|
1314
|
+
createContractDispatcher,
|
|
1278
1315
|
createCli,
|
|
1279
1316
|
collectTools,
|
|
1280
1317
|
coerceJsonArgs,
|
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
|
|
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 `
|
|
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,69 @@ 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 still want one contract: a `defineContract` with typed
|
|
1880
|
+
client/server, Zod validation and a typed error envelope, not a hand-rolled
|
|
1881
|
+
method registry alongside it.
|
|
1882
|
+
|
|
1883
|
+
stitchkit ships the **executor**, not the transport. `createContractDispatcher`
|
|
1884
|
+
runs a contract method by its key through the *same* core as the MCP / agent
|
|
1885
|
+
mounts — same validation, the same `{ ok, data } | { ok: false, code, … }`
|
|
1886
|
+
envelope, the same hooks and `beforeHandle` scope gate. You own the wire (framing,
|
|
1887
|
+
handshake, reconnect) and call `dispatch` per inbound frame.
|
|
1888
|
+
|
|
1889
|
+
```ts
|
|
1890
|
+
import { createContractDispatcher } from 'stitchkit/tools'
|
|
1891
|
+
import { implement } from 'stitchkit/server'
|
|
1892
|
+
|
|
1893
|
+
const service = implement(runtimeContract, { 'tasks.setDone': (ctx) => doIt(ctx.input), … })
|
|
1894
|
+
|
|
1895
|
+
const dispatcher = createContractDispatcher(service, { source: 'local-ws' })
|
|
1896
|
+
|
|
1897
|
+
// In your raw-WebSocket server, per `{ id, method, params }` frame:
|
|
1898
|
+
ws.onmessage = async (frame) => {
|
|
1899
|
+
const { id, method, params } = JSON.parse(frame.data)
|
|
1900
|
+
const result = await dispatcher.dispatch(method, params) // validates + runs
|
|
1901
|
+
ws.send(JSON.stringify({ id, ...result })) // { ok, data } | { ok:false, code, … }
|
|
1902
|
+
}
|
|
1903
|
+
```
|
|
1904
|
+
|
|
1905
|
+
`dispatch` never throws for a normal call — a handler error becomes a failed
|
|
1906
|
+
result, and an unknown method is a `NOT_FOUND` result. Pass `hooks`
|
|
1907
|
+
(`beforeToolCall` / `afterToolCall`) and `lifecycle.beforeHandle` to audit and
|
|
1908
|
+
scope-guard exactly like the other transports. Tag calls with your own
|
|
1909
|
+
`source` — `TransportSource` is an open union.
|
|
1910
|
+
|
|
1911
|
+
### Durability — `idempotent` + replay
|
|
1912
|
+
|
|
1913
|
+
If the sidecar can restart mid-call, the client decides what to do with an
|
|
1914
|
+
in-flight request on reconnect from the operation's **idempotency**, declared on
|
|
1915
|
+
the contract:
|
|
1916
|
+
|
|
1917
|
+
```ts
|
|
1918
|
+
export const runtimeContract = defineContract({ prefix: 'runtime' }, {
|
|
1919
|
+
'tasks.setDone': { method: 'POST', path: '/done', desc: '…',
|
|
1920
|
+
idempotent: true, input: taskDone, output: ok }, // re-send after reconnect — same result
|
|
1921
|
+
'capture.start': { method: 'POST', path: '/start', desc: '…',
|
|
1922
|
+
output: snapshot }, // unset → one-shot, do not re-send
|
|
1923
|
+
})
|
|
1924
|
+
```
|
|
1925
|
+
|
|
1926
|
+
`idempotent` rides through to `MethodDef.idempotent`; the core attaches no
|
|
1927
|
+
behaviour. Your reconnect logic reads it: replay an idempotent call (the
|
|
1928
|
+
durability guarantee — the user's action is not lost), reject a non-idempotent
|
|
1929
|
+
one rather than fire a second side effect. Pair it with
|
|
1930
|
+
[sticky events](#sticky-events) (`createRetainedTopics`) so a reconnected client
|
|
1931
|
+
also catches up on the latest pushed state.
|
|
1932
|
+
|
|
1933
|
+
This is deliberately *not* a reliable-RPC engine — that would be a competing
|
|
1934
|
+
WebSocket transport ([ADR 0008](../decisions/0008-thin-wrappers.md)). stitchkit
|
|
1935
|
+
gives you the executor and the metadata; the wire stays yours. See
|
|
1936
|
+
[ADR 0027](../decisions/0027-transport-neutral-contract-execution.md).
|
|
1937
|
+
|
|
1837
1938
|
|
|
1838
1939
|
==============================================================================
|
|
1839
1940
|
# Guide: Auth & errors (docs/guide/auth-and-errors.md)
|
|
@@ -2718,10 +2819,12 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
2718
2819
|
| Export | Kind | Summary |
|
|
2719
2820
|
|--------|------|---------|
|
|
2720
2821
|
| `createSocketIOClient` | function | the typed Socket.IO client — [guide](../guide/realtime.md#client--createsocketioclient) |
|
|
2822
|
+
| `createRetainedTopics` | function | retained last-value store for sticky events — [guide](../guide/realtime.md#sticky-events) |
|
|
2721
2823
|
| `parseSSE` | function | parse an SSE `Response` into an async generator — [guide](../guide/client.md#sse) |
|
|
2722
2824
|
| `SocketIOClient` | _type_ | the client handle |
|
|
2723
|
-
| `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` |
|
|
2825
|
+
| `SocketIOClientConfig` | _type_ | config for `createSocketIOClient` (incl. `retain`) |
|
|
2724
2826
|
| `SocketEventMap` | _type_ | the shape of an event map |
|
|
2827
|
+
| `RetainedTopics` | _type_ | the `createRetainedTopics` handle |
|
|
2725
2828
|
| `ParseSSEOptions` | _type_ | options for `parseSSE` |
|
|
2726
2829
|
|
|
2727
2830
|
---
|
|
@@ -2750,6 +2853,8 @@ from the root `stitchkit`.
|
|
|
2750
2853
|
| `TypedHttpClient` | _type_ | the typed client, HTTP endpoints only (`= ScopedHttpClient<C, unknown>`) |
|
|
2751
2854
|
| `ScopedHttpClient` | _type_ | a client whose `stripPrefixKeys` become required args ([guide](../guide/multi-tenant.md)) |
|
|
2752
2855
|
| `ScopedEndpointFn` | _type_ | one method's signature with the consumed keys folded in |
|
|
2856
|
+
| `MultipartFile` | _type_ | a `multipart` file field — `Blob \| FileDescriptor` |
|
|
2857
|
+
| `FileDescriptor` | _type_ | a React Native / Expo file — `{ uri, name, type }` |
|
|
2753
2858
|
|
|
2754
2859
|
### Errors
|
|
2755
2860
|
|
|
@@ -2953,6 +3058,7 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
2953
3058
|
| `mountMcp` | function | add contract tools to an existing `McpServer` — [guide](../guide/mcp-and-agents.md#mountmcp) |
|
|
2954
3059
|
| `implementRemote` | function | bind a contract to a remote HTTP API — [guide](../guide/mcp-and-agents.md#proxying-a-remote-api--implementremote) |
|
|
2955
3060
|
| `mountAgent` | function | a Vercel AI SDK `ToolSet` from a service — [guide](../guide/mcp-and-agents.md#ai-agents--mountagent) |
|
|
3061
|
+
| `createContractDispatcher` | function | run a contract over a bring-your-own transport — [guide](../guide/realtime.md#bring-your-own-transport) |
|
|
2956
3062
|
| `createCli` | function | a command-line program from contracts — [guide](../guide/cli.md) (also on `stitchkit/cli`) |
|
|
2957
3063
|
| `createToolkit` | function | context-typed tool mounts — [guide](../guide/cli.md#typed-context) |
|
|
2958
3064
|
| `mountViewFile` | function | a native multimodal "view file" MCP tool |
|
|
@@ -2964,6 +3070,8 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
2964
3070
|
| `ImplementRemoteOptions` | _type_ | options for `implementRemote` |
|
|
2965
3071
|
| `McpMountConfig` | _type_ | config for `mountMcp` |
|
|
2966
3072
|
| `AgentMountConfig` | _type_ | config for `mountAgent` |
|
|
3073
|
+
| `ContractDispatcher` | _type_ | the `createContractDispatcher` handle |
|
|
3074
|
+
| `ContractDispatcherConfig` | _type_ | config for `createContractDispatcher` |
|
|
2967
3075
|
| `AgentContext` | _type_ | the context merged into agent tool handlers |
|
|
2968
3076
|
| `CliConfig` | _type_ | config for `createCli` |
|
|
2969
3077
|
| `CliWaitConfig` | _type_ | `--wait` polling config |
|
package/package.json
CHANGED