stitchkit 0.25.0 → 0.26.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-multipart.d.ts +22 -0
- package/dist/browser/client-multipart.d.ts.map +1 -0
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/contract/define.d.ts +20 -0
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/factory.d.ts +1 -0
- package/dist/contract/factory.d.ts.map +1 -1
- package/dist/contract/index.js +1 -1
- package/dist/{index-4gawbm74.js → index-0d0rb85d.js} +41 -3
- package/dist/{index-g8kyab85.js → index-bkccbx64.js} +10 -3
- package/dist/{index-x62gnfsk.js → index-h4y2wg3n.js} +1 -1
- package/dist/{index-a9n8m4ec.js → index-p6fge9a5.js} +1 -1
- package/dist/{index-h9d1fm0p.js → index-q5w3cvvp.js} +62 -22
- package/dist/index.js +20 -18
- package/dist/internal/errors.d.ts +6 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/write-download.d.ts +17 -0
- package/dist/internal/write-download.d.ts.map +1 -0
- package/dist/node.js +2 -2
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +14 -3
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.js +6 -6
- package/dist/server/types.d.ts +13 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/agent.d.ts +2 -0
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +1 -1
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/list-names.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +10 -3
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount-download.d.ts.map +1 -1
- package/dist/tools/mount-upload.d.ts.map +1 -1
- package/dist/tools/mount-wait.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +13 -0
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/names.d.ts +34 -0
- package/dist/tools/names.d.ts.map +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools/transports.d.ts.map +1 -1
- package/dist/tools.js +48 -40
- package/llms-full.txt +97 -7
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multipart field encoding for the client — the platform-sensitive corner of
|
|
3
|
+
* `client.ts`, split out so the request-building logic there reads without it.
|
|
4
|
+
*
|
|
5
|
+
* Internal: none of this is public surface. The React Native descriptor path is
|
|
6
|
+
* the only genuinely subtle part, and keeping it together with its two guards
|
|
7
|
+
* makes that subtlety readable in one screen.
|
|
8
|
+
*/
|
|
9
|
+
import type { MultipartFile } from '../contract';
|
|
10
|
+
/** A multipart file field — a `Blob` (web / Bun) or a platform descriptor (RN). */
|
|
11
|
+
export declare function isMultipartFile(value: unknown): value is MultipartFile;
|
|
12
|
+
/**
|
|
13
|
+
* Append the file part. `FormData.append` is typed `(name, value: string | Blob)`
|
|
14
|
+
* by the DOM lib, but on React Native attaching a `{ uri, name, type }`
|
|
15
|
+
* descriptor is the native way to send a file (RN streams it from disk). Route
|
|
16
|
+
* through a structural type whose `append` also accepts a `FileDescriptor` —
|
|
17
|
+
* method-parameter bivariance lets the real `FormData` satisfy it, so the
|
|
18
|
+
* descriptor path stays cast-free. Web / Bun still pass a `Blob`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function appendMultipartFile(form: FormData, field: string, file: MultipartFile): void;
|
|
21
|
+
export declare function appendFormFields(formData: FormData, values: Record<string, unknown>, skipKeys: Set<string>): void;
|
|
22
|
+
//# sourceMappingURL=client-multipart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-multipart.d.ts","sourceRoot":"","sources":["../../src/browser/client-multipart.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,aAAa,CAAC;AAqBjE,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAG5F;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GACpB,IAAI,CAKN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAI/F,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;AA+EhB,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC1D,OAAO,GACP;KAAG,CAAC,IAAI,CAAC,GAAG,MAAM;CAAE,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK;IAC5D,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC;IAClE,eAAe,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAE9B,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,cAAc,EAAE,YAAY,GAAG,WAAW,EAC1C,cAAc,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GACvC,gBAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAepC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,EAC1E,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;CAAE,CAKzF"}
|
package/dist/cli.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
emitResult,
|
|
5
5
|
parseCliArgs,
|
|
6
6
|
pollUntilDone
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-q5w3cvvp.js";
|
|
8
8
|
import"./index-0ed3bx43.js";
|
|
9
|
-
import"./index-
|
|
9
|
+
import"./index-0d0rb85d.js";
|
|
10
10
|
import"./index-c7nyw0yt.js";
|
|
11
11
|
export {
|
|
12
12
|
pollUntilDone,
|
|
@@ -106,6 +106,16 @@ export type EndpointDef = HttpOnlyEndpointDef | ToolEndpointDef;
|
|
|
106
106
|
export interface ContractMeta<TScope extends string = string> {
|
|
107
107
|
prefix: string;
|
|
108
108
|
scope?: TScope;
|
|
109
|
+
/**
|
|
110
|
+
* Contract-wide default for every endpoint's opaque `meta` (→ ADR 0021).
|
|
111
|
+
* Endpoints **shallow-merge** over it, key by key — so a contract-wide
|
|
112
|
+
* `{ public: true }` survives an endpoint that adds `{ rateTier: 2 }`. One
|
|
113
|
+
* level only: no deep merge, no unset sentinel. → ADR 0036.
|
|
114
|
+
*
|
|
115
|
+
* `expose` deliberately has no equivalent — see ADR 0036 for why, and pin
|
|
116
|
+
* `listToolNames` in a snapshot to catch an endpoint that forgot it.
|
|
117
|
+
*/
|
|
118
|
+
meta?: Record<string, unknown>;
|
|
109
119
|
}
|
|
110
120
|
export interface ContractDef<T extends Record<string, EndpointDef> = Record<string, EndpointDef>, TScope extends string = string> {
|
|
111
121
|
meta: ContractMeta<TScope>;
|
|
@@ -119,11 +129,21 @@ export interface ContractDef<T extends Record<string, EndpointDef> = Record<stri
|
|
|
119
129
|
*/
|
|
120
130
|
export declare function defineContract<const T extends Record<string, EndpointDef>>(meta: {
|
|
121
131
|
prefix: string;
|
|
132
|
+
meta?: Record<string, unknown>;
|
|
122
133
|
}, endpoints: T): ContractDef<T, 'public'>;
|
|
123
134
|
export declare function defineContract<TScope extends string, const T extends Record<string, EndpointDef>>(meta: {
|
|
124
135
|
prefix: string;
|
|
125
136
|
scope: TScope;
|
|
137
|
+
meta?: Record<string, unknown>;
|
|
126
138
|
}, endpoints: T): ContractDef<T, TScope>;
|
|
139
|
+
/**
|
|
140
|
+
* Shallow-merge a contract-wide `meta` default with an endpoint's own — endpoint
|
|
141
|
+
* keys win. Returns `undefined` when neither side declares anything, because
|
|
142
|
+
* readers test `method.meta?.x` and an empty object would read as "declared".
|
|
143
|
+
* One level deep by design: a deep merge invites "how do I unset an inherited
|
|
144
|
+
* key", which has no answer without a sentinel. → ADR 0036.
|
|
145
|
+
*/
|
|
146
|
+
export declare function mergeMeta(contractMeta: Record<string, unknown> | undefined, endpointMeta: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
127
147
|
export interface RuntimeContext {
|
|
128
148
|
params: unknown;
|
|
129
149
|
input: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,eAAO,MAAM,cAAc,0CAA2C,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE/E,UAAU,eAAe;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;CAC3C;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,mBAAoB,SAAQ,eAAe;IACnD,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB;AAED,UAAU,eAAgB,SAAQ,eAAe;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,oEAAoE;IACpE,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAEhE,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/contract/define.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ import type { ContractDef, EndpointDef } from './define';
|
|
|
25
25
|
export type ScopedDefineContract<TScope extends string> = <const T extends Record<string, EndpointDef>>(meta: {
|
|
26
26
|
prefix: string;
|
|
27
27
|
scope: TScope;
|
|
28
|
+
meta?: Record<string, unknown>;
|
|
28
29
|
}, endpoints: T) => ContractDef<T, TScope>;
|
|
29
30
|
/**
|
|
30
31
|
* Build a `defineContract` that requires a `scope` from the application's own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGzD,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGzD,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACvE,SAAS,EAAE,CAAC,KACT,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,KAAK;IAC9D,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C,CAiBA"}
|
package/dist/contract/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord
|
|
3
|
+
} from "./index-c7nyw0yt.js";
|
|
4
|
+
|
|
1
5
|
// src/contract/errors.ts
|
|
2
6
|
var APP_ERROR_BRAND = Symbol.for("stitchkit.AppError");
|
|
3
7
|
|
|
@@ -64,6 +68,15 @@ function isStitchErrorCode(code) {
|
|
|
64
68
|
function appError(code, message, details) {
|
|
65
69
|
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
66
70
|
}
|
|
71
|
+
|
|
72
|
+
// src/contract/define.ts
|
|
73
|
+
function mergeMeta(contractMeta, endpointMeta) {
|
|
74
|
+
if (!contractMeta)
|
|
75
|
+
return endpointMeta;
|
|
76
|
+
if (!endpointMeta)
|
|
77
|
+
return { ...contractMeta };
|
|
78
|
+
return { ...contractMeta, ...endpointMeta };
|
|
79
|
+
}
|
|
67
80
|
// src/contract/pagination.ts
|
|
68
81
|
import { z } from "zod";
|
|
69
82
|
|
|
@@ -121,10 +134,35 @@ function normalizeError(err) {
|
|
|
121
134
|
console.error("[stitchkit] unhandled error:", err);
|
|
122
135
|
return new AppError("INTERNAL_SERVER_ERROR", "Internal server error", 500);
|
|
123
136
|
}
|
|
124
|
-
function
|
|
137
|
+
function strippedPaths(before, after, prefix) {
|
|
138
|
+
if (Array.isArray(before)) {
|
|
139
|
+
if (!Array.isArray(after))
|
|
140
|
+
return [];
|
|
141
|
+
return before.flatMap((item, i) => strippedPaths(item, after[i], `${prefix}[${i}]`));
|
|
142
|
+
}
|
|
143
|
+
if (!isRecord(before) || !isRecord(after))
|
|
144
|
+
return [];
|
|
145
|
+
const paths = [];
|
|
146
|
+
for (const [key, value] of Object.entries(before)) {
|
|
147
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
148
|
+
if (!(key in after)) {
|
|
149
|
+
paths.push(path);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
paths.push(...strippedPaths(value, after[key], path));
|
|
153
|
+
}
|
|
154
|
+
return paths;
|
|
155
|
+
}
|
|
156
|
+
function validateHandlerOutput(schema, data, onStripped) {
|
|
125
157
|
const parsed = schema.safeParse(data);
|
|
126
|
-
if (parsed.success)
|
|
158
|
+
if (parsed.success) {
|
|
159
|
+
if (onStripped) {
|
|
160
|
+
const paths = strippedPaths(data, parsed.data, "");
|
|
161
|
+
if (paths.length > 0)
|
|
162
|
+
onStripped(paths);
|
|
163
|
+
}
|
|
127
164
|
return { ok: true, data: parsed.data };
|
|
165
|
+
}
|
|
128
166
|
return {
|
|
129
167
|
ok: false,
|
|
130
168
|
message: `Handler output does not match the contract: ${formatZodError(parsed.error)}`
|
|
@@ -138,4 +176,4 @@ function isWithinDir(root, target) {
|
|
|
138
176
|
return target === root || target === base || target.startsWith(base + sep);
|
|
139
177
|
}
|
|
140
178
|
|
|
141
|
-
export { AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, bytesToBase64Url, base64UrlToBytes, formatZodError, zodIssues, errorCode, normalizeError, validateHandlerOutput, isWithinDir };
|
|
179
|
+
export { mergeMeta, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, bytesToBase64Url, base64UrlToBytes, formatZodError, zodIssues, errorCode, normalizeError, validateHandlerOutput, isWithinDir };
|
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
badRequest,
|
|
9
9
|
errorCode,
|
|
10
10
|
isWithinDir,
|
|
11
|
+
mergeMeta,
|
|
11
12
|
normalizeError,
|
|
12
13
|
validateHandlerOutput
|
|
13
|
-
} from "./index-
|
|
14
|
+
} from "./index-0d0rb85d.js";
|
|
14
15
|
import {
|
|
15
16
|
extractIp,
|
|
16
17
|
getClientInfo,
|
|
@@ -581,7 +582,13 @@ function createHandler(config) {
|
|
|
581
582
|
result = transformed;
|
|
582
583
|
}
|
|
583
584
|
if (method.outputSchema) {
|
|
584
|
-
const checked = validateHandlerOutput(method.outputSchema, result)
|
|
585
|
+
const checked = validateHandlerOutput(method.outputSchema, result, config.warnOnOutputStrip ? (paths) => {
|
|
586
|
+
const line = `[stitchkit] output strip ${method.serviceName}.${method.key}: ${paths.join(", ")}`;
|
|
587
|
+
if (customLogger)
|
|
588
|
+
customLogger.warn(line);
|
|
589
|
+
else
|
|
590
|
+
console.warn(line);
|
|
591
|
+
} : undefined);
|
|
585
592
|
if (!checked.ok) {
|
|
586
593
|
throw new AppError("INTERNAL_SERVER_ERROR", checked.message, 500);
|
|
587
594
|
}
|
|
@@ -692,7 +699,7 @@ function implement(contract, handlers) {
|
|
|
692
699
|
idempotent: endpoint.idempotent,
|
|
693
700
|
ui: "ui" in endpoint ? endpoint.ui : undefined,
|
|
694
701
|
annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
|
|
695
|
-
meta: endpoint.meta,
|
|
702
|
+
meta: mergeMeta(contract.meta.meta, endpoint.meta),
|
|
696
703
|
handler: (ctx) => typedHandler(ctx)
|
|
697
704
|
};
|
|
698
705
|
}
|
|
@@ -116,7 +116,7 @@ function createContractFactory() {
|
|
|
116
116
|
const validated = defineContract({ prefix: meta.prefix }, endpoints);
|
|
117
117
|
return {
|
|
118
118
|
endpoints: validated.endpoints,
|
|
119
|
-
meta: { prefix: meta.prefix, scope: meta.scope }
|
|
119
|
+
meta: { ...meta, prefix: meta.prefix, scope: meta.scope }
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
122
|
};
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
isWithinDir,
|
|
8
8
|
normalizeError,
|
|
9
9
|
validateHandlerOutput
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-0d0rb85d.js";
|
|
11
11
|
import {
|
|
12
12
|
isRecord,
|
|
13
13
|
isUnsafeKey,
|
|
@@ -346,7 +346,7 @@ function toolResultFromError(err) {
|
|
|
346
346
|
...appErr.hint && { hint: appErr.hint }
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
|
-
async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false) {
|
|
349
|
+
async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false, onOutputStrip) {
|
|
350
350
|
const startedAt = Date.now();
|
|
351
351
|
const finish = async (result) => {
|
|
352
352
|
await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context, method);
|
|
@@ -410,7 +410,7 @@ async function executeToolMethod(method, toolName, rawArgs, context, hooks, life
|
|
|
410
410
|
data = transformed;
|
|
411
411
|
}
|
|
412
412
|
if (method.outputSchema) {
|
|
413
|
-
const checked = validateHandlerOutput(method.outputSchema, data);
|
|
413
|
+
const checked = validateHandlerOutput(method.outputSchema, data, onOutputStrip);
|
|
414
414
|
if (!checked.ok) {
|
|
415
415
|
return finish({
|
|
416
416
|
ok: false,
|
|
@@ -437,6 +437,13 @@ var SINGULAR_EXCEPTIONS = new Set([
|
|
|
437
437
|
"progress",
|
|
438
438
|
"news"
|
|
439
439
|
]);
|
|
440
|
+
var TOOL_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
441
|
+
function normalizeService(value) {
|
|
442
|
+
return value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
443
|
+
}
|
|
444
|
+
function normalizeMethod(value) {
|
|
445
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
446
|
+
}
|
|
440
447
|
function singularize(name) {
|
|
441
448
|
if (SINGULAR_EXCEPTIONS.has(name))
|
|
442
449
|
return name;
|
|
@@ -446,22 +453,44 @@ function singularize(name) {
|
|
|
446
453
|
return name.slice(0, -1);
|
|
447
454
|
return name;
|
|
448
455
|
}
|
|
456
|
+
function singularizeTail(name) {
|
|
457
|
+
const cut = name.lastIndexOf("_");
|
|
458
|
+
if (cut === -1)
|
|
459
|
+
return singularize(name);
|
|
460
|
+
return `${name.slice(0, cut + 1)}${singularize(name.slice(cut + 1))}`;
|
|
461
|
+
}
|
|
462
|
+
function hasUsableChars(value) {
|
|
463
|
+
return /[a-zA-Z0-9]/.test(value);
|
|
464
|
+
}
|
|
465
|
+
function assertToolName(name, serviceName, key) {
|
|
466
|
+
const where = `service "${serviceName}", method "${key}"`;
|
|
467
|
+
if (!TOOL_NAME_RE.test(name)) {
|
|
468
|
+
const why = name.length > 64 ? `is ${name.length} characters (max 64) — set an explicit \`toolName\`` : "must match [a-zA-Z0-9_-]";
|
|
469
|
+
throw new Error(`Tool name "${name}" (${where}) ${why}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
449
472
|
function toToolName(serviceName, methodName) {
|
|
450
|
-
const normalized = serviceName
|
|
451
|
-
const singular =
|
|
452
|
-
|
|
473
|
+
const normalized = normalizeService(serviceName);
|
|
474
|
+
const singular = singularizeTail(normalized);
|
|
475
|
+
const method = normalizeMethod(methodName);
|
|
476
|
+
if (method === "list")
|
|
453
477
|
return `list_${normalized}`;
|
|
454
|
-
if (
|
|
478
|
+
if (method === "get")
|
|
455
479
|
return `get_${singular}`;
|
|
456
|
-
if (
|
|
480
|
+
if (method === "create")
|
|
457
481
|
return `create_${singular}`;
|
|
458
|
-
if (
|
|
482
|
+
if (method === "update")
|
|
459
483
|
return `update_${singular}`;
|
|
460
|
-
if (
|
|
484
|
+
if (method === "delete")
|
|
461
485
|
return `delete_${singular}`;
|
|
462
|
-
const snake =
|
|
486
|
+
const snake = method.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
463
487
|
return `${snake}_${singular}`.replace(/^_/, "");
|
|
464
488
|
}
|
|
489
|
+
function assertUniqueToolName(name, taken, surface) {
|
|
490
|
+
if (taken) {
|
|
491
|
+
throw new Error(`Duplicate ${surface} "${name}" across mounted services`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
465
494
|
|
|
466
495
|
// src/tools/mount.ts
|
|
467
496
|
function applyExtend(base, extra) {
|
|
@@ -475,7 +504,7 @@ function applyExtend(base, extra) {
|
|
|
475
504
|
return z4.intersection(z4.object(extra), base);
|
|
476
505
|
}
|
|
477
506
|
function collectTools(service, transport, config = {}) {
|
|
478
|
-
const { extend, flattenUnionInput = false } = config;
|
|
507
|
+
const { extend, flattenUnionInput = false, assertNames = true } = config;
|
|
479
508
|
const tools = [];
|
|
480
509
|
for (const [methodName, method] of Object.entries(service.methods)) {
|
|
481
510
|
if (transport === "CLI") {
|
|
@@ -487,6 +516,12 @@ function collectTools(service, transport, config = {}) {
|
|
|
487
516
|
if (method.multipart)
|
|
488
517
|
continue;
|
|
489
518
|
const name = method.toolName ?? toToolName(service.name, methodName);
|
|
519
|
+
if (assertNames && transport !== "CLI") {
|
|
520
|
+
if (!method.toolName && !hasUsableChars(service.name)) {
|
|
521
|
+
throw new Error(`Service prefix "${service.name}" (method "${methodName}") has no characters usable in a tool name — set an explicit \`toolName\` or rename the prefix`);
|
|
522
|
+
}
|
|
523
|
+
assertToolName(name, service.name, methodName);
|
|
524
|
+
}
|
|
490
525
|
const baseSchema = flattenUnionInput ? mergeSchemas(method.paramsSchema ? flattenUnionsDeep(method.paramsSchema) : undefined, method.inputSchema ? flattenUnionsDeep(method.inputSchema) : undefined) : mergeSchemas(method.paramsSchema, method.inputSchema);
|
|
491
526
|
const shouldExtend = !!extend && (!extend.filter || extend.filter(service, method));
|
|
492
527
|
const schema = shouldExtend && extend ? applyExtend(baseSchema, extend.schema) : baseSchema;
|
|
@@ -502,7 +537,7 @@ function createToolRunner(config) {
|
|
|
502
537
|
extraContext = await config.extend.resolve(rawArgs);
|
|
503
538
|
}
|
|
504
539
|
const cleanArgs = tool.shouldExtend && extendKeys ? Object.fromEntries(Object.entries(rawArgs).filter(([key]) => !extendKeys.has(key))) : rawArgs;
|
|
505
|
-
return executeToolMethod(tool.method, tool.name, cleanArgs, { ...config.context, ...extraContext, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true);
|
|
540
|
+
return executeToolMethod(tool.method, tool.name, cleanArgs, { ...config.context, ...extraContext, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(tool.name, paths) : undefined);
|
|
506
541
|
};
|
|
507
542
|
}
|
|
508
543
|
function formatToolError(result, toolName, errorHint) {
|
|
@@ -845,7 +880,6 @@ async function pollUntilDone(params) {
|
|
|
845
880
|
}
|
|
846
881
|
|
|
847
882
|
// src/tools/cli.ts
|
|
848
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
849
883
|
import { basename, resolve } from "node:path";
|
|
850
884
|
import process from "node:process";
|
|
851
885
|
|
|
@@ -962,6 +996,17 @@ async function readCapped(res, max) {
|
|
|
962
996
|
return Buffer.concat(chunks);
|
|
963
997
|
}
|
|
964
998
|
|
|
999
|
+
// src/internal/write-download.ts
|
|
1000
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
1001
|
+
import { dirname } from "node:path";
|
|
1002
|
+
async function writeDownload(root, target, data) {
|
|
1003
|
+
if (!isWithinDir(root, target)) {
|
|
1004
|
+
throw new Error("download name escapes the output dir");
|
|
1005
|
+
}
|
|
1006
|
+
await mkdir(dirname(target), { recursive: true });
|
|
1007
|
+
await writeFile(target, data);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
965
1010
|
// src/tools/cli.ts
|
|
966
1011
|
var GLOBAL_OPTIONS = [
|
|
967
1012
|
["--json", "Emit raw JSON on stdout (for piping / scripts)"],
|
|
@@ -1085,7 +1130,6 @@ function renderCommandHelp(name, command, tool) {
|
|
|
1085
1130
|
var DEFAULT_DOWNLOAD_MAX_BYTES = 100 * 1024 * 1024;
|
|
1086
1131
|
async function downloadResults(files, dir, stderr, quiet, allowPrivate, maxBytes) {
|
|
1087
1132
|
const root = resolve(dir);
|
|
1088
|
-
await mkdir(root, { recursive: true });
|
|
1089
1133
|
for (const file of files) {
|
|
1090
1134
|
try {
|
|
1091
1135
|
const res = await fetchGuarded(new URL(file.url), allowPrivate);
|
|
@@ -1095,9 +1139,7 @@ async function downloadResults(files, dir, stderr, quiet, allowPrivate, maxBytes
|
|
|
1095
1139
|
if (!buffer)
|
|
1096
1140
|
throw new Error(`file exceeds the ${maxBytes}-byte cap`);
|
|
1097
1141
|
const target = resolve(root, basename(file.name));
|
|
1098
|
-
|
|
1099
|
-
throw new Error("download name escapes the output dir");
|
|
1100
|
-
await writeFile(target, buffer);
|
|
1142
|
+
await writeDownload(root, target, buffer);
|
|
1101
1143
|
if (!quiet)
|
|
1102
1144
|
stderr(`saved ${target} (${(buffer.length / 1024).toFixed(0)}KB)
|
|
1103
1145
|
`);
|
|
@@ -1119,9 +1161,7 @@ async function createCli(config) {
|
|
|
1119
1161
|
const tools = new Map;
|
|
1120
1162
|
for (const service of services) {
|
|
1121
1163
|
for (const mountable of collectTools(service, "CLI")) {
|
|
1122
|
-
|
|
1123
|
-
throw new Error(`Duplicate CLI command "${mountable.name}" across mounted services`);
|
|
1124
|
-
}
|
|
1164
|
+
assertUniqueToolName(mountable.name, tools.has(mountable.name), "CLI command");
|
|
1125
1165
|
tools.set(mountable.name, mountable);
|
|
1126
1166
|
}
|
|
1127
1167
|
}
|
|
@@ -1216,4 +1256,4 @@ function safeInputSchema(tool) {
|
|
|
1216
1256
|
}
|
|
1217
1257
|
}
|
|
1218
1258
|
|
|
1219
|
-
export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, flattenUnionsDeep, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
|
|
1259
|
+
export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, flattenUnionsDeep, assertToolName, assertUniqueToolName, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, writeDownload, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
paginatedSchema,
|
|
17
17
|
rateLimited,
|
|
18
18
|
unauthorized
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-h4y2wg3n.js";
|
|
20
20
|
import {
|
|
21
21
|
isRecord,
|
|
22
22
|
mapObject,
|
|
@@ -28,6 +28,25 @@ function inputIsQuery(method) {
|
|
|
28
28
|
return method === "GET" || method === "DELETE";
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// src/browser/client-multipart.ts
|
|
32
|
+
function isFileDescriptor(value) {
|
|
33
|
+
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";
|
|
34
|
+
}
|
|
35
|
+
function isMultipartFile(value) {
|
|
36
|
+
return value instanceof Blob || isFileDescriptor(value);
|
|
37
|
+
}
|
|
38
|
+
function appendMultipartFile(form, field, file) {
|
|
39
|
+
const sink = form;
|
|
40
|
+
sink.append(field, file);
|
|
41
|
+
}
|
|
42
|
+
function appendFormFields(formData, values, skipKeys) {
|
|
43
|
+
for (const [key, value] of Object.entries(values)) {
|
|
44
|
+
if (skipKeys.has(key) || value === undefined || value === null)
|
|
45
|
+
continue;
|
|
46
|
+
formData.append(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
31
50
|
// src/browser/http.ts
|
|
32
51
|
import ky, { isHTTPError } from "ky";
|
|
33
52
|
|
|
@@ -407,23 +426,6 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
407
426
|
return endpoint.output ? endpoint.output.parse(json) : json;
|
|
408
427
|
};
|
|
409
428
|
}
|
|
410
|
-
function isFileDescriptor(value) {
|
|
411
|
-
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";
|
|
412
|
-
}
|
|
413
|
-
function isMultipartFile(value) {
|
|
414
|
-
return value instanceof Blob || isFileDescriptor(value);
|
|
415
|
-
}
|
|
416
|
-
function appendMultipartFile(form, field, file) {
|
|
417
|
-
const sink = form;
|
|
418
|
-
sink.append(field, file);
|
|
419
|
-
}
|
|
420
|
-
function appendFormFields(formData, values, skipKeys) {
|
|
421
|
-
for (const [key, value] of Object.entries(values)) {
|
|
422
|
-
if (skipKeys.has(key) || value === undefined || value === null)
|
|
423
|
-
continue;
|
|
424
|
-
formData.append(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
429
|
async function throwForErrorResponse(res, config, fallbackBody) {
|
|
428
430
|
const body = await res.json().catch(() => fallbackBody);
|
|
429
431
|
config.onError?.(res.status, body);
|
|
@@ -29,8 +29,13 @@ export declare function normalizeError(err: unknown): AppError;
|
|
|
29
29
|
* Validate a handler's return value against the contract `output` schema. A
|
|
30
30
|
* mismatch is a **server** fault (the handler broke its own contract) — shared
|
|
31
31
|
* by the HTTP and tool transports so both report it identically.
|
|
32
|
+
*
|
|
33
|
+
* `onStripped` is the migration diagnostic: a handler returning more than its
|
|
34
|
+
* contract declares has the extra fields **deleted**, correctly but invisibly —
|
|
35
|
+
* types cannot catch it (structural typing does not reject excess properties) and
|
|
36
|
+
* nothing logs it. Pass a reporter to find out; omit it and nothing is computed.
|
|
32
37
|
*/
|
|
33
|
-
export declare function validateHandlerOutput(schema: ZodType, data: unknown): {
|
|
38
|
+
export declare function validateHandlerOutput(schema: ZodType, data: unknown, onStripped?: (paths: string[]) => void): {
|
|
34
39
|
ok: true;
|
|
35
40
|
data: unknown;
|
|
36
41
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAMxD;AAED,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,eAAe,EAAE,CAM9D;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAI1D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAgBrD;AA4BD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,OAAO,EACb,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAe9D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write a downloaded body to disk, with the containment check both download
|
|
3
|
+
* paths need.
|
|
4
|
+
*
|
|
5
|
+
* Shared by the CLI's `--output-dir` and the `mountDownload` native tool. It
|
|
6
|
+
* deliberately takes an **already-resolved** target rather than building one:
|
|
7
|
+
* the two callers derive the filename differently (an untrusted `file.name` vs a
|
|
8
|
+
* name derived from the URL) and, more importantly, report the path back to the
|
|
9
|
+
* user — so composing it here would silently change one of those outputs from
|
|
10
|
+
* relative to absolute.
|
|
11
|
+
*
|
|
12
|
+
* The containment re-check is cheap and belongs on this side: both callers reduce
|
|
13
|
+
* the name to a basename first, but that is an invariant of *their* code, and
|
|
14
|
+
* this is where the write actually happens.
|
|
15
|
+
*/
|
|
16
|
+
export declare function writeDownload(root: string, target: string, data: Uint8Array): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=write-download.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-download.d.ts","sourceRoot":"","sources":["../../src/internal/write-download.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
package/dist/node.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createImplement,
|
|
4
4
|
createSocketIOServer,
|
|
5
5
|
implement
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-bkccbx64.js";
|
|
7
7
|
import"./index-tje0q6gp.js";
|
|
8
8
|
import {
|
|
9
9
|
AppError,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
notFound,
|
|
15
15
|
rateLimited,
|
|
16
16
|
unauthorized
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-0d0rb85d.js";
|
|
18
18
|
import"./index-dzx781tm.js";
|
|
19
19
|
import"./index-khwedj16.js";
|
|
20
20
|
import"./index-c7nyw0yt.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA0OxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
|
|
@@ -22,11 +22,16 @@
|
|
|
22
22
|
* CONFLICT: 'conflict', RATE_LIMITED: 'rate_limited',
|
|
23
23
|
* INTERNAL_SERVER_ERROR: 'internal',
|
|
24
24
|
* } satisfies Record<StitchErrorCode, string>,
|
|
25
|
-
* render: (info) => ({
|
|
25
|
+
* render: (info, ctx) => ({
|
|
26
|
+
* ok: false,
|
|
27
|
+
* error: { code: info.code, message: info.message },
|
|
28
|
+
* traceId: ctx.traceId,
|
|
29
|
+
* }),
|
|
26
30
|
* });
|
|
27
31
|
* createServer({ services, hooks: { onError } });
|
|
28
32
|
* ```
|
|
29
33
|
*/
|
|
34
|
+
import type { RuntimeContext } from '../contract';
|
|
30
35
|
import { type StitchErrorCode } from '../contract';
|
|
31
36
|
import type { LifecycleHooks } from './types';
|
|
32
37
|
/** The normalised error handed to `render` — code already remapped. */
|
|
@@ -51,9 +56,15 @@ export interface ErrorHookConfig<TWireCode extends string = string> {
|
|
|
51
56
|
*/
|
|
52
57
|
codeMap?: Record<StitchErrorCode, TWireCode>;
|
|
53
58
|
/** Build the response body from the resolved error. */
|
|
54
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Build the response body from the resolved error. `ctx` is the request's
|
|
61
|
+
* `RuntimeContext` — read `ctx.traceId` / `ctx.spanId` to put a correlation id
|
|
62
|
+
* in the envelope, which is the ordinary reason to have one. Declaring the
|
|
63
|
+
* parameter is optional: a one-argument `render` stays assignable.
|
|
64
|
+
*/
|
|
65
|
+
render: (info: ResolvedError, ctx: RuntimeContext) => unknown;
|
|
55
66
|
/** Observe the raw thrown value before rendering — logging / metrics. */
|
|
56
|
-
onError?: (error: unknown, info: ResolvedError) => void;
|
|
67
|
+
onError?: (error: unknown, info: ResolvedError, ctx: RuntimeContext) => void;
|
|
57
68
|
}
|
|
58
69
|
/** Build an `onError` hook from a code map + envelope renderer. */
|
|
59
70
|
export declare function createErrorHook<TWireCode extends string = string>(config: ErrorHookConfig<TWireCode>): NonNullable<LifecycleHooks['onError']>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-hook.d.ts","sourceRoot":"","sources":["../../src/server/error-hook.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"error-hook.d.ts","sourceRoot":"","sources":["../../src/server/error-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IAChE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAC7C,uDAAuD;IACvD;;;;;OAKG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC;IAC9D,yEAAyE;IACzE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;CAC9E;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAC/D,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAyBxC"}
|
|
@@ -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;
|
|
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;AAG5E,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,CAgD3E;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"}
|