stitchkit 0.17.0 → 0.18.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/http.d.ts +9 -0
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/{index-6k6y7wat.js → index-6qv1fxqy.js} +1 -1
- package/dist/{index-fwqnkc90.js → index-dz2k8d5h.js} +4 -40
- package/dist/index-khwedj16.js +40 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -14
- package/dist/node.js +3 -2
- package/dist/observability/index.js +8 -6
- package/dist/server/index.js +3 -2
- package/dist/tools/list-names.d.ts +33 -0
- package/dist/tools/list-names.d.ts.map +1 -0
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +43 -14
- package/llms-full.txt +72 -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,EACV,WAAW,EACX,WAAW,EAGX,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,UAAU,IAAI,WAAW,EAG/B,MAAM,QAAQ,CAAC;
|
|
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;AAkEhB,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/browser/http.d.ts
CHANGED
|
@@ -50,6 +50,15 @@ export interface HttpClientConfig {
|
|
|
50
50
|
* request — use it for runtime tokens (e.g. a short-lived auth token).
|
|
51
51
|
*/
|
|
52
52
|
headers?: HeaderProvider;
|
|
53
|
+
/**
|
|
54
|
+
* Emit a W3C `traceparent` header on every request — a fresh root trace per
|
|
55
|
+
* request. The stitchkit server continues an inbound `traceparent`
|
|
56
|
+
* (`resolveTraceContext`), so with this on, a browser call, its HTTP handler
|
|
57
|
+
* and every nested tool call share one trace id end-to-end. A `traceparent`
|
|
58
|
+
* already set (via `headers`) wins — the client never overwrites it.
|
|
59
|
+
* Default `false`.
|
|
60
|
+
*/
|
|
61
|
+
trace?: boolean;
|
|
53
62
|
}
|
|
54
63
|
type ParamValue = string | number | boolean | undefined;
|
|
55
64
|
type ParamArrayValue = Array<string | number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/browser/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveTraceContext
|
|
3
|
+
} from "./index-khwedj16.js";
|
|
1
4
|
import {
|
|
2
5
|
isRecord,
|
|
3
6
|
isUnsafeKey
|
|
@@ -55,45 +58,6 @@ function parseQueryParams(url) {
|
|
|
55
58
|
return query;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
// src/observability/trace.ts
|
|
59
|
-
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
60
|
-
function randomHex(bytes) {
|
|
61
|
-
const arr = new Uint8Array(bytes);
|
|
62
|
-
crypto.getRandomValues(arr);
|
|
63
|
-
let hex = "";
|
|
64
|
-
for (const byte of arr)
|
|
65
|
-
hex += byte.toString(16).padStart(2, "0");
|
|
66
|
-
return hex;
|
|
67
|
-
}
|
|
68
|
-
function createTraceContext() {
|
|
69
|
-
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
70
|
-
}
|
|
71
|
-
function parseTraceparent(header) {
|
|
72
|
-
if (!header)
|
|
73
|
-
return null;
|
|
74
|
-
const match = TRACEPARENT_RE.exec(header.trim());
|
|
75
|
-
if (!match?.[1] || !match[2])
|
|
76
|
-
return null;
|
|
77
|
-
const traceId = match[1].toLowerCase();
|
|
78
|
-
const parentSpanId = match[2].toLowerCase();
|
|
79
|
-
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
80
|
-
return null;
|
|
81
|
-
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
82
|
-
}
|
|
83
|
-
function formatTraceparent(ctx) {
|
|
84
|
-
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
85
|
-
}
|
|
86
|
-
function resolveTraceContext(req) {
|
|
87
|
-
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
88
|
-
}
|
|
89
|
-
function childSpan(parent) {
|
|
90
|
-
return {
|
|
91
|
-
traceId: parent.traceId,
|
|
92
|
-
spanId: randomHex(8),
|
|
93
|
-
parentSpanId: parent.spanId
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
61
|
// src/observability/context.ts
|
|
98
62
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
99
63
|
var storage = new AsyncLocalStorage;
|
|
@@ -148,4 +112,4 @@ function wrapInRequestContext(handler, options = {}) {
|
|
|
148
112
|
};
|
|
149
113
|
}
|
|
150
114
|
|
|
151
|
-
export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams,
|
|
115
|
+
export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/observability/trace.ts
|
|
2
|
+
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
3
|
+
function randomHex(bytes) {
|
|
4
|
+
const arr = new Uint8Array(bytes);
|
|
5
|
+
crypto.getRandomValues(arr);
|
|
6
|
+
let hex = "";
|
|
7
|
+
for (const byte of arr)
|
|
8
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
9
|
+
return hex;
|
|
10
|
+
}
|
|
11
|
+
function createTraceContext() {
|
|
12
|
+
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
13
|
+
}
|
|
14
|
+
function parseTraceparent(header) {
|
|
15
|
+
if (!header)
|
|
16
|
+
return null;
|
|
17
|
+
const match = TRACEPARENT_RE.exec(header.trim());
|
|
18
|
+
if (!match?.[1] || !match[2])
|
|
19
|
+
return null;
|
|
20
|
+
const traceId = match[1].toLowerCase();
|
|
21
|
+
const parentSpanId = match[2].toLowerCase();
|
|
22
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
23
|
+
return null;
|
|
24
|
+
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
25
|
+
}
|
|
26
|
+
function formatTraceparent(ctx) {
|
|
27
|
+
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
28
|
+
}
|
|
29
|
+
function resolveTraceContext(req) {
|
|
30
|
+
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
31
|
+
}
|
|
32
|
+
function childSpan(parent) {
|
|
33
|
+
return {
|
|
34
|
+
traceId: parent.traceId,
|
|
35
|
+
spanId: randomHex(8),
|
|
36
|
+
parentSpanId: parent.spanId
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ 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 { childSpan, createTraceContext, formatTraceparent, parseTraceparent, type TraceContext, } from './observability/trace';
|
|
7
8
|
export { createRetainedTopics, type RetainedTopics } from './retained';
|
|
8
9
|
//# 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;AAG3B,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,44 @@ function mapObject(source, mapper) {
|
|
|
40
40
|
|
|
41
41
|
// src/browser/http.ts
|
|
42
42
|
import ky, { isHTTPError } from "ky";
|
|
43
|
+
|
|
44
|
+
// src/observability/trace.ts
|
|
45
|
+
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
46
|
+
function randomHex(bytes) {
|
|
47
|
+
const arr = new Uint8Array(bytes);
|
|
48
|
+
crypto.getRandomValues(arr);
|
|
49
|
+
let hex = "";
|
|
50
|
+
for (const byte of arr)
|
|
51
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
52
|
+
return hex;
|
|
53
|
+
}
|
|
54
|
+
function createTraceContext() {
|
|
55
|
+
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
56
|
+
}
|
|
57
|
+
function parseTraceparent(header) {
|
|
58
|
+
if (!header)
|
|
59
|
+
return null;
|
|
60
|
+
const match = TRACEPARENT_RE.exec(header.trim());
|
|
61
|
+
if (!match?.[1] || !match[2])
|
|
62
|
+
return null;
|
|
63
|
+
const traceId = match[1].toLowerCase();
|
|
64
|
+
const parentSpanId = match[2].toLowerCase();
|
|
65
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
66
|
+
return null;
|
|
67
|
+
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
68
|
+
}
|
|
69
|
+
function formatTraceparent(ctx) {
|
|
70
|
+
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
71
|
+
}
|
|
72
|
+
function childSpan(parent) {
|
|
73
|
+
return {
|
|
74
|
+
traceId: parent.traceId,
|
|
75
|
+
spanId: randomHex(8),
|
|
76
|
+
parentSpanId: parent.spanId
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/browser/http.ts
|
|
43
81
|
class ApiError extends Error {
|
|
44
82
|
code;
|
|
45
83
|
status;
|
|
@@ -104,6 +142,9 @@ function createHttpClient(config) {
|
|
|
104
142
|
request2.headers.set(key, value);
|
|
105
143
|
}
|
|
106
144
|
}
|
|
145
|
+
if (config.trace && !request2.headers.has("traceparent")) {
|
|
146
|
+
request2.headers.set("traceparent", formatTraceparent(createTraceContext()));
|
|
147
|
+
}
|
|
107
148
|
}
|
|
108
149
|
],
|
|
109
150
|
afterResponse: [
|
|
@@ -206,7 +247,7 @@ function withTimeout(options, timeout) {
|
|
|
206
247
|
function isParamArray(value) {
|
|
207
248
|
return Array.isArray(value) && value.every((v) => typeof v === "string" || typeof v === "number");
|
|
208
249
|
}
|
|
209
|
-
function collectQueryParams(args, skipKeys) {
|
|
250
|
+
function collectQueryParams(args, skipKeys, endpoint) {
|
|
210
251
|
const params = {};
|
|
211
252
|
let hasParams = false;
|
|
212
253
|
for (const [key, value] of Object.entries(args)) {
|
|
@@ -215,7 +256,10 @@ function collectQueryParams(args, skipKeys) {
|
|
|
215
256
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isParamArray(value)) {
|
|
216
257
|
params[key] = value;
|
|
217
258
|
hasParams = true;
|
|
259
|
+
continue;
|
|
218
260
|
}
|
|
261
|
+
const what = Array.isArray(value) ? "an array with non-primitive items" : typeof value === "object" ? "a nested object" : `a ${typeof value}`;
|
|
262
|
+
throw new Error(`${endpoint.method} ${endpoint.path}: input field "${key}" is ${what} — it cannot ` + "travel as a query parameter. GET / DELETE input must be flat (string / number / " + "boolean, or an array of string / number); flatten the field or move the " + "operation to a body verb (POST).");
|
|
219
263
|
}
|
|
220
264
|
return hasParams ? params : undefined;
|
|
221
265
|
}
|
|
@@ -272,11 +316,11 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
272
316
|
return client.post(url, formData, withTimeout(undefined, endpoint.timeout));
|
|
273
317
|
}
|
|
274
318
|
if (isGet) {
|
|
275
|
-
const params = collectQueryParams(firstArg, prefixKeys);
|
|
319
|
+
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
276
320
|
return client.get(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
277
321
|
}
|
|
278
322
|
if (httpMethod === "delete") {
|
|
279
|
-
const params = collectQueryParams(firstArg, prefixKeys);
|
|
323
|
+
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
280
324
|
return client.delete(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
281
325
|
}
|
|
282
326
|
const payload = {};
|
|
@@ -306,19 +350,19 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
306
350
|
const hasBody = !isQuery && !endpoint.multipart && endpoint.input && args;
|
|
307
351
|
if (isQuery && args) {
|
|
308
352
|
const remaining = stripParams(args, endpoint.path, prefixKeys);
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
353
|
+
const params = collectQueryParams(remaining, new Set, endpoint);
|
|
354
|
+
if (params) {
|
|
355
|
+
const searchParams = new URLSearchParams;
|
|
356
|
+
for (const [k, v] of Object.entries(params)) {
|
|
357
|
+
if (Array.isArray(v)) {
|
|
358
|
+
for (const item of v)
|
|
359
|
+
searchParams.append(k, String(item));
|
|
360
|
+
} else {
|
|
361
|
+
searchParams.set(k, String(v));
|
|
362
|
+
}
|
|
318
363
|
}
|
|
319
|
-
}
|
|
320
|
-
if (searchParams.size > 0)
|
|
321
364
|
url += `?${searchParams}`;
|
|
365
|
+
}
|
|
322
366
|
}
|
|
323
367
|
if (hasBody)
|
|
324
368
|
headers["Content-Type"] = "application/json";
|
|
@@ -596,20 +640,24 @@ async function* parseSSE(response, options) {
|
|
|
596
640
|
export {
|
|
597
641
|
unauthorized,
|
|
598
642
|
rateLimited,
|
|
643
|
+
parseTraceparent,
|
|
599
644
|
parseSSE,
|
|
600
645
|
paginatedSchema,
|
|
601
646
|
notFound,
|
|
602
647
|
isStitchErrorCode,
|
|
648
|
+
formatTraceparent,
|
|
603
649
|
forbidden,
|
|
604
650
|
encodeCursor,
|
|
605
651
|
defineContract,
|
|
606
652
|
decodeCursor,
|
|
653
|
+
createTraceContext,
|
|
607
654
|
createSocketIOClient,
|
|
608
655
|
createRetainedTopics,
|
|
609
656
|
createHttpClient,
|
|
610
657
|
createClients,
|
|
611
658
|
createClient,
|
|
612
659
|
conflict,
|
|
660
|
+
childSpan,
|
|
613
661
|
badRequest,
|
|
614
662
|
appError,
|
|
615
663
|
STITCH_ERROR_STATUS,
|
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-6qv1fxqy.js";
|
|
7
7
|
import {
|
|
8
8
|
AppError,
|
|
9
9
|
appError,
|
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
rateLimited,
|
|
15
15
|
unauthorized
|
|
16
16
|
} from "./index-ktn76xz0.js";
|
|
17
|
-
import"./index-
|
|
17
|
+
import"./index-dz2k8d5h.js";
|
|
18
|
+
import"./index-khwedj16.js";
|
|
18
19
|
import"./index-tm7dqzxc.js";
|
|
19
20
|
// src/server/node.ts
|
|
20
21
|
import { serve } from "srvx";
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
childSpan,
|
|
3
|
-
createTraceContext,
|
|
4
|
-
formatTraceparent,
|
|
5
2
|
getRequestContext,
|
|
6
3
|
getTraceId,
|
|
7
4
|
getUserId,
|
|
8
|
-
parseTraceparent,
|
|
9
|
-
resolveTraceContext,
|
|
10
5
|
runWithRequestContext,
|
|
11
6
|
setRequestDimensions,
|
|
12
7
|
setRequestEndpoint,
|
|
13
8
|
setRequestError,
|
|
14
9
|
setRequestUser,
|
|
15
10
|
wrapInRequestContext
|
|
16
|
-
} from "../index-
|
|
11
|
+
} from "../index-dz2k8d5h.js";
|
|
12
|
+
import {
|
|
13
|
+
childSpan,
|
|
14
|
+
createTraceContext,
|
|
15
|
+
formatTraceparent,
|
|
16
|
+
parseTraceparent,
|
|
17
|
+
resolveTraceContext
|
|
18
|
+
} from "../index-khwedj16.js";
|
|
17
19
|
import {
|
|
18
20
|
isRecord,
|
|
19
21
|
isUnsafeKey
|
package/dist/server/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
socketIoLane,
|
|
13
13
|
staticRoute,
|
|
14
14
|
webSocketLane
|
|
15
|
-
} from "../index-
|
|
15
|
+
} from "../index-6qv1fxqy.js";
|
|
16
16
|
import {
|
|
17
17
|
createAuthHook,
|
|
18
18
|
createBearerResolver,
|
|
@@ -50,7 +50,8 @@ import {
|
|
|
50
50
|
getTraceId,
|
|
51
51
|
resolveSocketIp,
|
|
52
52
|
resolveTraceId
|
|
53
|
-
} from "../index-
|
|
53
|
+
} from "../index-dz2k8d5h.js";
|
|
54
|
+
import"../index-khwedj16.js";
|
|
54
55
|
import {
|
|
55
56
|
isRecord
|
|
56
57
|
} from "../index-tm7dqzxc.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-name baseline — the final mounted name of every tool across the tool
|
|
3
|
+
* transports, with its `(service, method)` identity. Tool names are partly
|
|
4
|
+
* derived (`toolName` override, else `toToolName(service, method)`), so a
|
|
5
|
+
* consumer pins them with a snapshot test / CI diff: an upgrade that would
|
|
6
|
+
* shift a derived name — and silently break MCP client configs — fails the
|
|
7
|
+
* consumer's build instead. Also the mechanical "what changed" diff when
|
|
8
|
+
* migrating a service between contract shapes.
|
|
9
|
+
*
|
|
10
|
+
* Built on `collectTools`, the exact resolver `mountMcp` / `mountAgent` /
|
|
11
|
+
* `createCli` use — the listing can never drift from what actually mounts.
|
|
12
|
+
*/
|
|
13
|
+
import type { Transport } from '../contract';
|
|
14
|
+
import type { ServiceDef } from '../server/types';
|
|
15
|
+
/** One mounted tool name and where it comes from. */
|
|
16
|
+
export interface ToolNameEntry {
|
|
17
|
+
/** Final tool name — the `toolName` override, else derived from service + method. */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Owning service (`ServiceDef.name` — the contract's prefix). */
|
|
20
|
+
service: string;
|
|
21
|
+
/** Endpoint key in the contract (e.g. `updatePartial`). */
|
|
22
|
+
method: string;
|
|
23
|
+
/** Tool transports the name is exposed on (mount order: MCP, AGENT, CLI). */
|
|
24
|
+
transports: Transport[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve every tool name the given services expose, sorted by name (then
|
|
28
|
+
* service) — a stable shape to snapshot. Multipart endpoints are absent
|
|
29
|
+
* (never mounted as tools) and CLI appears only where `expose` opts in,
|
|
30
|
+
* mirroring the real mounts.
|
|
31
|
+
*/
|
|
32
|
+
export declare function listToolNames(services: ServiceDef[]): ToolNameEntry[];
|
|
33
|
+
//# sourceMappingURL=list-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-names.d.ts","sourceRoot":"","sources":["../../src/tools/list-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,CAwBrE"}
|
package/dist/tools.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type { CliWaitConfig } from './tools/cli-wait';
|
|
|
6
6
|
export { coerceJsonArgs } from './tools/coerce';
|
|
7
7
|
export type { ToolCallHooks, ToolLifecycle, ToolResult } from './tools/execute';
|
|
8
8
|
export { flattenDiscriminatedUnion, flattenUnionsDeep } from './tools/flatten';
|
|
9
|
+
export { listToolNames, type ToolNameEntry } from './tools/list-names';
|
|
9
10
|
export { buildToolManifest, type ToolManifestEntry } from './tools/manifest';
|
|
10
11
|
export { buildMcpServer, type IncompatibleSchemaPolicy, type McpMountConfig, type McpServerBuildConfig, mountMcp, mountMcpResource, validateMcpSchemas, } from './tools/mcp';
|
|
11
12
|
export { EXT_APPS_BUNDLE_PLACEHOLDER, inlineMcpAppBundle, type McpAppCsp, type McpAppResourceMeta, type McpResourceDef, RESOURCE_MIME_TYPE, } from './tools/mcp-app';
|
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,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,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,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,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
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
AppError,
|
|
24
24
|
isWithinDir
|
|
25
25
|
} from "./index-ktn76xz0.js";
|
|
26
|
+
import"./index-khwedj16.js";
|
|
26
27
|
import {
|
|
27
28
|
isRecord,
|
|
28
29
|
typedEntries
|
|
@@ -69,6 +70,30 @@ function mountAgent(services, config = {}) {
|
|
|
69
70
|
}
|
|
70
71
|
return tools;
|
|
71
72
|
}
|
|
73
|
+
// src/tools/list-names.ts
|
|
74
|
+
var TOOL_TRANSPORTS = ["MCP", "AGENT", "CLI"];
|
|
75
|
+
function listToolNames(services) {
|
|
76
|
+
const entries = new Map;
|
|
77
|
+
for (const service of services) {
|
|
78
|
+
for (const transport of TOOL_TRANSPORTS) {
|
|
79
|
+
for (const tool2 of collectTools(service, transport)) {
|
|
80
|
+
const id = `${service.name}\x00${tool2.method.key}`;
|
|
81
|
+
const existing = entries.get(id);
|
|
82
|
+
if (existing) {
|
|
83
|
+
existing.transports.push(transport);
|
|
84
|
+
} else {
|
|
85
|
+
entries.set(id, {
|
|
86
|
+
name: tool2.name,
|
|
87
|
+
service: service.name,
|
|
88
|
+
method: tool2.method.key,
|
|
89
|
+
transports: [transport]
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return [...entries.values()].sort((a, b) => a.name.localeCompare(b.name) || a.service.localeCompare(b.service));
|
|
96
|
+
}
|
|
72
97
|
// src/tools/manifest.ts
|
|
73
98
|
function buildToolManifest(tools) {
|
|
74
99
|
return tools.map((t) => {
|
|
@@ -873,7 +898,7 @@ function withTimeout(options, timeout) {
|
|
|
873
898
|
function isParamArray(value) {
|
|
874
899
|
return Array.isArray(value) && value.every((v) => typeof v === "string" || typeof v === "number");
|
|
875
900
|
}
|
|
876
|
-
function collectQueryParams(args, skipKeys) {
|
|
901
|
+
function collectQueryParams(args, skipKeys, endpoint) {
|
|
877
902
|
const params = {};
|
|
878
903
|
let hasParams = false;
|
|
879
904
|
for (const [key, value] of Object.entries(args)) {
|
|
@@ -882,7 +907,10 @@ function collectQueryParams(args, skipKeys) {
|
|
|
882
907
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isParamArray(value)) {
|
|
883
908
|
params[key] = value;
|
|
884
909
|
hasParams = true;
|
|
910
|
+
continue;
|
|
885
911
|
}
|
|
912
|
+
const what = Array.isArray(value) ? "an array with non-primitive items" : typeof value === "object" ? "a nested object" : `a ${typeof value}`;
|
|
913
|
+
throw new Error(`${endpoint.method} ${endpoint.path}: input field "${key}" is ${what} — it cannot ` + "travel as a query parameter. GET / DELETE input must be flat (string / number / " + "boolean, or an array of string / number); flatten the field or move the " + "operation to a body verb (POST).");
|
|
886
914
|
}
|
|
887
915
|
return hasParams ? params : undefined;
|
|
888
916
|
}
|
|
@@ -936,11 +964,11 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
936
964
|
return client.post(url, formData, withTimeout(undefined, endpoint.timeout));
|
|
937
965
|
}
|
|
938
966
|
if (isGet) {
|
|
939
|
-
const params = collectQueryParams(firstArg, prefixKeys);
|
|
967
|
+
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
940
968
|
return client.get(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
941
969
|
}
|
|
942
970
|
if (httpMethod === "delete") {
|
|
943
|
-
const params = collectQueryParams(firstArg, prefixKeys);
|
|
971
|
+
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
944
972
|
return client.delete(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
945
973
|
}
|
|
946
974
|
const payload = {};
|
|
@@ -970,19 +998,19 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
970
998
|
const hasBody = !isQuery && !endpoint.multipart && endpoint.input && args;
|
|
971
999
|
if (isQuery && args) {
|
|
972
1000
|
const remaining = stripParams(args, endpoint.path, prefixKeys);
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1001
|
+
const params = collectQueryParams(remaining, new Set, endpoint);
|
|
1002
|
+
if (params) {
|
|
1003
|
+
const searchParams = new URLSearchParams;
|
|
1004
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1005
|
+
if (Array.isArray(v)) {
|
|
1006
|
+
for (const item of v)
|
|
1007
|
+
searchParams.append(k, String(item));
|
|
1008
|
+
} else {
|
|
1009
|
+
searchParams.set(k, String(v));
|
|
1010
|
+
}
|
|
982
1011
|
}
|
|
983
|
-
}
|
|
984
|
-
if (searchParams.size > 0)
|
|
985
1012
|
url += `?${searchParams}`;
|
|
1013
|
+
}
|
|
986
1014
|
}
|
|
987
1015
|
if (hasBody)
|
|
988
1016
|
headers["Content-Type"] = "application/json";
|
|
@@ -1284,6 +1312,7 @@ export {
|
|
|
1284
1312
|
mountMcp,
|
|
1285
1313
|
mountDownload,
|
|
1286
1314
|
mountAgent,
|
|
1315
|
+
listToolNames,
|
|
1287
1316
|
inlineMcpAppBundle,
|
|
1288
1317
|
implementRemote,
|
|
1289
1318
|
flattenUnionsDeep,
|
package/llms-full.txt
CHANGED
|
@@ -268,6 +268,26 @@ For the client, an endpoint's argument type is the schema's **input** type
|
|
|
268
268
|
present (required) in the handler's parsed `ctx.input`. The contract handles the
|
|
269
269
|
two type views; you do not.
|
|
270
270
|
|
|
271
|
+
### Query input (`GET` / `DELETE`)
|
|
272
|
+
|
|
273
|
+
`GET` and `DELETE` carry their input as the **query string**, and a query
|
|
274
|
+
string can only encode flat values. An input field on these verbs must be a
|
|
275
|
+
`string`, `number`, `boolean`, or an array of `string` / `number` (repeated
|
|
276
|
+
query keys). A **nested object has no canonical query encoding** — the typed
|
|
277
|
+
client throws on one instead of sending a silently incomplete request:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// input: z.object({ q: z.string(), filter: z.object({ … }) }) on a GET
|
|
281
|
+
await api.search({ q: 'x', filter: { status: 'active' } })
|
|
282
|
+
// ✗ throws: GET /: input field "filter" is a nested object — it cannot travel
|
|
283
|
+
// as a query parameter
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Flatten the field (`status: 'active'`) or move the operation to a body verb
|
|
287
|
+
(`POST`). Remember the server parses query values from **strings** — use
|
|
288
|
+
`z.coerce.number()` / `z.coerce.boolean()` in a query-input schema for
|
|
289
|
+
non-string fields.
|
|
290
|
+
|
|
271
291
|
## Transports
|
|
272
292
|
|
|
273
293
|
By default an endpoint is exposed on **every** surface — HTTP, MCP and agent
|
|
@@ -293,9 +313,9 @@ file upload is not a tool call.
|
|
|
293
313
|
|
|
294
314
|
## `toolName`
|
|
295
315
|
|
|
296
|
-
When an endpoint is exposed as a tool, its name defaults to
|
|
297
|
-
(`users` + `create` ⇒ `
|
|
298
|
-
name:
|
|
316
|
+
When an endpoint is exposed as a tool, its name defaults to a verb-aware
|
|
317
|
+
derivation from the method key + prefix (`users` + `create` ⇒ `create_user`,
|
|
318
|
+
`users` + `list` ⇒ `list_users`). Set `toolName` for an explicit, stable name:
|
|
299
319
|
|
|
300
320
|
```ts
|
|
301
321
|
{ method: 'POST', path: '/', desc: 'Create a user', toolName: 'create_user', /* … */ }
|
|
@@ -831,10 +851,16 @@ const http = createHttpClient({ baseUrl: '/api' })
|
|
|
831
851
|
| `headers` | — | extra headers — an object, or a function re-run per request |
|
|
832
852
|
| `authEndpoints` | `['auth/']` | paths that should **not** emit `unauthorized` on 401 |
|
|
833
853
|
| `parseError` | built-in | map an error body to `{ code, message, details, hint }` |
|
|
854
|
+
| `trace` | `false` | emit a W3C `traceparent` header on every request |
|
|
834
855
|
|
|
835
856
|
`headers` as a function is the hook for runtime tokens — a bearer token or any
|
|
836
857
|
short-lived credential — re-evaluated on every request.
|
|
837
858
|
|
|
859
|
+
`trace: true` mints a fresh root trace per request. The stitchkit server
|
|
860
|
+
[continues an inbound `traceparent`](./observability.md#trace-context), so the
|
|
861
|
+
browser call, the HTTP handler and every nested tool call share one trace id
|
|
862
|
+
end-to-end. A `traceparent` you set yourself (via `headers`) always wins.
|
|
863
|
+
|
|
838
864
|
Retry is deliberately conservative: only a connection that never landed (a
|
|
839
865
|
network error), only on idempotent `GET`. A server that *responded* with a 5xx
|
|
840
866
|
is the data layer's call (TanStack Query), not the transport's — retrying in
|
|
@@ -1053,6 +1079,27 @@ to a verb-aware name from the method + prefix (`list` → `list_widgets`, `get`
|
|
|
1053
1079
|
`get_widget`); set `toolName` for an explicit one. See
|
|
1054
1080
|
[Contracts → transports](./contracts.md#transports).
|
|
1055
1081
|
|
|
1082
|
+
### Pinning tool names — `listToolNames`
|
|
1083
|
+
|
|
1084
|
+
Derived tool names are part of your public surface — an MCP client config or an
|
|
1085
|
+
agent prompt refers to them by string. `listToolNames(services)` resolves every
|
|
1086
|
+
tool name your services expose (the exact resolver the mounts use), with its
|
|
1087
|
+
`(service, method)` identity and transports, sorted — a stable shape to
|
|
1088
|
+
snapshot:
|
|
1089
|
+
|
|
1090
|
+
```ts
|
|
1091
|
+
import { listToolNames } from 'stitchkit/tools'
|
|
1092
|
+
|
|
1093
|
+
test('tool names have not drifted', () => {
|
|
1094
|
+
expect(listToolNames(services)).toMatchSnapshot()
|
|
1095
|
+
})
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
A stitchkit upgrade (or a contract refactor) that would shift a derived name
|
|
1099
|
+
now fails this test instead of silently breaking the clients that call the
|
|
1100
|
+
tool. It is also the mechanical diff when migrating a service: run it before
|
|
1101
|
+
and after, compare.
|
|
1102
|
+
|
|
1056
1103
|
## MCP — `createMcpHandler`
|
|
1057
1104
|
|
|
1058
1105
|
`createMcpHandler` builds a complete Streamable-HTTP MCP server as a single
|
|
@@ -2361,6 +2408,12 @@ You rarely call the trace functions directly — `wrapInRequestContext` and
|
|
|
2361
2408
|
`parseTraceparent`, `formatTraceparent`, `childSpan`) for when you need to
|
|
2362
2409
|
propagate a `traceparent` onward to another service.
|
|
2363
2410
|
|
|
2411
|
+
The browser side starts the trace:
|
|
2412
|
+
[`createHttpClient({ trace: true })`](./client.md#httpclientconfig) emits a
|
|
2413
|
+
fresh root `traceparent` on every request, which the server then continues. The
|
|
2414
|
+
trace helpers themselves are browser-safe and also exported from the root
|
|
2415
|
+
`stitchkit` entry — a custom client can format its own header.
|
|
2416
|
+
|
|
2364
2417
|
> **Span ids live in the request context, not on `ctx`.** The handler `ctx`
|
|
2365
2418
|
> carries a single `traceId`; the full `{ traceId, spanId, parentSpanId }` is on
|
|
2366
2419
|
> the observability request context. To stamp `spanId` / `parentSpanId` into an
|
|
@@ -2859,6 +2912,20 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
2859
2912
|
| `RetainedTopics` | _type_ | the `createRetainedTopics` handle |
|
|
2860
2913
|
| `ParseSSEOptions` | _type_ | options for `parseSSE` |
|
|
2861
2914
|
|
|
2915
|
+
### Trace (client)
|
|
2916
|
+
|
|
2917
|
+
Browser-safe W3C trace helpers — the same functions as on
|
|
2918
|
+
[`stitchkit/observability`](#stitchkitobservability), re-exported so a client
|
|
2919
|
+
can emit / propagate a `traceparent` (see `HttpClientConfig.trace`).
|
|
2920
|
+
|
|
2921
|
+
| Export | Kind | Summary |
|
|
2922
|
+
|--------|------|---------|
|
|
2923
|
+
| `createTraceContext` | function | a fresh root trace |
|
|
2924
|
+
| `formatTraceparent` | function | render a `traceparent` header value |
|
|
2925
|
+
| `parseTraceparent` | function | parse a `traceparent` header |
|
|
2926
|
+
| `childSpan` | function | a child span of a parent trace |
|
|
2927
|
+
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId? }` |
|
|
2928
|
+
|
|
2862
2929
|
---
|
|
2863
2930
|
|
|
2864
2931
|
## `stitchkit/contract`
|
|
@@ -3095,6 +3162,7 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
3095
3162
|
| `mountViewFile` | function | a native multimodal "view file" MCP tool |
|
|
3096
3163
|
| `resolveMedia` | function | resolve a media reference for a tool result |
|
|
3097
3164
|
| `validateMcpSchemas` | function | assert every tool schema is JSON Schema-compatible — [guide](../guide/mcp-and-agents.md#incompatible-schemas--onincompatibleschema) |
|
|
3165
|
+
| `listToolNames` | function | every mounted tool name with its `(service, method)` identity — for name-baseline snapshots — [guide](../guide/mcp-and-agents.md#pinning-tool-names--listtoolnames) |
|
|
3098
3166
|
| `McpHandlerConfig` | _type_ | config for `createMcpHandler` |
|
|
3099
3167
|
| `StdioMcpServerConfig` | _type_ | config for `createStdioMcpServer` |
|
|
3100
3168
|
| `McpServerBuildConfig` | _type_ | shared config for `buildMcpServer` |
|
|
@@ -3110,6 +3178,7 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
3110
3178
|
| `ToolLifecycle` | _type_ | `beforeHandle` / `afterHandle` gate for tool calls — [guide](../guide/mcp-and-agents.md#guarding-tools--lifecycle) |
|
|
3111
3179
|
| `ToolCallHooks` | _type_ | `beforeToolCall` / `afterToolCall` observability hooks |
|
|
3112
3180
|
| `ToolResult` | _type_ | the result of one tool call |
|
|
3181
|
+
| `ToolNameEntry` | _type_ | one `listToolNames` row — `{ name, service, method, transports }` |
|
|
3113
3182
|
| `IncompatibleSchemaPolicy` | _type_ | `'throw' \| 'skip' \| 'warn'` |
|
|
3114
3183
|
| `McpMediaContent` | _type_ | a multimodal MCP content item |
|
|
3115
3184
|
|
package/package.json
CHANGED