stitchkit 0.35.0 → 0.36.1
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/cli.js +2 -2
- package/dist/{index-enc7t99e.js → index-17rdjw68.js} +146 -1
- package/dist/{index-bfabej0h.js → index-82gncajj.js} +25 -3
- package/dist/{index-nmq59nae.js → index-bx49hskg.js} +1 -1
- package/dist/{index-k7ysesv0.js → index-dvrn81q4.js} +9 -11
- package/dist/node.js +2 -3
- package/dist/observability/index.js +4 -6
- package/dist/server/index.js +9 -11
- package/dist/tools/execute.d.ts +15 -0
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools.js +4 -6
- package/llms-full.txt +15 -4
- package/package.json +1 -1
- package/dist/index-wya8bkme.js +0 -151
package/dist/cli.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
emitResult,
|
|
5
5
|
parseCliArgs,
|
|
6
6
|
pollUntilDone
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-82gncajj.js";
|
|
8
8
|
import"./index-0ed3bx43.js";
|
|
9
9
|
import"./index-x3fcszf8.js";
|
|
10
|
-
import"./index-
|
|
10
|
+
import"./index-17rdjw68.js";
|
|
11
11
|
export {
|
|
12
12
|
pollUntilDone,
|
|
13
13
|
parseCliArgs,
|
|
@@ -192,4 +192,149 @@ function safeJsonParse(text) {
|
|
|
192
192
|
return JSON.parse(text, (key, value) => isUnsafeKey(key) ? undefined : value);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
// src/server/request.ts
|
|
196
|
+
function generateTraceId() {
|
|
197
|
+
return `${Date.now().toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
198
|
+
}
|
|
199
|
+
function resolveTraceId(req) {
|
|
200
|
+
const header = req.headers.get("x-request-id") ?? req.headers.get("x-trace-id");
|
|
201
|
+
const trimmed = header?.trim();
|
|
202
|
+
if (trimmed && trimmed.length <= 128 && /^[\w.-]+$/.test(trimmed)) {
|
|
203
|
+
return trimmed;
|
|
204
|
+
}
|
|
205
|
+
return generateTraceId();
|
|
206
|
+
}
|
|
207
|
+
function resolveSocketIp(req, server) {
|
|
208
|
+
if (typeof server === "object" && server !== null && "requestIP" in server && typeof server.requestIP === "function") {
|
|
209
|
+
const addr = server.requestIP(req);
|
|
210
|
+
if (isRecord(addr) && typeof addr.address === "string" && addr.address) {
|
|
211
|
+
return addr.address;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if ("ip" in req && typeof req.ip === "string" && req.ip)
|
|
215
|
+
return req.ip;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
function extractIp(req, options = {}) {
|
|
219
|
+
if (options.trustProxy) {
|
|
220
|
+
const forwarded = req.headers.get("x-forwarded-for");
|
|
221
|
+
if (forwarded)
|
|
222
|
+
return (forwarded.split(",")[0] ?? "").trim().replace(/^::ffff:/, "");
|
|
223
|
+
const realIp = req.headers.get("x-real-ip");
|
|
224
|
+
if (realIp)
|
|
225
|
+
return realIp.trim().replace(/^::ffff:/, "");
|
|
226
|
+
}
|
|
227
|
+
return (options.socketIp ?? "").replace(/^::ffff:/, "");
|
|
228
|
+
}
|
|
229
|
+
function getClientInfo(req, options = {}) {
|
|
230
|
+
return {
|
|
231
|
+
ipAddress: extractIp(req, options) || undefined,
|
|
232
|
+
userAgent: req.headers.get("user-agent") ?? undefined
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function parseQueryParams(url) {
|
|
236
|
+
const query = {};
|
|
237
|
+
for (const key of new Set(url.searchParams.keys())) {
|
|
238
|
+
if (isUnsafeKey(key))
|
|
239
|
+
continue;
|
|
240
|
+
const values = url.searchParams.getAll(key);
|
|
241
|
+
const [first] = values;
|
|
242
|
+
query[key] = values.length === 1 && first !== undefined ? first : values;
|
|
243
|
+
}
|
|
244
|
+
return query;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/observability/trace.ts
|
|
248
|
+
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
249
|
+
function randomHex(bytes) {
|
|
250
|
+
const arr = new Uint8Array(bytes);
|
|
251
|
+
crypto.getRandomValues(arr);
|
|
252
|
+
let hex = "";
|
|
253
|
+
for (const byte of arr)
|
|
254
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
255
|
+
return hex;
|
|
256
|
+
}
|
|
257
|
+
function createTraceContext() {
|
|
258
|
+
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
259
|
+
}
|
|
260
|
+
function parseTraceparent(header) {
|
|
261
|
+
if (!header)
|
|
262
|
+
return null;
|
|
263
|
+
const match = TRACEPARENT_RE.exec(header.trim());
|
|
264
|
+
if (!match?.[1] || !match[2])
|
|
265
|
+
return null;
|
|
266
|
+
const traceId = match[1].toLowerCase();
|
|
267
|
+
const parentSpanId = match[2].toLowerCase();
|
|
268
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
269
|
+
return null;
|
|
270
|
+
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
271
|
+
}
|
|
272
|
+
function formatTraceparent(ctx) {
|
|
273
|
+
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
274
|
+
}
|
|
275
|
+
function resolveTraceContext(req) {
|
|
276
|
+
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
277
|
+
}
|
|
278
|
+
function childSpan(parent) {
|
|
279
|
+
return {
|
|
280
|
+
traceId: parent.traceId,
|
|
281
|
+
spanId: randomHex(8),
|
|
282
|
+
parentSpanId: parent.spanId
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/observability/context.ts
|
|
287
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
288
|
+
var storage = new AsyncLocalStorage;
|
|
289
|
+
function runWithRequestContext(ctx, fn) {
|
|
290
|
+
return storage.run(ctx, fn);
|
|
291
|
+
}
|
|
292
|
+
function getRequestContext() {
|
|
293
|
+
return storage.getStore();
|
|
294
|
+
}
|
|
295
|
+
function getTraceId() {
|
|
296
|
+
return storage.getStore()?.trace.traceId;
|
|
297
|
+
}
|
|
298
|
+
function getUserId() {
|
|
299
|
+
return storage.getStore()?.userId;
|
|
300
|
+
}
|
|
301
|
+
function setRequestUser(userId) {
|
|
302
|
+
const ctx = storage.getStore();
|
|
303
|
+
if (ctx)
|
|
304
|
+
ctx.userId = userId;
|
|
305
|
+
}
|
|
306
|
+
function setRequestEndpoint(serviceName, action) {
|
|
307
|
+
const ctx = storage.getStore();
|
|
308
|
+
if (ctx) {
|
|
309
|
+
ctx.serviceName = serviceName;
|
|
310
|
+
ctx.action = action;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function setRequestDimensions(dimensions) {
|
|
314
|
+
const ctx = storage.getStore();
|
|
315
|
+
if (ctx)
|
|
316
|
+
ctx.dimensions = { ...ctx.dimensions, ...dimensions };
|
|
317
|
+
}
|
|
318
|
+
function setRequestError(error) {
|
|
319
|
+
const ctx = storage.getStore();
|
|
320
|
+
if (ctx)
|
|
321
|
+
ctx.error = error;
|
|
322
|
+
}
|
|
323
|
+
function wrapInRequestContext(handler, options = {}) {
|
|
324
|
+
return (req, server) => {
|
|
325
|
+
const ctx = {
|
|
326
|
+
trace: resolveTraceContext(req),
|
|
327
|
+
source: "http",
|
|
328
|
+
method: req.method,
|
|
329
|
+
path: new URL(req.url, "http://localhost").pathname,
|
|
330
|
+
startedAt: process.hrtime.bigint(),
|
|
331
|
+
...getClientInfo(req, {
|
|
332
|
+
trustProxy: options.trustProxy,
|
|
333
|
+
socketIp: resolveSocketIp(req, server)
|
|
334
|
+
})
|
|
335
|
+
};
|
|
336
|
+
return runWithRequestContext(ctx, () => handler(req, server));
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export { __require, mergeMeta, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, typedEntries, isRecord, bytesToBase64Url, base64UrlToBytes, formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateHandlerOutput, isUnsafeKey, safeJsonParse, generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
|
|
@@ -7,12 +7,14 @@ import {
|
|
|
7
7
|
} from "./index-x3fcszf8.js";
|
|
8
8
|
import {
|
|
9
9
|
formatZodError,
|
|
10
|
+
getRequestContext,
|
|
10
11
|
isRecord,
|
|
11
12
|
isUnsafeKey,
|
|
12
13
|
normalizeError,
|
|
14
|
+
runWithRequestContext,
|
|
13
15
|
safeJsonParse,
|
|
14
16
|
validateHandlerOutput
|
|
15
|
-
} from "./index-
|
|
17
|
+
} from "./index-17rdjw68.js";
|
|
16
18
|
|
|
17
19
|
// src/tools/coerce.ts
|
|
18
20
|
import { z } from "zod";
|
|
@@ -434,6 +436,25 @@ function toolResultFromError(err) {
|
|
|
434
436
|
};
|
|
435
437
|
}
|
|
436
438
|
async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false, onOutputStrip) {
|
|
439
|
+
return inToolCallContext({ source: context.source, toolName, method }, () => runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip));
|
|
440
|
+
}
|
|
441
|
+
function inToolCallContext(call, body) {
|
|
442
|
+
const parent = getRequestContext();
|
|
443
|
+
if (!parent)
|
|
444
|
+
return body();
|
|
445
|
+
return runWithRequestContext({
|
|
446
|
+
...parent,
|
|
447
|
+
trace: parent.trace,
|
|
448
|
+
dimensions: parent.dimensions ? { ...parent.dimensions } : undefined,
|
|
449
|
+
error: undefined,
|
|
450
|
+
source: call.source,
|
|
451
|
+
method: "TOOL",
|
|
452
|
+
path: `/${call.source}/${call.toolName}`,
|
|
453
|
+
serviceName: call.method.serviceName,
|
|
454
|
+
action: call.method.key
|
|
455
|
+
}, body);
|
|
456
|
+
}
|
|
457
|
+
async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip) {
|
|
437
458
|
const startedAt = Date.now();
|
|
438
459
|
const finish = async (result, thrown) => {
|
|
439
460
|
await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context, method, thrown);
|
|
@@ -627,14 +648,15 @@ function collectTools(service, transport, config = {}) {
|
|
|
627
648
|
}
|
|
628
649
|
function createToolRunner(config) {
|
|
629
650
|
const extendKeys = config.extend ? new Set(Object.keys(config.extend.schema)) : null;
|
|
630
|
-
return async (tool, rawArgs) => {
|
|
651
|
+
return async (tool, rawArgs) => inToolCallContext({ source: config.source, toolName: tool.name, method: tool.method }, () => runOneToolCall(tool, rawArgs));
|
|
652
|
+
async function runOneToolCall(tool, rawArgs) {
|
|
631
653
|
let extraContext = {};
|
|
632
654
|
if (tool.shouldExtend && config.extend) {
|
|
633
655
|
extraContext = await config.extend.resolve(rawArgs);
|
|
634
656
|
}
|
|
635
657
|
const cleanArgs = tool.shouldExtend && extendKeys ? Object.fromEntries(Object.entries(rawArgs).filter(([key]) => !extendKeys.has(key))) : rawArgs;
|
|
636
658
|
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);
|
|
637
|
-
}
|
|
659
|
+
}
|
|
638
660
|
}
|
|
639
661
|
function formatToolError(result, toolName, errorHint) {
|
|
640
662
|
const err = { error: result.code };
|
|
@@ -6,30 +6,28 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
isWithinDir
|
|
8
8
|
} from "./index-x3fcszf8.js";
|
|
9
|
-
import {
|
|
10
|
-
extractIp,
|
|
11
|
-
getClientInfo,
|
|
12
|
-
getRequestContext,
|
|
13
|
-
parseQueryParams,
|
|
14
|
-
resolveSocketIp,
|
|
15
|
-
resolveTraceId,
|
|
16
|
-
setRequestEndpoint,
|
|
17
|
-
setRequestError
|
|
18
|
-
} from "./index-wya8bkme.js";
|
|
19
9
|
import {
|
|
20
10
|
AppError,
|
|
21
11
|
__require,
|
|
22
12
|
badRequest,
|
|
23
13
|
errorCode,
|
|
14
|
+
extractIp,
|
|
15
|
+
getClientInfo,
|
|
16
|
+
getRequestContext,
|
|
24
17
|
isRecord,
|
|
25
18
|
isUnsafeKey,
|
|
26
19
|
mergeMeta,
|
|
27
20
|
normalizeError,
|
|
21
|
+
parseQueryParams,
|
|
28
22
|
recordedErrorMessage,
|
|
23
|
+
resolveSocketIp,
|
|
24
|
+
resolveTraceId,
|
|
29
25
|
safeJsonParse,
|
|
26
|
+
setRequestEndpoint,
|
|
27
|
+
setRequestError,
|
|
30
28
|
typedEntries,
|
|
31
29
|
validateHandlerOutput
|
|
32
|
-
} from "./index-
|
|
30
|
+
} from "./index-17rdjw68.js";
|
|
33
31
|
|
|
34
32
|
// src/server/multipart.ts
|
|
35
33
|
var DEFAULT_MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
package/dist/node.js
CHANGED
|
@@ -3,10 +3,9 @@ import {
|
|
|
3
3
|
createImplement,
|
|
4
4
|
createSocketIOServer,
|
|
5
5
|
implement
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-dvrn81q4.js";
|
|
7
7
|
import"./index-czmqks7r.js";
|
|
8
8
|
import"./index-x3fcszf8.js";
|
|
9
|
-
import"./index-wya8bkme.js";
|
|
10
9
|
import {
|
|
11
10
|
AppError,
|
|
12
11
|
appError,
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
notFound,
|
|
17
16
|
rateLimited,
|
|
18
17
|
unauthorized
|
|
19
|
-
} from "./index-
|
|
18
|
+
} from "./index-17rdjw68.js";
|
|
20
19
|
// src/server/node.ts
|
|
21
20
|
import { serve } from "srvx";
|
|
22
21
|
async function serveNode(config) {
|
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
getRequestContext,
|
|
6
6
|
getTraceId,
|
|
7
7
|
getUserId,
|
|
8
|
+
isRecord,
|
|
9
|
+
isUnsafeKey,
|
|
8
10
|
parseTraceparent,
|
|
11
|
+
recordedErrorMessage,
|
|
9
12
|
resolveTraceContext,
|
|
10
13
|
runWithRequestContext,
|
|
11
14
|
setRequestDimensions,
|
|
@@ -13,12 +16,7 @@ import {
|
|
|
13
16
|
setRequestError,
|
|
14
17
|
setRequestUser,
|
|
15
18
|
wrapInRequestContext
|
|
16
|
-
} from "../index-
|
|
17
|
-
import {
|
|
18
|
-
isRecord,
|
|
19
|
-
isUnsafeKey,
|
|
20
|
-
recordedErrorMessage
|
|
21
|
-
} from "../index-enc7t99e.js";
|
|
19
|
+
} from "../index-17rdjw68.js";
|
|
22
20
|
|
|
23
21
|
// src/observability/sanitize.ts
|
|
24
22
|
var DEFAULT_SENSITIVE_KEYS = /(password|passwd|pwd|secret|token|apikey|api[-_ ]?key|auth|authorization|bearer|session|cookie|init[-_ ]?data|credential|private[-_ ]?key)/i;
|
package/dist/server/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
socketIoLane,
|
|
11
11
|
staticRoute,
|
|
12
12
|
webSocketLane
|
|
13
|
-
} from "../index-
|
|
13
|
+
} from "../index-dvrn81q4.js";
|
|
14
14
|
import {
|
|
15
15
|
createAuthHook,
|
|
16
16
|
createBearerResolver,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
signJwt,
|
|
24
24
|
verifyJwt,
|
|
25
25
|
verifyPkce
|
|
26
|
-
} from "../index-
|
|
26
|
+
} from "../index-bx49hskg.js";
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_CORS_ALLOW_HEADERS,
|
|
29
29
|
DEFAULT_CORS_EXPOSE_HEADERS,
|
|
@@ -37,14 +37,6 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
isWithinDir
|
|
39
39
|
} from "../index-x3fcszf8.js";
|
|
40
|
-
import {
|
|
41
|
-
extractIp,
|
|
42
|
-
generateTraceId,
|
|
43
|
-
getClientInfo,
|
|
44
|
-
getTraceId,
|
|
45
|
-
resolveSocketIp,
|
|
46
|
-
resolveTraceId
|
|
47
|
-
} from "../index-wya8bkme.js";
|
|
48
40
|
import {
|
|
49
41
|
AppError,
|
|
50
42
|
STITCH_ERROR_STATUS,
|
|
@@ -52,16 +44,22 @@ import {
|
|
|
52
44
|
badRequest,
|
|
53
45
|
conflict,
|
|
54
46
|
errorCode,
|
|
47
|
+
extractIp,
|
|
55
48
|
forbidden,
|
|
56
49
|
formatZodError,
|
|
50
|
+
generateTraceId,
|
|
51
|
+
getClientInfo,
|
|
52
|
+
getTraceId,
|
|
57
53
|
isRecord,
|
|
58
54
|
isStitchErrorCode,
|
|
59
55
|
normalizeError,
|
|
60
56
|
notFound,
|
|
61
57
|
rateLimited,
|
|
58
|
+
resolveSocketIp,
|
|
59
|
+
resolveTraceId,
|
|
62
60
|
unauthorized,
|
|
63
61
|
zodIssues
|
|
64
|
-
} from "../index-
|
|
62
|
+
} from "../index-17rdjw68.js";
|
|
65
63
|
// src/server/swept-map.ts
|
|
66
64
|
function createSweptMap(options) {
|
|
67
65
|
const store = new Map;
|
package/dist/tools/execute.d.ts
CHANGED
|
@@ -88,4 +88,19 @@ export declare function toolResultFromError(err: unknown): Extract<ToolResult, {
|
|
|
88
88
|
ok: false;
|
|
89
89
|
}>;
|
|
90
90
|
export declare function executeToolMethod(method: MethodDef<unknown, unknown, unknown>, toolName: string, rawArgs: Record<string, unknown>, context: ToolCallContext, hooks?: ToolCallHooks, lifecycle?: ToolLifecycle, coerceJson?: boolean, onOutputStrip?: (paths: string[]) => void): Promise<ToolResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Run `body` in a request context forked for one tool call — the shared rule,
|
|
93
|
+
* so every entry point isolates the same way. A mount uses it around
|
|
94
|
+
* `ToolExtend.resolve` as well, which runs before the executor and is a
|
|
95
|
+
* documented per-call resolution point. → ADR 0045.
|
|
96
|
+
*
|
|
97
|
+
* No fork where there is no ambient context: nothing is shared there, and
|
|
98
|
+
* inventing a root would stamp every stdio / CLI row with a `parentSpanId`
|
|
99
|
+
* pointing at a span no row emits.
|
|
100
|
+
*/
|
|
101
|
+
export declare function inToolCallContext<T>(call: {
|
|
102
|
+
source: TransportSource;
|
|
103
|
+
toolName: string;
|
|
104
|
+
method: MethodDef<unknown, unknown, unknown>;
|
|
105
|
+
}, body: () => Promise<T>): Promise<T>;
|
|
91
106
|
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/tools/mount.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACL,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/tools/mount.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
inputIsQuery,
|
|
3
3
|
signJwt,
|
|
4
4
|
verifyPkce
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-bx49hskg.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_CORS_ALLOW_HEADERS
|
|
8
8
|
} from "./index-czmqks7r.js";
|
|
@@ -21,22 +21,20 @@ import {
|
|
|
21
21
|
readCapped,
|
|
22
22
|
toolResultFromError,
|
|
23
23
|
writeDownload
|
|
24
|
-
} from "./index-
|
|
24
|
+
} from "./index-82gncajj.js";
|
|
25
25
|
import {
|
|
26
26
|
toJsonSchema
|
|
27
27
|
} from "./index-0ed3bx43.js";
|
|
28
28
|
import {
|
|
29
29
|
isWithinDir
|
|
30
30
|
} from "./index-x3fcszf8.js";
|
|
31
|
-
import {
|
|
32
|
-
getTraceId
|
|
33
|
-
} from "./index-wya8bkme.js";
|
|
34
31
|
import {
|
|
35
32
|
AppError,
|
|
33
|
+
getTraceId,
|
|
36
34
|
isRecord,
|
|
37
35
|
mergeMeta,
|
|
38
36
|
typedEntries
|
|
39
|
-
} from "./index-
|
|
37
|
+
} from "./index-17rdjw68.js";
|
|
40
38
|
|
|
41
39
|
// src/tools/agent.ts
|
|
42
40
|
import { tool, zodSchema } from "ai";
|
package/llms-full.txt
CHANGED
|
@@ -2912,6 +2912,8 @@ import {
|
|
|
2912
2912
|
} from 'stitchkit/observability'
|
|
2913
2913
|
|
|
2914
2914
|
createAuthHook({ /* … */ inject: (ctx, user) => user && setRequestUser(user.id) })
|
|
2915
|
+
// ↑ on the HTTP path. Inside a tool call this writes to that call's own context
|
|
2916
|
+
// (→ ADR 0045); a tool row takes its identity from the mount's `context`.
|
|
2915
2917
|
// only to override what the framework already recorded — see below:
|
|
2916
2918
|
setRequestError({ code: err.code, message: err.message, details: err.issues })
|
|
2917
2919
|
```
|
|
@@ -2940,6 +2942,12 @@ meaning to (→ ADR 0021). Resolve it cheaply from `ctx.params` / headers in
|
|
|
2940
2942
|
`ctx.req` are available there) and it lands on `event.dimensions` for the request
|
|
2941
2943
|
either way, so your sink reads it as a column instead of re-parsing the path:
|
|
2942
2944
|
|
|
2945
|
+
> **On the tool path it lands on that call's own event, not the request's.** The
|
|
2946
|
+
> same hooks object is assignable to `ToolLifecycle`, so this recipe is the one
|
|
2947
|
+
> people apply to tools — and since ADR 0045 each tool call runs in its own
|
|
2948
|
+
> context. Read the value off the tool row (`event.toolName != null`); both rows
|
|
2949
|
+
> carry the same `traceId`.
|
|
2950
|
+
|
|
2943
2951
|
```ts
|
|
2944
2952
|
// beforeHandle (success) and onError (failure) alike:
|
|
2945
2953
|
const projectId = ctx.req?.headers.get('x-project') ?? String(ctx.params?.projectId ?? '')
|
|
@@ -2957,6 +2965,9 @@ createHandler({ /* … */ traceId: getTraceId })
|
|
|
2957
2965
|
falls back to its own resolver — a trusted inbound `x-request-id` / `x-trace-id`,
|
|
2958
2966
|
else a fresh id — so the line never carries the string `"undefined"`.
|
|
2959
2967
|
|
|
2968
|
+
Inside a **tool call** the context is that call's own (→ ADR 0045), so the
|
|
2969
|
+
enrichment a request log picks up describes the request, not the call.
|
|
2970
|
+
|
|
2960
2971
|
`getRequestContext()` / `getTraceId()` then return the active values from
|
|
2961
2972
|
anywhere in the call — stamp `getTraceId()` onto every line your logger writes.
|
|
2962
2973
|
The **request log picks the context up on its own**: with a context active, each
|
|
@@ -3136,10 +3147,10 @@ object must stay assignable to `ToolLifecycle`.)
|
|
|
3136
3147
|
which `createAuditHook`'s **tool** row does not read: a tool event takes
|
|
3137
3148
|
`errorCode` / `errorMessage` / `errorDetail` from the `ToolResult`, and only
|
|
3138
3149
|
identity and `dimensions` from the context. Calling it in `onToolError` would
|
|
3139
|
-
leave the tool row exactly as scrubbed as before
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3150
|
+
leave the tool row exactly as scrubbed as before. It is right for the **HTTP**
|
|
3151
|
+
path, where the request *is* the record. (Since ADR 0045 a tool call runs in its
|
|
3152
|
+
own context, so it can no longer write into the enclosing `/mcp` request's row
|
|
3153
|
+
either — the call is simply not where that helper belongs.)
|
|
3143
3154
|
|
|
3144
3155
|
### One row that names the cause
|
|
3145
3156
|
|
package/package.json
CHANGED
package/dist/index-wya8bkme.js
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isRecord,
|
|
3
|
-
isUnsafeKey
|
|
4
|
-
} from "./index-enc7t99e.js";
|
|
5
|
-
|
|
6
|
-
// src/server/request.ts
|
|
7
|
-
function generateTraceId() {
|
|
8
|
-
return `${Date.now().toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
9
|
-
}
|
|
10
|
-
function resolveTraceId(req) {
|
|
11
|
-
const header = req.headers.get("x-request-id") ?? req.headers.get("x-trace-id");
|
|
12
|
-
const trimmed = header?.trim();
|
|
13
|
-
if (trimmed && trimmed.length <= 128 && /^[\w.-]+$/.test(trimmed)) {
|
|
14
|
-
return trimmed;
|
|
15
|
-
}
|
|
16
|
-
return generateTraceId();
|
|
17
|
-
}
|
|
18
|
-
function resolveSocketIp(req, server) {
|
|
19
|
-
if (typeof server === "object" && server !== null && "requestIP" in server && typeof server.requestIP === "function") {
|
|
20
|
-
const addr = server.requestIP(req);
|
|
21
|
-
if (isRecord(addr) && typeof addr.address === "string" && addr.address) {
|
|
22
|
-
return addr.address;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
if ("ip" in req && typeof req.ip === "string" && req.ip)
|
|
26
|
-
return req.ip;
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
function extractIp(req, options = {}) {
|
|
30
|
-
if (options.trustProxy) {
|
|
31
|
-
const forwarded = req.headers.get("x-forwarded-for");
|
|
32
|
-
if (forwarded)
|
|
33
|
-
return (forwarded.split(",")[0] ?? "").trim().replace(/^::ffff:/, "");
|
|
34
|
-
const realIp = req.headers.get("x-real-ip");
|
|
35
|
-
if (realIp)
|
|
36
|
-
return realIp.trim().replace(/^::ffff:/, "");
|
|
37
|
-
}
|
|
38
|
-
return (options.socketIp ?? "").replace(/^::ffff:/, "");
|
|
39
|
-
}
|
|
40
|
-
function getClientInfo(req, options = {}) {
|
|
41
|
-
return {
|
|
42
|
-
ipAddress: extractIp(req, options) || undefined,
|
|
43
|
-
userAgent: req.headers.get("user-agent") ?? undefined
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function parseQueryParams(url) {
|
|
47
|
-
const query = {};
|
|
48
|
-
for (const key of new Set(url.searchParams.keys())) {
|
|
49
|
-
if (isUnsafeKey(key))
|
|
50
|
-
continue;
|
|
51
|
-
const values = url.searchParams.getAll(key);
|
|
52
|
-
const [first] = values;
|
|
53
|
-
query[key] = values.length === 1 && first !== undefined ? first : values;
|
|
54
|
-
}
|
|
55
|
-
return query;
|
|
56
|
-
}
|
|
57
|
-
|
|
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
|
-
// src/observability/context.ts
|
|
98
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
99
|
-
var storage = new AsyncLocalStorage;
|
|
100
|
-
function runWithRequestContext(ctx, fn) {
|
|
101
|
-
return storage.run(ctx, fn);
|
|
102
|
-
}
|
|
103
|
-
function getRequestContext() {
|
|
104
|
-
return storage.getStore();
|
|
105
|
-
}
|
|
106
|
-
function getTraceId() {
|
|
107
|
-
return storage.getStore()?.trace.traceId;
|
|
108
|
-
}
|
|
109
|
-
function getUserId() {
|
|
110
|
-
return storage.getStore()?.userId;
|
|
111
|
-
}
|
|
112
|
-
function setRequestUser(userId) {
|
|
113
|
-
const ctx = storage.getStore();
|
|
114
|
-
if (ctx)
|
|
115
|
-
ctx.userId = userId;
|
|
116
|
-
}
|
|
117
|
-
function setRequestEndpoint(serviceName, action) {
|
|
118
|
-
const ctx = storage.getStore();
|
|
119
|
-
if (ctx) {
|
|
120
|
-
ctx.serviceName = serviceName;
|
|
121
|
-
ctx.action = action;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function setRequestDimensions(dimensions) {
|
|
125
|
-
const ctx = storage.getStore();
|
|
126
|
-
if (ctx)
|
|
127
|
-
ctx.dimensions = { ...ctx.dimensions, ...dimensions };
|
|
128
|
-
}
|
|
129
|
-
function setRequestError(error) {
|
|
130
|
-
const ctx = storage.getStore();
|
|
131
|
-
if (ctx)
|
|
132
|
-
ctx.error = error;
|
|
133
|
-
}
|
|
134
|
-
function wrapInRequestContext(handler, options = {}) {
|
|
135
|
-
return (req, server) => {
|
|
136
|
-
const ctx = {
|
|
137
|
-
trace: resolveTraceContext(req),
|
|
138
|
-
source: "http",
|
|
139
|
-
method: req.method,
|
|
140
|
-
path: new URL(req.url, "http://localhost").pathname,
|
|
141
|
-
startedAt: process.hrtime.bigint(),
|
|
142
|
-
...getClientInfo(req, {
|
|
143
|
-
trustProxy: options.trustProxy,
|
|
144
|
-
socketIp: resolveSocketIp(req, server)
|
|
145
|
-
})
|
|
146
|
-
};
|
|
147
|
-
return runWithRequestContext(ctx, () => handler(req, server));
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
|