stitchkit 0.5.0 → 0.7.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 +17 -5
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/contract/define.d.ts +16 -2
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/errors.d.ts +26 -1
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/index.d.ts +2 -2
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +5 -1
- package/dist/{index-vhdvv00d.js → index-4843j09b.js} +1 -1
- package/dist/{index-kgjnt3hn.js → index-8hsj2qm9.js} +102 -36
- package/dist/{index-afzt3nmx.js → index-9bk6r5ff.js} +8 -4
- package/dist/{index-1cf8jkhf.js → index-hty3443r.js} +1 -1
- package/dist/{index-78q1qm7v.js → index-kdkvp26v.js} +21 -12
- package/dist/{index-d4rwrjbc.js → index-mahbaen9.js} +1 -1
- package/dist/{index-0ma1eqv4.js → index-p8byjw3e.js} +3 -3
- package/dist/index-za2p453b.js +87 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/node.js +3 -3
- package/dist/observability/index.js +14 -86
- package/dist/server/context.d.ts +1 -1
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/file.d.ts +52 -0
- package/dist/server/file.d.ts.map +1 -0
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +190 -5
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/mime.d.ts +3 -0
- package/dist/server/mime.d.ts.map +1 -0
- package/dist/server/raw.d.ts +36 -0
- package/dist/server/raw.d.ts.map +1 -0
- package/dist/server/router.d.ts +4 -3
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/socket-io.d.ts +10 -1
- package/dist/server/socket-io.d.ts.map +1 -1
- package/dist/server/types.d.ts +32 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +2 -2
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +5 -0
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools.js +9 -5
- package/package.json +1 -1
package/dist/browser/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContractDef, EndpointDef, TypedHttpClient } from '../contract';
|
|
1
|
+
import type { ContractDef, EndpointDef, ScopedHttpClient, TypedHttpClient } from '../contract';
|
|
2
2
|
import { type HttpClient as HttpAdapter } from './http';
|
|
3
3
|
/** Config for the built-in fetch client — used when no `HttpClient` is passed. */
|
|
4
4
|
export interface ClientConfig {
|
|
@@ -7,10 +7,22 @@ export interface ClientConfig {
|
|
|
7
7
|
credentials?: RequestCredentials;
|
|
8
8
|
onError?: (status: number, body: unknown) => void;
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The keys a `pathPrefix` consumes, as required `string` args. `never` (a plain
|
|
12
|
+
* client) collapses to `unknown`, so `EndpointArgs & unknown = EndpointArgs`.
|
|
13
|
+
*/
|
|
14
|
+
export type ScopedKeys<K extends string> = [K] extends [never] ? unknown : {
|
|
15
|
+
[P in K]: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Per-contract client tweaks — a dynamic URL `pathPrefix` and the keys it
|
|
19
|
+
* consumes. List the consumed keys in `stripPrefixKeys` (e.g. `['tenantId']`)
|
|
20
|
+
* and they become required, typed args on every method of the returned client —
|
|
21
|
+
* no hand-written scoped-client wrapper.
|
|
22
|
+
*/
|
|
23
|
+
export interface ContractClientConfig<K extends string = never> {
|
|
12
24
|
pathPrefix?: string | ((args: Record<string, unknown>) => string);
|
|
13
|
-
stripPrefixKeys?:
|
|
25
|
+
stripPrefixKeys?: readonly K[];
|
|
14
26
|
}
|
|
15
27
|
/**
|
|
16
28
|
* Build a fully-typed client from a contract. Every endpoint becomes a typed
|
|
@@ -18,7 +30,7 @@ export interface ContractClientConfig {
|
|
|
18
30
|
* (from `createHttpClient`) for cookie auth, SSR and retry, or a plain
|
|
19
31
|
* `ClientConfig` for a bare fetch client.
|
|
20
32
|
*/
|
|
21
|
-
export declare function createClient<T extends Record<string, EndpointDef
|
|
33
|
+
export declare function createClient<T extends Record<string, EndpointDef>, const K extends string = never>(contract: ContractDef<T, string>, configOrClient: ClientConfig | HttpAdapter, contractConfig?: ContractClientConfig<K>): ScopedHttpClient<T, ScopedKeys<K>>;
|
|
22
34
|
/**
|
|
23
35
|
* Batch form of `createClient` — one fully-typed client per contract, built
|
|
24
36
|
* from a `name → contract` registry. Each key keeps its own client type, so
|
|
@@ -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,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
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"}
|
package/dist/cli.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
emitResult,
|
|
5
5
|
parseCliArgs,
|
|
6
6
|
pollUntilDone
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-p8byjw3e.js";
|
|
8
8
|
import"./index-0ed3bx43.js";
|
|
9
9
|
import"./index-x3fcszf8.js";
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
10
|
+
import"./index-4843j09b.js";
|
|
11
|
+
import"./index-9bk6r5ff.js";
|
|
12
12
|
import"./index-kzfs85xp.js";
|
|
13
13
|
import"./index-809wc1tt.js";
|
|
14
14
|
import"./index-37x76zdn.js";
|
|
@@ -12,6 +12,13 @@ interface EndpointDefBase {
|
|
|
12
12
|
input?: ZodType<unknown>;
|
|
13
13
|
output?: ZodType<unknown>;
|
|
14
14
|
multipart?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Per-route upload ceiling in bytes for a `multipart` endpoint. Overrides the
|
|
17
|
+
* server's `maxUploadBytes` default; without either, the 25 MB framework
|
|
18
|
+
* default applies. Lets an avatar (5 MB) and a video (200 MB) declare their
|
|
19
|
+
* own caps. Ignored on non-multipart endpoints.
|
|
20
|
+
*/
|
|
21
|
+
maxUploadBytes?: number;
|
|
15
22
|
/**
|
|
16
23
|
* HTTP client timeout in ms for this endpoint. Use it for slow synchronous
|
|
17
24
|
* endpoints (AI generation) that need more than the client default. A
|
|
@@ -26,6 +33,10 @@ interface EndpointDefBase {
|
|
|
26
33
|
* app concerns the generic core does not model — a feature gate, a rate tier,
|
|
27
34
|
* a cache hint, a doc/owner tag. The consumer narrows the type when reading.
|
|
28
35
|
* Never surfaced in the OpenAPI document (app-private, not the HTTP contract).
|
|
36
|
+
*
|
|
37
|
+
* Declare its type as a `type` / inline literal / `satisfies` — **not an
|
|
38
|
+
* `interface`** (an interface has no implicit index signature, so it is not
|
|
39
|
+
* assignable to `Record<string, unknown>`).
|
|
29
40
|
*/
|
|
30
41
|
meta?: Record<string, unknown>;
|
|
31
42
|
}
|
|
@@ -130,8 +141,11 @@ export type TypedClient<C extends Record<string, EndpointDef>> = {
|
|
|
130
141
|
type ExposesHttp<E> = E extends {
|
|
131
142
|
expose: readonly Transport[];
|
|
132
143
|
} ? 'HTTP' extends E['expose'][number] ? true : false : true;
|
|
133
|
-
|
|
134
|
-
|
|
144
|
+
type ArgsWith<E, Extra> = EndpointArgs<E> & Extra;
|
|
145
|
+
export type ScopedEndpointFn<E, Extra> = [keyof ArgsWith<E, Extra>] extends [never] ? () => Promise<EndpointOutput<E>> : (args: ArgsWith<E, Extra>) => Promise<EndpointOutput<E>>;
|
|
146
|
+
export type ScopedHttpClient<C extends Record<string, EndpointDef>, Extra> = {
|
|
147
|
+
[K in keyof C as ExposesHttp<C[K]> extends true ? K : never]: ScopedEndpointFn<C[K], Extra>;
|
|
135
148
|
};
|
|
149
|
+
export type TypedHttpClient<C extends Record<string, EndpointDef>> = ScopedHttpClient<C, unknown>;
|
|
136
150
|
export {};
|
|
137
151
|
//# sourceMappingURL=define.d.ts.map
|
|
@@ -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/D,UAAU,eAAe;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,31 @@ export declare function forbidden(message?: string): never;
|
|
|
42
42
|
export declare function conflict(message?: string, details?: Record<string, unknown>): never;
|
|
43
43
|
/** Throw a `429 RATE_LIMITED` error. */
|
|
44
44
|
export declare function rateLimited(message?: string): never;
|
|
45
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* `code → HTTP status` for the error codes **stitchkit itself** emits — the
|
|
47
|
+
* typed helpers above, `normalizeError` (`VALIDATION_ERROR` /
|
|
48
|
+
* `INTERNAL_SERVER_ERROR`) and the router (`METHOD_NOT_ALLOWED`). This map is the
|
|
49
|
+
* single source of truth: `StitchErrorCode` is derived from its keys, so the two
|
|
50
|
+
* never drift. App-defined codes are free strings the core never sees (ADR 0002);
|
|
51
|
+
* these are stitchkit's own, published so a consumer can map stitch → app codes
|
|
52
|
+
* against a stable, typed reference instead of a hand-copied string list.
|
|
53
|
+
* → ADR 0026.
|
|
54
|
+
*/
|
|
55
|
+
export declare const STITCH_ERROR_STATUS: {
|
|
56
|
+
BAD_REQUEST: number;
|
|
57
|
+
UNAUTHORIZED: number;
|
|
58
|
+
FORBIDDEN: number;
|
|
59
|
+
NOT_FOUND: number;
|
|
60
|
+
METHOD_NOT_ALLOWED: number;
|
|
61
|
+
CONFLICT: number;
|
|
62
|
+
RATE_LIMITED: number;
|
|
63
|
+
VALIDATION_ERROR: number;
|
|
64
|
+
INTERNAL_SERVER_ERROR: number;
|
|
65
|
+
};
|
|
66
|
+
/** A code stitchkit itself emits — derived from `STITCH_ERROR_STATUS` (no dup). */
|
|
67
|
+
export type StitchErrorCode = keyof typeof STITCH_ERROR_STATUS;
|
|
68
|
+
/** Type guard — is `code` one of stitchkit's own error codes? */
|
|
69
|
+
export declare function isStitchErrorCode(code: string): code is StitchErrorCode;
|
|
70
|
+
/** Throw an `AppError` for any `code`, mapping a stitch code to its HTTP status (else 500). */
|
|
46
71
|
export declare function appError(code: string, message?: string, details?: Record<string, unknown>): never;
|
|
47
72
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/contract/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,2CAA2C;QAC3C,IAAI,EAAE,MAAM,CAAC;QACb,8BAA8B;QAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,gCAAgC;QAChC,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,0BAA0B;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aAEZ,MAAM,EAAE,MAAM;aACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;aACjC,IAAI,CAAC,EAAE,MAAM;gBAJb,IAAI,EAAE,MAAM,EAC5B,OAAO,CAAC,EAAE,MAAM,EACA,MAAM,GAAE,MAAY,EACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA,EACjC,IAAI,CAAC,EAAE,MAAM,YAAA;IAM/B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,QAAQ;IAIxC,MAAM,IAAI,aAAa;CAUxB;AAED,qCAAqC;AACrC,wBAAgB,QAAQ,CAAC,OAAO,SAAc,GAAG,KAAK,CAErD;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAEpF;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAAC,OAAO,SAAiB,GAAG,KAAK,CAE5D;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,OAAO,SAAc,GAAG,KAAK,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,OAAO,SAAa,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAEvF;AAED,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,OAAO,SAAsB,GAAG,KAAK,CAEhE;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/contract/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,2CAA2C;QAC3C,IAAI,EAAE,MAAM,CAAC;QACb,8BAA8B;QAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,gCAAgC;QAChC,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,0BAA0B;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aAEZ,MAAM,EAAE,MAAM;aACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;aACjC,IAAI,CAAC,EAAE,MAAM;gBAJb,IAAI,EAAE,MAAM,EAC5B,OAAO,CAAC,EAAE,MAAM,EACA,MAAM,GAAE,MAAY,EACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA,EACjC,IAAI,CAAC,EAAE,MAAM,YAAA;IAM/B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,QAAQ;IAIxC,MAAM,IAAI,aAAa;CAUxB;AAED,qCAAqC;AACrC,wBAAgB,QAAQ,CAAC,OAAO,SAAc,GAAG,KAAK,CAErD;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAEpF;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAAC,OAAO,SAAiB,GAAG,KAAK,CAE5D;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,OAAO,SAAc,GAAG,KAAK,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,OAAO,SAAa,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAEvF;AAED,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,OAAO,SAAsB,GAAG,KAAK,CAEhE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;CAUE,CAAC;AAEnC,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAE/D,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,eAAe,CAEvE;AAED,+FAA+F;AAC/F,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,KAAK,CAOP"}
|
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 Transport, type TransportSource, type TypedClient, type TypedHttpClient, } from './define';
|
|
2
|
-
export { AppError, appError, badRequest, conflict, type ErrorEnvelope, forbidden, notFound, rateLimited, unauthorized, } from './errors';
|
|
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';
|
|
2
|
+
export { AppError, appError, badRequest, conflict, type ErrorEnvelope, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from './errors';
|
|
3
3
|
export { 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,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,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,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,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,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/contract/index.js
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ALL_TRANSPORTS,
|
|
3
3
|
AppError,
|
|
4
|
+
STITCH_ERROR_STATUS,
|
|
4
5
|
appError,
|
|
5
6
|
badRequest,
|
|
6
7
|
conflict,
|
|
7
8
|
defineContract,
|
|
8
9
|
forbidden,
|
|
10
|
+
isStitchErrorCode,
|
|
9
11
|
notFound,
|
|
10
12
|
paginatedSchema,
|
|
11
13
|
rateLimited,
|
|
12
14
|
unauthorized
|
|
13
|
-
} from "../index-
|
|
15
|
+
} from "../index-9bk6r5ff.js";
|
|
14
16
|
import"../index-37x76zdn.js";
|
|
15
17
|
export {
|
|
16
18
|
unauthorized,
|
|
17
19
|
rateLimited,
|
|
18
20
|
paginatedSchema,
|
|
19
21
|
notFound,
|
|
22
|
+
isStitchErrorCode,
|
|
20
23
|
forbidden,
|
|
21
24
|
defineContract,
|
|
22
25
|
conflict,
|
|
23
26
|
badRequest,
|
|
24
27
|
appError,
|
|
28
|
+
STITCH_ERROR_STATUS,
|
|
25
29
|
AppError,
|
|
26
30
|
ALL_TRANSPORTS
|
|
27
31
|
};
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
normalizeError,
|
|
6
6
|
validateHandlerOutput
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-4843j09b.js";
|
|
8
8
|
import {
|
|
9
9
|
AppError,
|
|
10
10
|
badRequest
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-9bk6r5ff.js";
|
|
12
12
|
import {
|
|
13
13
|
extractIp,
|
|
14
14
|
getClientInfo,
|
|
@@ -129,7 +129,45 @@ function corsPreflightResponse(config, req) {
|
|
|
129
129
|
|
|
130
130
|
// src/server/router.ts
|
|
131
131
|
import { readFile, stat } from "node:fs/promises";
|
|
132
|
-
import {
|
|
132
|
+
import { resolve } from "node:path";
|
|
133
|
+
|
|
134
|
+
// src/server/mime.ts
|
|
135
|
+
import { extname } from "node:path";
|
|
136
|
+
var MIME_BY_EXT = {
|
|
137
|
+
".html": "text/html; charset=utf-8",
|
|
138
|
+
".css": "text/css; charset=utf-8",
|
|
139
|
+
".js": "text/javascript; charset=utf-8",
|
|
140
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
141
|
+
".json": "application/json; charset=utf-8",
|
|
142
|
+
".svg": "image/svg+xml",
|
|
143
|
+
".png": "image/png",
|
|
144
|
+
".jpg": "image/jpeg",
|
|
145
|
+
".jpeg": "image/jpeg",
|
|
146
|
+
".gif": "image/gif",
|
|
147
|
+
".webp": "image/webp",
|
|
148
|
+
".avif": "image/avif",
|
|
149
|
+
".ico": "image/x-icon",
|
|
150
|
+
".woff2": "font/woff2",
|
|
151
|
+
".txt": "text/plain; charset=utf-8",
|
|
152
|
+
".wasm": "application/wasm",
|
|
153
|
+
".mp4": "video/mp4",
|
|
154
|
+
".webm": "video/webm",
|
|
155
|
+
".mov": "video/quicktime",
|
|
156
|
+
".ogv": "video/ogg",
|
|
157
|
+
".mp3": "audio/mpeg",
|
|
158
|
+
".m4a": "audio/mp4",
|
|
159
|
+
".wav": "audio/wav",
|
|
160
|
+
".flac": "audio/flac",
|
|
161
|
+
".oga": "audio/ogg",
|
|
162
|
+
".ogg": "audio/ogg",
|
|
163
|
+
".pdf": "application/pdf",
|
|
164
|
+
".zip": "application/zip"
|
|
165
|
+
};
|
|
166
|
+
function mimeForPath(path) {
|
|
167
|
+
return MIME_BY_EXT[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/server/router.ts
|
|
133
171
|
function joinPath(...parts) {
|
|
134
172
|
const joined = parts.filter(Boolean).map((part) => part.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
|
|
135
173
|
return `/${joined}`;
|
|
@@ -247,22 +285,6 @@ function matchRawRoute(rawRoutes, httpMethod, pathname) {
|
|
|
247
285
|
}
|
|
248
286
|
return null;
|
|
249
287
|
}
|
|
250
|
-
var STATIC_MIME = {
|
|
251
|
-
".html": "text/html; charset=utf-8",
|
|
252
|
-
".css": "text/css; charset=utf-8",
|
|
253
|
-
".js": "text/javascript; charset=utf-8",
|
|
254
|
-
".mjs": "text/javascript; charset=utf-8",
|
|
255
|
-
".json": "application/json; charset=utf-8",
|
|
256
|
-
".svg": "image/svg+xml",
|
|
257
|
-
".png": "image/png",
|
|
258
|
-
".jpg": "image/jpeg",
|
|
259
|
-
".jpeg": "image/jpeg",
|
|
260
|
-
".gif": "image/gif",
|
|
261
|
-
".webp": "image/webp",
|
|
262
|
-
".ico": "image/x-icon",
|
|
263
|
-
".woff2": "font/woff2",
|
|
264
|
-
".txt": "text/plain; charset=utf-8"
|
|
265
|
-
};
|
|
266
288
|
function staticRoute(prefix, dir) {
|
|
267
289
|
const cleanPrefix = prefix.replace(/\/+$/, "");
|
|
268
290
|
const root = resolve(dir.replace(/\/+$/, ""));
|
|
@@ -288,7 +310,7 @@ function staticRoute(prefix, dir) {
|
|
|
288
310
|
const body = await readFile(target);
|
|
289
311
|
return new Response(body, {
|
|
290
312
|
headers: {
|
|
291
|
-
"Content-Type":
|
|
313
|
+
"Content-Type": mimeForPath(target),
|
|
292
314
|
"X-Content-Type-Options": "nosniff"
|
|
293
315
|
}
|
|
294
316
|
});
|
|
@@ -322,12 +344,13 @@ async function readJsonBody(req) {
|
|
|
322
344
|
badRequest("Invalid JSON body");
|
|
323
345
|
}
|
|
324
346
|
}
|
|
325
|
-
async function buildContext(req, url, method, pathParams, traceId, clientIp) {
|
|
347
|
+
async function buildContext(req, url, method, pathParams, traceId, clientIp, maxUploadBytes) {
|
|
326
348
|
const parsedParams = method.paramsSchema ? method.paramsSchema.parse(pathParams) : undefined;
|
|
327
349
|
let parsedInput;
|
|
328
350
|
let file;
|
|
329
351
|
if (method.multipart) {
|
|
330
|
-
const
|
|
352
|
+
const cap = method.maxUploadBytes ?? maxUploadBytes;
|
|
353
|
+
const multipart = await parseMultipart(req, method.multipart, method.inputSchema, cap);
|
|
331
354
|
parsedInput = multipart.fields;
|
|
332
355
|
file = multipart.file;
|
|
333
356
|
} else if (method.inputSchema) {
|
|
@@ -410,7 +433,13 @@ function elapsedMs(startTime) {
|
|
|
410
433
|
return performance.now() - startTime;
|
|
411
434
|
}
|
|
412
435
|
function safePath(pathname) {
|
|
413
|
-
|
|
436
|
+
let out = "";
|
|
437
|
+
for (let i = 0;i < pathname.length; i++) {
|
|
438
|
+
const code = pathname.charCodeAt(i);
|
|
439
|
+
if (code > 31 && code !== 127)
|
|
440
|
+
out += pathname.charAt(i);
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
414
443
|
}
|
|
415
444
|
function levelForStatus(status) {
|
|
416
445
|
if (status >= 500)
|
|
@@ -574,7 +603,7 @@ function createHandler(config) {
|
|
|
574
603
|
const { method, pathParams, groupHooks } = match;
|
|
575
604
|
let ctx;
|
|
576
605
|
try {
|
|
577
|
-
ctx = await buildContext(req, url, method, pathParams, traceId, clientIp);
|
|
606
|
+
ctx = await buildContext(req, url, method, pathParams, traceId, clientIp, config.maxUploadBytes);
|
|
578
607
|
if (hooks?.beforeHandle) {
|
|
579
608
|
await hooks.beforeHandle(ctx, method);
|
|
580
609
|
}
|
|
@@ -646,7 +675,8 @@ function normalizeGroups(config) {
|
|
|
646
675
|
const result = [];
|
|
647
676
|
if (config.services) {
|
|
648
677
|
for (const service of config.services) {
|
|
649
|
-
|
|
678
|
+
const prefix = config.scopePrefixes?.[service.scope] ?? "";
|
|
679
|
+
result.push({ prefix, service });
|
|
650
680
|
}
|
|
651
681
|
}
|
|
652
682
|
if (config.groups) {
|
|
@@ -690,6 +720,8 @@ function implement(contract, handlers) {
|
|
|
690
720
|
method: endpoint.method,
|
|
691
721
|
path: endpoint.path,
|
|
692
722
|
desc: endpoint.desc,
|
|
723
|
+
serviceName: contract.meta.prefix,
|
|
724
|
+
key: String(key),
|
|
693
725
|
toolName: "toolName" in endpoint ? endpoint.toolName : undefined,
|
|
694
726
|
expose: endpoint.expose,
|
|
695
727
|
scope: endpoint.scope ?? groupScope,
|
|
@@ -697,6 +729,7 @@ function implement(contract, handlers) {
|
|
|
697
729
|
inputSchema: endpoint.input,
|
|
698
730
|
outputSchema: endpoint.output,
|
|
699
731
|
multipart: endpoint.multipart,
|
|
732
|
+
maxUploadBytes: endpoint.maxUploadBytes,
|
|
700
733
|
ui: "ui" in endpoint ? endpoint.ui : undefined,
|
|
701
734
|
annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
|
|
702
735
|
meta: endpoint.meta,
|
|
@@ -774,25 +807,58 @@ function composeWebSocketHandlers(lanes, config) {
|
|
|
774
807
|
|
|
775
808
|
// src/server/socket-io.ts
|
|
776
809
|
var noop = () => {};
|
|
810
|
+
function isModuleNotFound(err) {
|
|
811
|
+
if (typeof err !== "object" || err === null)
|
|
812
|
+
return false;
|
|
813
|
+
const code = "code" in err ? err.code : undefined;
|
|
814
|
+
const message = "message" in err && typeof err.message === "string" ? err.message : "";
|
|
815
|
+
return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || message.includes("Cannot find module") || message.includes("Cannot find package");
|
|
816
|
+
}
|
|
817
|
+
async function importPeer(load, pkg) {
|
|
818
|
+
try {
|
|
819
|
+
return await load();
|
|
820
|
+
} catch (err) {
|
|
821
|
+
if (isModuleNotFound(err)) {
|
|
822
|
+
throw new Error(`[stitchkit] createSocketIOServer needs the optional peer "${pkg}" — install it: bun add ${pkg}`, { cause: err });
|
|
823
|
+
}
|
|
824
|
+
throw err;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
777
827
|
async function createSocketIOServer(config) {
|
|
778
828
|
const path = config.path ?? "/socket.io/";
|
|
779
829
|
const onBun = "Bun" in globalThis;
|
|
780
830
|
const transports = config.transports ?? (onBun ? ["websocket", "polling"] : ["websocket"]);
|
|
781
|
-
const
|
|
831
|
+
const pingTimeout = config.pingTimeout ?? 20000;
|
|
832
|
+
const pingInterval = config.pingInterval ?? 1e4;
|
|
833
|
+
const cors = {
|
|
834
|
+
origin: config.cors.origin,
|
|
835
|
+
credentials: config.cors.credentials ?? true,
|
|
836
|
+
methods: ["GET", "POST"]
|
|
837
|
+
};
|
|
838
|
+
const { Server } = await importPeer(() => import("socket.io"), "socket.io");
|
|
782
839
|
const io = new Server({
|
|
840
|
+
...config.serverOptions,
|
|
783
841
|
path,
|
|
784
|
-
cors
|
|
785
|
-
origin: config.cors.origin,
|
|
786
|
-
credentials: config.cors.credentials ?? true,
|
|
787
|
-
methods: ["GET", "POST"]
|
|
788
|
-
},
|
|
842
|
+
cors,
|
|
789
843
|
transports,
|
|
790
|
-
pingTimeout
|
|
791
|
-
pingInterval
|
|
844
|
+
pingTimeout,
|
|
845
|
+
pingInterval
|
|
792
846
|
});
|
|
793
847
|
if (onBun) {
|
|
794
|
-
const { Server: Engine } = await import("@socket.io/bun-engine");
|
|
795
|
-
const
|
|
848
|
+
const { Server: Engine } = await importPeer(() => import("@socket.io/bun-engine"), "@socket.io/bun-engine");
|
|
849
|
+
const engineOpts = {
|
|
850
|
+
path,
|
|
851
|
+
cors,
|
|
852
|
+
pingTimeout,
|
|
853
|
+
pingInterval
|
|
854
|
+
};
|
|
855
|
+
if (config.serverOptions?.maxHttpBufferSize !== undefined) {
|
|
856
|
+
engineOpts.maxHttpBufferSize = config.serverOptions.maxHttpBufferSize;
|
|
857
|
+
}
|
|
858
|
+
if (config.serverOptions?.upgradeTimeout !== undefined) {
|
|
859
|
+
engineOpts.upgradeTimeout = config.serverOptions.upgradeTimeout;
|
|
860
|
+
}
|
|
861
|
+
const engine = new Engine(engineOpts);
|
|
796
862
|
io.bind(engine);
|
|
797
863
|
const { websocket } = engine.handler();
|
|
798
864
|
const route = {
|
|
@@ -827,4 +893,4 @@ function socketIoLane(websocket) {
|
|
|
827
893
|
});
|
|
828
894
|
}
|
|
829
895
|
|
|
830
|
-
export { parseMultipart, corsHeaders, corsPreflightResponse, staticRoute, createHandler, createServer, implement, createImplement, webSocketLane, composeWebSocketHandlers, createSocketIOServer, socketIoLane };
|
|
896
|
+
export { parseMultipart, corsHeaders, corsPreflightResponse, mimeForPath, staticRoute, createHandler, createServer, implement, createImplement, webSocketLane, composeWebSocketHandlers, createSocketIOServer, socketIoLane };
|
|
@@ -72,18 +72,22 @@ function conflict(message = "Conflict", details) {
|
|
|
72
72
|
function rateLimited(message = "Too many requests") {
|
|
73
73
|
throw new AppError("RATE_LIMITED", message, 429);
|
|
74
74
|
}
|
|
75
|
-
var
|
|
76
|
-
NOT_FOUND: 404,
|
|
75
|
+
var STITCH_ERROR_STATUS = {
|
|
77
76
|
BAD_REQUEST: 400,
|
|
78
77
|
UNAUTHORIZED: 401,
|
|
79
78
|
FORBIDDEN: 403,
|
|
79
|
+
NOT_FOUND: 404,
|
|
80
|
+
METHOD_NOT_ALLOWED: 405,
|
|
80
81
|
CONFLICT: 409,
|
|
81
82
|
RATE_LIMITED: 429,
|
|
82
83
|
VALIDATION_ERROR: 400,
|
|
83
84
|
INTERNAL_SERVER_ERROR: 500
|
|
84
85
|
};
|
|
86
|
+
function isStitchErrorCode(code) {
|
|
87
|
+
return code in STITCH_ERROR_STATUS;
|
|
88
|
+
}
|
|
85
89
|
function appError(code, message, details) {
|
|
86
|
-
throw new AppError(code, message,
|
|
90
|
+
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
87
91
|
}
|
|
88
92
|
// src/contract/pagination.ts
|
|
89
93
|
import { z } from "zod";
|
|
@@ -93,4 +97,4 @@ function paginatedSchema(itemSchema) {
|
|
|
93
97
|
nextCursor: z.string().nullable()
|
|
94
98
|
});
|
|
95
99
|
}
|
|
96
|
-
export { ALL_TRANSPORTS, defineContract, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, appError, paginatedSchema };
|
|
100
|
+
export { ALL_TRANSPORTS, defineContract, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, paginatedSchema };
|
|
@@ -190,7 +190,7 @@ function collectQueryParams(args, skipKeys) {
|
|
|
190
190
|
}
|
|
191
191
|
function createClient(contract, configOrClient, contractConfig) {
|
|
192
192
|
const client = {};
|
|
193
|
-
const makeMethod = isHttpAdapter(configOrClient) ? (endpoint) => createHttpMethod(endpoint, contract.meta.prefix, configOrClient, contractConfig) : (endpoint) => createFetchMethod(endpoint, contract.meta.prefix, configOrClient);
|
|
193
|
+
const makeMethod = isHttpAdapter(configOrClient) ? (endpoint) => createHttpMethod(endpoint, contract.meta.prefix, configOrClient, contractConfig) : (endpoint) => createFetchMethod(endpoint, contract.meta.prefix, configOrClient, contractConfig);
|
|
194
194
|
for (const [key, endpoint] of typedEntries(contract.endpoints)) {
|
|
195
195
|
if (endpoint.expose && !endpoint.expose.includes("HTTP"))
|
|
196
196
|
continue;
|
|
@@ -257,9 +257,16 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
257
257
|
return client[httpMethod](url, Object.keys(payload).length > 0 ? payload : undefined, withTimeout(undefined, endpoint.timeout));
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
|
-
function createFetchMethod(endpoint, prefix, config) {
|
|
260
|
+
function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
261
|
+
const prefixKeys = new Set(contractConfig?.stripPrefixKeys ?? []);
|
|
261
262
|
return async (args) => {
|
|
262
|
-
let
|
|
263
|
+
let pathPrefixStr = "";
|
|
264
|
+
if (contractConfig?.pathPrefix) {
|
|
265
|
+
pathPrefixStr = typeof contractConfig.pathPrefix === "function" ? contractConfig.pathPrefix(args ?? {}) : contractConfig.pathPrefix;
|
|
266
|
+
if (pathPrefixStr && !pathPrefixStr.endsWith("/"))
|
|
267
|
+
pathPrefixStr += "/";
|
|
268
|
+
}
|
|
269
|
+
let url = buildFetchUrl(config.baseUrl, prefix, endpoint.path, args, pathPrefixStr);
|
|
263
270
|
const headers = {
|
|
264
271
|
Accept: "application/json",
|
|
265
272
|
...typeof config.headers === "function" ? config.headers() : config.headers
|
|
@@ -267,7 +274,7 @@ function createFetchMethod(endpoint, prefix, config) {
|
|
|
267
274
|
const isQuery = inputIsQuery(endpoint.method);
|
|
268
275
|
const hasBody = !isQuery && !endpoint.multipart && endpoint.input && args;
|
|
269
276
|
if (isQuery && args) {
|
|
270
|
-
const remaining = stripParams(args, endpoint.path);
|
|
277
|
+
const remaining = stripParams(args, endpoint.path, prefixKeys);
|
|
271
278
|
const searchParams = new URLSearchParams;
|
|
272
279
|
for (const [k, v] of Object.entries(remaining)) {
|
|
273
280
|
if (v === undefined || v === null)
|
|
@@ -291,7 +298,7 @@ function createFetchMethod(endpoint, prefix, config) {
|
|
|
291
298
|
}
|
|
292
299
|
const formData = new FormData;
|
|
293
300
|
formData.append(endpoint.multipart, file);
|
|
294
|
-
appendFormFields(formData, stripParams(args, endpoint.path), new Set([endpoint.multipart]));
|
|
301
|
+
appendFormFields(formData, stripParams(args, endpoint.path, prefixKeys), new Set([endpoint.multipart]));
|
|
295
302
|
const res2 = await fetch(url, {
|
|
296
303
|
method: endpoint.method,
|
|
297
304
|
headers,
|
|
@@ -310,7 +317,9 @@ function createFetchMethod(endpoint, prefix, config) {
|
|
|
310
317
|
method: endpoint.method,
|
|
311
318
|
headers,
|
|
312
319
|
credentials: config.credentials,
|
|
313
|
-
...hasBody && {
|
|
320
|
+
...hasBody && {
|
|
321
|
+
body: JSON.stringify(stripParams(hasBody, endpoint.path, prefixKeys))
|
|
322
|
+
}
|
|
314
323
|
});
|
|
315
324
|
if (!res.ok) {
|
|
316
325
|
await throwForErrorResponse(res, config, { error: res.statusText });
|
|
@@ -341,8 +350,8 @@ function extractParamNames(path) {
|
|
|
341
350
|
const matches = path.match(/:(\w+)/g);
|
|
342
351
|
return matches ? matches.map((m) => m.slice(1)) : [];
|
|
343
352
|
}
|
|
344
|
-
function buildFetchUrl(baseUrl, prefix, path, args) {
|
|
345
|
-
let fullPath = `/${prefix}${path === "/" ? "" : path}`;
|
|
353
|
+
function buildFetchUrl(baseUrl, prefix, path, args, pathPrefix = "") {
|
|
354
|
+
let fullPath = `/${pathPrefix}${prefix}${path === "/" ? "" : path}`;
|
|
346
355
|
if (args) {
|
|
347
356
|
fullPath = fullPath.replace(/:(\w+)/g, (_, key) => {
|
|
348
357
|
const val = args[key];
|
|
@@ -354,15 +363,15 @@ function buildFetchUrl(baseUrl, prefix, path, args) {
|
|
|
354
363
|
}
|
|
355
364
|
return `${baseUrl}${fullPath}`;
|
|
356
365
|
}
|
|
357
|
-
function stripParams(args, path) {
|
|
358
|
-
const
|
|
366
|
+
function stripParams(args, path, extra) {
|
|
367
|
+
const skip = new Set(extra);
|
|
359
368
|
for (const match of path.matchAll(/:(\w+)/g)) {
|
|
360
369
|
if (match[1])
|
|
361
|
-
|
|
370
|
+
skip.add(match[1]);
|
|
362
371
|
}
|
|
363
372
|
const result = {};
|
|
364
373
|
for (const [k, v] of Object.entries(args)) {
|
|
365
|
-
if (!
|
|
374
|
+
if (!skip.has(k))
|
|
366
375
|
result[k] = v;
|
|
367
376
|
}
|
|
368
377
|
return result;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
formatZodError,
|
|
10
10
|
normalizeError,
|
|
11
11
|
validateHandlerOutput
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-4843j09b.js";
|
|
13
13
|
import {
|
|
14
14
|
isUnsafeKey,
|
|
15
15
|
safeJsonParse
|
|
@@ -134,12 +134,12 @@ function toolResultFromError(err) {
|
|
|
134
134
|
async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false) {
|
|
135
135
|
const startedAt = Date.now();
|
|
136
136
|
const finish = async (result) => {
|
|
137
|
-
await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context);
|
|
137
|
+
await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context, method);
|
|
138
138
|
return result;
|
|
139
139
|
};
|
|
140
140
|
if (hooks?.beforeToolCall) {
|
|
141
141
|
try {
|
|
142
|
-
await hooks.beforeToolCall(toolName, rawArgs, context);
|
|
142
|
+
await hooks.beforeToolCall(toolName, rawArgs, context, method);
|
|
143
143
|
} catch (err) {
|
|
144
144
|
return finish(toolResultFromError(err));
|
|
145
145
|
}
|