stitchkit 0.27.0 → 0.28.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.
@@ -2,7 +2,7 @@ import {
2
2
  assertCorsConfig,
3
3
  corsHeaders,
4
4
  corsPreflightResponse
5
- } from "./index-zfscdskj.js";
5
+ } from "./index-czmqks7r.js";
6
6
  import {
7
7
  AppError,
8
8
  badRequest,
@@ -15,13 +15,15 @@ import {
15
15
  import {
16
16
  extractIp,
17
17
  getClientInfo,
18
+ getRequestContext,
18
19
  parseQueryParams,
19
20
  resolveSocketIp,
20
21
  resolveTraceId,
21
22
  setRequestEndpoint
22
- } from "./index-dzx781tm.js";
23
+ } from "./index-9g9d6r1h.js";
23
24
  import {
24
25
  __require,
26
+ isRecord,
25
27
  isUnsafeKey,
26
28
  safeJsonParse,
27
29
  typedEntries
@@ -426,7 +428,7 @@ function levelForStatus(status) {
426
428
  return "info";
427
429
  }
428
430
  function buildLogFields(method, path, status, durationMs, traceId, errorCode2) {
429
- return { traceId, method, path, status, durationMs, ...errorCode2 && { errorCode: errorCode2 } };
431
+ return { traceId, method, path, status, durationMs, errorCode: errorCode2 };
430
432
  }
431
433
  function formatMs(ms) {
432
434
  if (ms >= 1000)
@@ -470,16 +472,25 @@ function logIncoming(req, pathname, traceId, ipAddress) {
470
472
  }
471
473
  return log;
472
474
  }
473
- function logOutgoing(req, pathname, status, log, ipAddress, errorCode2) {
475
+ function structuredLine(own, extra) {
476
+ try {
477
+ return JSON.stringify({ ...extra, ...own });
478
+ } catch {
479
+ return JSON.stringify(own);
480
+ }
481
+ }
482
+ function logOutgoing(entry) {
483
+ const { req, pathname, status, log, ipAddress, errorCode: errorCode2, durationMs, extra } = entry;
474
484
  const ms = elapsedMs(log.startTime);
475
485
  if (isProd) {
476
- console.log(JSON.stringify({
486
+ const own = {
477
487
  ts: new Date().toISOString(),
478
488
  level: levelForStatus(status),
479
489
  msg: `${req.method} ${pathname} ${status}`,
480
- ...buildLogFields(req.method, pathname, status, Math.round(ms), log.traceId, errorCode2),
490
+ ...buildLogFields(req.method, pathname, status, durationMs, log.traceId, errorCode2),
481
491
  ip: ipAddress
482
- }));
492
+ };
493
+ console.log(structuredLine(own, extra));
483
494
  return;
484
495
  }
485
496
  const mc = METHOD_COLOR[req.method] ?? c.dim;
@@ -487,14 +498,65 @@ function logOutgoing(req, pathname, status, log, ipAddress, errorCode2) {
487
498
  console.log(`${c.gray}[${timestamp()}]${c.reset} ${mc}${req.method}${c.reset} ${c.dim}${log.traceId}${c.reset} ${c.cyan}←${c.reset} ${safePath(pathname)} ${statusColor(status)}${status}${c.reset}${code} ${durationColor(ms)}${formatMs(ms)}${c.reset} ${ipLabel(ipAddress ?? "")}`);
488
499
  }
489
500
 
501
+ // src/server/logging.ts
502
+ var LOGGER_METHODS = ["info", "warn", "error", "debug"];
503
+ function isBareLogger(value) {
504
+ if (value.logger !== undefined || value.skip !== undefined || value.enrich !== undefined) {
505
+ return false;
506
+ }
507
+ return LOGGER_METHODS.every((method) => typeof value[method] === "function");
508
+ }
509
+ function resolveLoggingConfig(logging) {
510
+ if (logging === false)
511
+ return null;
512
+ if (logging === true)
513
+ return {};
514
+ if (isRecord(logging) && isBareLogger(logging)) {
515
+ throw new Error("[stitchkit] `logging` no longer takes a StitchLogger directly — nest it: " + "`logging: { logger: myLogger }`.");
516
+ }
517
+ return logging;
518
+ }
519
+ function shouldSkipLog(config, req, url) {
520
+ if (!config.skip)
521
+ return false;
522
+ try {
523
+ return config.skip(req, url);
524
+ } catch {
525
+ return false;
526
+ }
527
+ }
528
+ function collectExtraLogFields(config, req, url, outcome) {
529
+ const fields = {};
530
+ const ctx = getRequestContext();
531
+ if (ctx) {
532
+ if (ctx.userId)
533
+ fields.userId = ctx.userId;
534
+ if (ctx.serviceName)
535
+ fields.serviceName = ctx.serviceName;
536
+ if (ctx.action)
537
+ fields.action = ctx.action;
538
+ if (ctx.dimensions)
539
+ fields.dimensions = ctx.dimensions;
540
+ }
541
+ if (config.enrich) {
542
+ try {
543
+ const extra = config.enrich(req, url, outcome);
544
+ if (extra)
545
+ Object.assign(fields, extra);
546
+ } catch {}
547
+ }
548
+ return fields;
549
+ }
550
+
490
551
  // src/server/create.ts
491
552
  function createHandler(config) {
492
553
  const { cors, hooks, logging = false, trustProxy = false } = config;
493
554
  if (cors)
494
555
  assertCorsConfig(cors);
495
- const customLogger = typeof logging === "object" ? logging : null;
496
- const useDefaultLog = logging === true;
497
- const resolveId = config.traceId ?? resolveTraceId;
556
+ const logConfig = resolveLoggingConfig(logging);
557
+ const customLogger = logConfig?.logger ?? null;
558
+ const useDefaultLog = logConfig !== null && !logConfig.logger;
559
+ const customTraceId = config.traceId;
498
560
  const routeMap = buildRouteMap(normalizeGroups(config));
499
561
  validateRoutes(routeMap);
500
562
  for (const shadow of findShadowedRoutes(routeMap, config.rawRoutes)) {
@@ -506,31 +568,56 @@ function createHandler(config) {
506
568
  console.warn(line);
507
569
  }
508
570
  async function dispatch(req, url, traceId, server, clientIp) {
509
- const shouldLogRequest = logging && shouldLog(url.pathname, req.method);
571
+ const shouldLogRequest = logConfig !== null && shouldLog(url.pathname, req.method) && !shouldSkipLog(logConfig, req, url);
510
572
  const ipAddress = extractIp(req, clientIp) || undefined;
511
573
  let reqLog;
512
574
  if (shouldLogRequest && useDefaultLog) {
513
575
  reqLog = logIncoming(req, url.pathname, traceId, ipAddress);
514
576
  }
515
577
  if (shouldLogRequest && customLogger) {
516
- customLogger.debug(`${req.method} ${url.pathname}`, {
517
- traceId,
518
- method: req.method,
519
- path: url.pathname,
520
- ip: ipAddress
521
- });
522
578
  reqLog = { traceId, startTime: performance.now() };
579
+ try {
580
+ customLogger.debug(`${req.method} ${url.pathname}`, {
581
+ traceId,
582
+ method: req.method,
583
+ path: url.pathname,
584
+ ip: ipAddress
585
+ });
586
+ } catch {}
523
587
  }
588
+ let logged = false;
524
589
  const logDone = (status, errorCode2) => {
525
- if (!reqLog)
590
+ if (!reqLog || logged || !logConfig)
526
591
  return;
527
- if (useDefaultLog)
528
- logOutgoing(req, url.pathname, status, reqLog, ipAddress, errorCode2);
529
- if (customLogger) {
592
+ logged = true;
593
+ try {
530
594
  const durationMs = Math.round(elapsedMs(reqLog.startTime));
531
- const level = levelForStatus(status);
532
- customLogger[level](`${req.method} ${url.pathname} ${status}${errorCode2 ? ` ${errorCode2}` : ""} ${durationMs}ms`, buildLogFields(req.method, url.pathname, status, durationMs, reqLog.traceId, errorCode2));
533
- }
595
+ const extra = collectExtraLogFields(logConfig, req, url, {
596
+ status,
597
+ durationMs,
598
+ errorCode: errorCode2
599
+ });
600
+ if (useDefaultLog) {
601
+ logOutgoing({
602
+ req,
603
+ pathname: url.pathname,
604
+ status,
605
+ log: reqLog,
606
+ ipAddress,
607
+ errorCode: errorCode2,
608
+ durationMs,
609
+ extra
610
+ });
611
+ }
612
+ if (customLogger) {
613
+ const level = levelForStatus(status);
614
+ customLogger[level](`${req.method} ${url.pathname} ${status}${errorCode2 ? ` ${errorCode2}` : ""} ${durationMs}ms`, {
615
+ ...extra,
616
+ ...buildLogFields(req.method, url.pathname, status, durationMs, reqLog.traceId, errorCode2),
617
+ ip: ipAddress
618
+ });
619
+ }
620
+ } catch {}
534
621
  };
535
622
  const respondError = async (err, errCtx, endpoint) => {
536
623
  if (hooks?.onError) {
@@ -548,9 +635,7 @@ function createHandler(config) {
548
635
  return json(appErr.toJSON(), appErr.status, cors, req);
549
636
  };
550
637
  if (cors && req.method === "OPTIONS") {
551
- const res = corsPreflightResponse(cors, req);
552
- logDone(204);
553
- return res;
638
+ return corsPreflightResponse(cors, req);
554
639
  }
555
640
  if (hooks?.onRequest) {
556
641
  const earlyResponse = await hooks.onRequest(req);
@@ -623,10 +708,12 @@ function createHandler(config) {
623
708
  if (method.outputSchema) {
624
709
  const checked = validateHandlerOutput(method.outputSchema, result, config.warnOnOutputStrip ? (paths) => {
625
710
  const line = `[stitchkit] output strip ${method.serviceName}.${method.key}: ${paths.join(", ")}`;
626
- if (customLogger)
627
- customLogger.warn(line);
628
- else
629
- console.warn(line);
711
+ try {
712
+ if (customLogger)
713
+ customLogger.warn(line);
714
+ else
715
+ console.warn(line);
716
+ } catch {}
630
717
  } : undefined);
631
718
  if (!checked.ok) {
632
719
  throw new AppError("INTERNAL_SERVER_ERROR", checked.message, 500);
@@ -634,18 +721,20 @@ function createHandler(config) {
634
721
  result = checked.data;
635
722
  }
636
723
  if (result === undefined || result === null) {
724
+ const empty = new Response(null, { status: 204, headers: corsHeaders2(cors, req) });
637
725
  logDone(204);
638
- return new Response(null, { status: 204, headers: corsHeaders2(cors, req) });
726
+ return empty;
639
727
  }
728
+ const body = json(result, 200, cors, req);
640
729
  logDone(200);
641
- return json(result, 200, cors, req);
730
+ return body;
642
731
  } catch (err) {
643
732
  return respondError(err, ctx, method);
644
733
  }
645
734
  }
646
735
  return async (req, server) => {
647
736
  const url = new URL(req.url, "http://localhost");
648
- const traceId = resolveId(req);
737
+ const traceId = customTraceId?.(req) ?? resolveTraceId(req);
649
738
  const clientIp = {
650
739
  trustProxy,
651
740
  socketIp: resolveSocketIp(req, server)
@@ -659,7 +748,8 @@ function createHandler(config) {
659
748
  }
660
749
  function createServer(config) {
661
750
  const { routes, websocket, development, bun: bunExtra, port = 3000, hostname } = config;
662
- const fetch = createHandler(config);
751
+ const handler = createHandler(config);
752
+ const fetch = config.wrapFetch ? config.wrapFetch(handler) : handler;
663
753
  return websocket ? Bun.serve({
664
754
  ...bunExtra,
665
755
  ...routes && { routes },
@@ -1,6 +1,3 @@
1
- import {
2
- resolveTraceContext
3
- } from "./index-khwedj16.js";
4
1
  import {
5
2
  isRecord,
6
3
  isUnsafeKey
@@ -58,6 +55,45 @@ function parseQueryParams(url) {
58
55
  return query;
59
56
  }
60
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
+
61
97
  // src/observability/context.ts
62
98
  import { AsyncLocalStorage } from "node:async_hooks";
63
99
  var storage = new AsyncLocalStorage;
@@ -112,4 +148,4 @@ function wrapInRequestContext(handler, options = {}) {
112
148
  };
113
149
  }
114
150
 
115
- export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
151
+ export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
@@ -1,6 +1,6 @@
1
1
  // src/server/middleware/cors.ts
2
2
  var DEFAULT_CORS_ALLOW_HEADERS = "Content-Type, Authorization, X-Trace-Id, traceparent, tracestate";
3
- var DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Trace-Id";
3
+ var DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Request-Id";
4
4
  function assertCorsConfig(config) {
5
5
  if (config.credentials && (config.origin === undefined || config.origin === "*")) {
6
6
  throw new Error("[stitchkit] cors: `credentials: true` cannot be combined with a wildcard origin. " + "Set `origin` to an explicit string or list.");
package/dist/node.d.ts CHANGED
@@ -9,5 +9,5 @@ export { createHandler } from './server/create';
9
9
  export { createImplement, implement } from './server/implement';
10
10
  export { type NodeServerConfig, type NodeServerHandle, serveNode } from './server/node';
11
11
  export { createSocketIOServer, type SocketIOServerConfig, type SocketIOServerHandle, } from './server/socket-io';
12
- export type { HandlerConfig, RawRoute, RawRouteContext, ServiceDef, } from './server/types';
12
+ export type { FetchComposition, FetchHandler, HandlerConfig, LoggingConfig, LogOutcome, RawRoute, RawRouteContext, ServiceDef, } from './server/types';
13
13
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACxF,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,aAAa,EACb,QAAQ,EACR,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACxF,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC"}
package/dist/node.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  createImplement,
4
4
  createSocketIOServer,
5
5
  implement
6
- } from "./index-y4132gqh.js";
7
- import"./index-zfscdskj.js";
6
+ } from "./index-17jpjnhd.js";
7
+ import"./index-czmqks7r.js";
8
8
  import {
9
9
  AppError,
10
10
  appError,
@@ -15,15 +15,15 @@ import {
15
15
  rateLimited,
16
16
  unauthorized
17
17
  } from "./index-zza375qp.js";
18
- import"./index-dzx781tm.js";
19
- import"./index-khwedj16.js";
18
+ import"./index-9g9d6r1h.js";
20
19
  import"./index-c7nyw0yt.js";
21
20
  // src/server/node.ts
22
21
  import { serve } from "srvx";
23
22
  async function serveNode(config) {
24
- const { port = 3000, hostname, socket, ...handlerConfig } = config;
23
+ const { port = 3000, hostname, socket, wrapFetch, ...handlerConfig } = config;
25
24
  const handler = createHandler(handlerConfig);
26
- const server = serve({ port, hostname, fetch: handler });
25
+ const fetch = wrapFetch ? wrapFetch(handler) : handler;
26
+ const server = serve({ port, hostname, fetch });
27
27
  await server.ready();
28
28
  if (socket) {
29
29
  const nodeServer = server.node?.server;
@@ -97,10 +97,14 @@ export interface WrapRequestContextOptions {
97
97
  * (the inbound `traceparent` continued, or freshly minted), timing and client
98
98
  * info.
99
99
  *
100
- * Compose it as the OUTERMOST wrapper of the server's fetch handler. To make
101
- * the framework router reuse this trace id (so request logs and application
102
- * logs share one id), pass `traceId: getTraceId` to `createServer` /
103
- * `createHandler`.
100
+ * Compose it as the OUTERMOST wrapper of the server's fetch handler with raw
101
+ * `Bun.serve`, or through `wrapFetch` on `createServer` / `serveNode`, which own
102
+ * their own `fetch`.
103
+ *
104
+ * To make the framework router reuse this trace id (so request logs and
105
+ * application logs share one id), pass `traceId: getTraceId` to `createServer` /
106
+ * `createHandler`: outside an active context it yields `undefined` and the
107
+ * framework falls back to its own resolver.
104
108
  */
105
109
  export declare function wrapInRequestContext<S>(handler: (req: Request, server: S) => Promise<Response>, options?: WrapRequestContextOptions): (req: Request, server: S) => Promise<Response>;
106
110
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjE,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,4CAA4C;IAC5C,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;8EAC0E;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAChE;AAID,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED,mEAAmE;AACnE,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAM5E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAG7E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,IAAI,CAGP;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EACvD,OAAO,GAAE,yBAA8B,GACtC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAiBhD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjE,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,4CAA4C;IAC5C,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;8EAC0E;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAChE;AAID,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED,mEAAmE;AACnE,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAM5E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAG7E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,IAAI,CAGP;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EACvD,OAAO,GAAE,yBAA8B,GACtC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAiBhD"}
@@ -1,21 +1,19 @@
1
1
  import {
2
+ childSpan,
3
+ createTraceContext,
4
+ formatTraceparent,
2
5
  getRequestContext,
3
6
  getTraceId,
4
7
  getUserId,
8
+ parseTraceparent,
9
+ resolveTraceContext,
5
10
  runWithRequestContext,
6
11
  setRequestDimensions,
7
12
  setRequestEndpoint,
8
13
  setRequestError,
9
14
  setRequestUser,
10
15
  wrapInRequestContext
11
- } from "../index-dzx781tm.js";
12
- import {
13
- childSpan,
14
- createTraceContext,
15
- formatTraceparent,
16
- parseTraceparent,
17
- resolveTraceContext
18
- } from "../index-khwedj16.js";
16
+ } from "../index-9g9d6r1h.js";
19
17
  import {
20
18
  isRecord,
21
19
  isUnsafeKey
@@ -1,4 +1,4 @@
1
- import type { BunServerConfig, HandlerConfig } from './types';
2
- export declare function createHandler(config: HandlerConfig): (req: Request) => Promise<Response>;
1
+ import type { BunServerConfig, FetchHandler, HandlerConfig } from './types';
2
+ export declare function createHandler(config: HandlerConfig): FetchHandler;
3
3
  export declare function createServer(config: BunServerConfig): Bun.Server<unknown>;
4
4
  //# sourceMappingURL=create.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AAgCA,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,CAyRxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EACZ,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAoVjE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAuBnD"}
@@ -20,6 +20,6 @@ export { staticRoute } from './router';
20
20
  export type { SocketIOServerConfig, SocketIOServerHandle } from './socket-io';
21
21
  export { createSocketIOServer, socketIoLane } from './socket-io';
22
22
  export { type ParseSSEOptions, parseSSE, streamSSE } from './stream';
23
- export type { BunServer, BunServerConfig, HandlerConfig, Handlers, LifecycleHooks, MethodDef, RawRoute, RawRouteContext, RouteGroup, ServerPassthrough, ServiceDef, StitchLogger, } from './types';
23
+ export type { BunServer, BunServerConfig, FetchComposition, FetchHandler, HandlerConfig, Handlers, LifecycleHooks, LoggingConfig, LogOutcome, MethodDef, RawRoute, RawRouteContext, RouteGroup, ServerPassthrough, ServiceDef, StitchLogger, } from './types';
24
24
  export { type ComposedLane, composeWebSocketHandlers, type WebSocketComposeConfig, type WebSocketLane, webSocketLane, } from './websocket';
25
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,SAAS,EACT,cAAc,EACd,cAAc,EACd,KAAK,eAAe,EACpB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,SAAS,EACT,cAAc,EACd,cAAc,EACd,KAAK,eAAe,EACpB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,UAAU,EACV,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
@@ -10,7 +10,7 @@ import {
10
10
  socketIoLane,
11
11
  staticRoute,
12
12
  webSocketLane
13
- } from "../index-y4132gqh.js";
13
+ } from "../index-17jpjnhd.js";
14
14
  import {
15
15
  createAuthHook,
16
16
  createBearerResolver,
@@ -29,7 +29,7 @@ import {
29
29
  DEFAULT_CORS_EXPOSE_HEADERS,
30
30
  corsHeaders,
31
31
  corsPreflightResponse
32
- } from "../index-zfscdskj.js";
32
+ } from "../index-czmqks7r.js";
33
33
  import {
34
34
  jsonSchemaFields,
35
35
  toJsonSchema
@@ -58,8 +58,7 @@ import {
58
58
  getTraceId,
59
59
  resolveSocketIp,
60
60
  resolveTraceId
61
- } from "../index-dzx781tm.js";
62
- import"../index-khwedj16.js";
61
+ } from "../index-9g9d6r1h.js";
63
62
  import {
64
63
  isRecord
65
64
  } from "../index-c7nyw0yt.js";
@@ -2,14 +2,19 @@
2
2
  export declare function elapsedMs(startTime: number): number;
3
3
  /** Map an HTTP status to a log level. */
4
4
  export declare function levelForStatus(status: number): 'error' | 'warn' | 'info';
5
- /** The structured fields shared by every completed-request log line. */
5
+ /**
6
+ * The structured fields shared by every completed-request log line. `errorCode`
7
+ * is always present, `undefined` on success — a conditional key would let an
8
+ * `enrich` value survive on a 200, and these fields must always win the merge.
9
+ * `JSON.stringify` drops the undefined, so the production line is unchanged.
10
+ */
6
11
  export declare function buildLogFields(method: string, path: string, status: number, durationMs: number, traceId: string, errorCode?: string): {
7
12
  traceId: string;
8
13
  method: string;
9
14
  path: string;
10
15
  status: number;
11
16
  durationMs: number;
12
- errorCode?: string;
17
+ errorCode: string | undefined;
13
18
  };
14
19
  export interface RequestLog {
15
20
  traceId: string;
@@ -18,6 +23,33 @@ export interface RequestLog {
18
23
  export declare function shouldLog(pathname: string, method: string): boolean;
19
24
  /** Open the timing window for a request. Development prints a `→` line. */
20
25
  export declare function logIncoming(req: Request, pathname: string, traceId: string, ipAddress?: string): RequestLog;
21
- /** Close a request. Development: `←` line. Production: one structured JSON line. */
22
- export declare function logOutgoing(req: Request, pathname: string, status: number, log: RequestLog, ipAddress?: string, errorCode?: string): void;
26
+ /**
27
+ * Serialise one structured line: consumer fields under the framework's own. A
28
+ * value `JSON.stringify` refuses (a cycle, a `BigInt`) costs the consumer
29
+ * fields for that line — never the record, which is re-emitted alone.
30
+ */
31
+ export declare function structuredLine(own: Record<string, unknown>, extra?: Record<string, unknown>): string;
32
+ /** One finished request, as the formatter needs it. */
33
+ export interface CompletedRequest {
34
+ req: Request;
35
+ pathname: string;
36
+ status: number;
37
+ log: RequestLog;
38
+ ipAddress?: string;
39
+ errorCode?: string;
40
+ /** Duration the caller already measured — the one `enrich` was shown. */
41
+ durationMs: number;
42
+ /**
43
+ * Consumer-supplied fields for the structured line — request-context
44
+ * identity and whatever `enrich` returned. Spread *first* so the framework's
45
+ * own fields overwrite anything that collides with them.
46
+ */
47
+ extra?: Record<string, unknown>;
48
+ }
49
+ /**
50
+ * Close a request. Development: `←` line — deliberately unchanged by `extra`,
51
+ * it is a line to read, not a record to query. Production: one structured JSON
52
+ * line, enriched.
53
+ */
54
+ export declare function logOutgoing(entry: CompletedRequest): void;
23
55
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoBD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAEA;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CA4BN"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoBD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,CAEA;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CAMR;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAwBzD"}
@@ -0,0 +1,20 @@
1
+ import type { LoggingConfig, LogOutcome } from './types';
2
+ /**
3
+ * Normalise `logging` into either a config or `null` (off). `true` is shorthand
4
+ * for `{}`: any object turns logging on, and `logger` decides which sink writes.
5
+ */
6
+ export declare function resolveLoggingConfig(logging: boolean | LoggingConfig): LoggingConfig | null;
7
+ /** Consult the consumer's noise filter. A throw means "do not skip". */
8
+ export declare function shouldSkipLog(config: LoggingConfig, req: Request, url: URL): boolean;
9
+ /**
10
+ * The fields a completion line carries beyond the framework's own — the active
11
+ * request context first (free identity: who, which operation, which tenant),
12
+ * then whatever `enrich` returns, which may override it. Both are merged
13
+ * *under* the framework fields by the caller, so neither can corrupt the record.
14
+ *
15
+ * Returns an empty object when no context is active and no `enrich` is set —
16
+ * the cost of observability that was never wired is one `AsyncLocalStorage`
17
+ * lookup.
18
+ */
19
+ export declare function collectExtraLogFields(config: LoggingConfig, req: Request, url: URL, outcome: LogOutcome): Record<string, unknown>;
20
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/server/logging.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAmBzD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,IAAI,CAU3F;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAQpF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,UAAU,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB"}
@@ -34,8 +34,14 @@ export declare const DEFAULT_CORS_ALLOW_HEADERS = "Content-Type, Authorization,
34
34
  * the request carries credentials — exactly the authenticated download case.
35
35
  * These are headers the server already chose to send; exposing them reveals
36
36
  * nothing new. Opt out with `exposeHeaders: []`.
37
+ *
38
+ * `X-Request-Id` is the trace id every response carries — the id a browser
39
+ * client needs to quote in a bug report and the one a reverse proxy logs.
40
+ * Note the deliberate asymmetry with {@link DEFAULT_CORS_ALLOW_HEADERS}:
41
+ * inbound the id may arrive as `X-Trace-Id`, outbound it is always
42
+ * `X-Request-Id` — one name on the wire out, no alias.
37
43
  */
38
- export declare const DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Trace-Id";
44
+ export declare const DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Request-Id";
39
45
  /**
40
46
  * Reject an unsafe CORS config at construction. `credentials: true` with a
41
47
  * wildcard origin would reflect *any* caller's `Origin` with
@@ -1 +1 @@
1
- {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,qEAC6B,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,uGAC8D,CAAC;AAEvG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAOzD;AAoBD,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,CAKhF"}
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,qEAC6B,CAAC;AAErE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,2BAA2B,yGACgE,CAAC;AAEzG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAOzD;AAoBD,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,CAKhF"}
@@ -1,6 +1,6 @@
1
1
  import type { Server as HttpServer } from 'node:http';
2
- import type { HandlerConfig } from './types';
3
- export interface NodeServerConfig extends HandlerConfig {
2
+ import type { FetchComposition, HandlerConfig } from './types';
3
+ export interface NodeServerConfig extends HandlerConfig, FetchComposition {
4
4
  port?: number;
5
5
  hostname?: string;
6
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/server/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6BnF"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/server/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE/D,MAAM,WAAW,gBAAiB,SAAQ,aAAa,EAAE,gBAAgB;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8BnF"}
@@ -154,6 +154,63 @@ export interface StitchLogger {
154
154
  error(msg: string, data?: Record<string, unknown>): void;
155
155
  debug(msg: string, data?: Record<string, unknown>): void;
156
156
  }
157
+ /** How a request finished — what `LoggingConfig.enrich` gets to react to. */
158
+ export interface LogOutcome {
159
+ status: number;
160
+ durationMs: number;
161
+ errorCode?: string;
162
+ }
163
+ /**
164
+ * Request-logging configuration. `logging: true` is shorthand for `logging: {}`
165
+ * — **any** object turns request logging on; `logger` replaces the built-in
166
+ * sink, and `skip` / `enrich` apply to whichever sink is active.
167
+ */
168
+ export interface LoggingConfig {
169
+ /** Send lines here instead of to the built-in formatter. */
170
+ logger?: StitchLogger;
171
+ /**
172
+ * Silence a request. Consulted *after* the built-in noise filter (framework
173
+ * assets, `favicon`, preflights), so it can only quieten more, never restore
174
+ * a line the framework drops — `/_bun/` assets are served by the runtime
175
+ * before `fetch` sees them, so un-skipping would be a promise the router
176
+ * cannot keep. A throw is swallowed and treated as "do not skip".
177
+ *
178
+ * The case this exists for: a monitoring probe on a path that 404s every
179
+ * cycle, and Socket.IO's polling transport, which logs a line per poll.
180
+ */
181
+ skip?: (req: Request, url: URL) => boolean;
182
+ /**
183
+ * Extra fields for the completion line. Runs once per request, at close —
184
+ * not on the development `→` breadcrumb — and its keys are merged **under**
185
+ * the framework's own, which always win: `traceId`, `method`, `path`,
186
+ * `status`, `durationMs`, `errorCode` and `ip` in both sinks, plus `ts`,
187
+ * `level` and `msg` on the built-in production line.
188
+ *
189
+ * Four things to know:
190
+ * - It reaches the structured output only: the production JSON line and a
191
+ * custom logger's `data`. The development `←` line stays as it is — it is a
192
+ * human-readable line, not a record — so **enriched fields are invisible in
193
+ * development**, which is exactly where they get written.
194
+ * - Values must survive `JSON.stringify` on the built-in line. One that does
195
+ * not (a cycle, a `BigInt`) costs the extra fields for that line; the
196
+ * framework's own are re-emitted alone rather than losing the record.
197
+ * - It is synchronous and the request body is **already consumed** by the
198
+ * time it runs. Anything body-derived belongs in `createAuditHook`, which
199
+ * clones the request before the handler.
200
+ * - Its values reach the sink as given. A header echoed straight into a
201
+ * text-based logger can inject line breaks — sanitise anything
202
+ * caller-controlled, as the framework does for the request path.
203
+ *
204
+ * A throw is swallowed; the line is still written without the extra fields.
205
+ */
206
+ enrich?: (req: Request, url: URL, outcome: LogOutcome) => Record<string, unknown> | undefined;
207
+ }
208
+ /**
209
+ * A fetch handler — what `createHandler` returns and what the servers hand to
210
+ * the runtime. The optional second argument is the runtime's server handle:
211
+ * Bun passes one (raw routes need it for upgrades), Node adapters never do.
212
+ */
213
+ export type FetchHandler = (req: Request, server?: BunServer) => Promise<Response>;
157
214
  /**
158
215
  * Runtime-neutral handler config — everything `createHandler` needs.
159
216
  * No Bun globals, no Bun types. This is the portability seam.
@@ -181,7 +238,7 @@ export interface HandlerConfig {
181
238
  maxUploadBytes?: number;
182
239
  cors?: CorsConfig;
183
240
  hooks?: LifecycleHooks;
184
- logging?: boolean | StitchLogger;
241
+ logging?: boolean | LoggingConfig;
185
242
  /**
186
243
  * Report handler-output keys the contract schema removed, as dot-paths, through
187
244
  * the configured logger. **Off by default** — the strip itself is correct (the
@@ -195,7 +252,14 @@ export interface HandlerConfig {
195
252
  * → ADR 0037.
196
253
  */
197
254
  warnOnOutputStrip?: boolean;
198
- traceId?: (req: Request) => string;
255
+ /**
256
+ * Resolve the trace id for a request. Returning `undefined` falls back to
257
+ * {@link resolveTraceId} (a trusted inbound `x-request-id` / `x-trace-id`,
258
+ * else a fresh id) — which is what makes `traceId: getTraceId` work: outside
259
+ * an active observability context it yields `undefined`, and the framework
260
+ * mints one instead of stamping the string `"undefined"`.
261
+ */
262
+ traceId?: (req: Request) => string | undefined;
199
263
  /**
200
264
  * Trust the `x-forwarded-for` / `x-real-ip` headers for the client IP.
201
265
  * These are client-controllable — enable only when the server runs behind a
@@ -215,11 +279,29 @@ type BunDevelopmentOptions = BunServeOptions extends {
215
279
  development?: infer T;
216
280
  } ? T : never;
217
281
  export type ServerPassthrough = Omit<BunServeOptions, 'fetch' | 'port' | 'hostname' | 'unix' | 'routes' | 'websocket' | 'development'>;
282
+ /**
283
+ * The composition seam shared by the servers that own their own `fetch`.
284
+ *
285
+ * `wrapInRequestContext` and `createAuditHook` must sit **outside** the
286
+ * handler, which used to mean building the server by hand — `createServer` and
287
+ * `serveNode` construct `fetch` internally, so neither could reach the
288
+ * observability layer at all. `wrapFetch` is where those wrappers go.
289
+ *
290
+ * Order is the consumer's, and it matters: `wrapInRequestContext` outermost,
291
+ * the audit wrapper inside it, because the audit hook reads that context.
292
+ *
293
+ * ```ts
294
+ * createServer({ services, wrapFetch: (h) => wrapInRequestContext(audit.http(h)) })
295
+ * ```
296
+ */
297
+ export interface FetchComposition {
298
+ wrapFetch?: (fetch: FetchHandler) => FetchHandler;
299
+ }
218
300
  /**
219
301
  * Full config for `createServer` — extends `HandlerConfig` with Bun-specific
220
302
  * options (`Bun.serve` routes, websocket, development, passthrough).
221
303
  */
222
- export interface BunServerConfig extends HandlerConfig {
304
+ export interface BunServerConfig extends HandlerConfig, FetchComposition {
223
305
  port?: number;
224
306
  hostname?: string;
225
307
  routes?: BunRoutes;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,13 @@ export interface ToolCallRecord {
15
15
  durationMs: number;
16
16
  /** Transport tag the call came in on (`ctx.source`). */
17
17
  source: string;
18
+ /**
19
+ * The active trace id, when an observability context is running — the key
20
+ * that joins this line to the HTTP request that triggered the tool call.
21
+ * Absent when nothing established a context (`wrapInRequestContext`, or a
22
+ * server's `wrapFetch`).
23
+ */
24
+ traceId?: string;
18
25
  }
19
26
  /** Config for `createToolLogger`. */
20
27
  export interface ToolLoggerConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-logger.d.ts","sourceRoot":"","sources":["../../src/tools/tool-logger.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,gBAAqB,GAAG,aAAa,CAoB7E"}
1
+ {"version":3,"file":"tool-logger.d.ts","sourceRoot":"","sources":["../../src/tools/tool-logger.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,gBAAqB,GAAG,aAAa,CAqB7E"}
package/dist/tools.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  } from "./index-jvescqgr.js";
6
6
  import {
7
7
  DEFAULT_CORS_ALLOW_HEADERS
8
- } from "./index-zfscdskj.js";
8
+ } from "./index-czmqks7r.js";
9
9
  import {
10
10
  assertToolName,
11
11
  assertUniqueToolName,
@@ -30,7 +30,9 @@ import {
30
30
  isWithinDir,
31
31
  mergeMeta
32
32
  } from "./index-zza375qp.js";
33
- import"./index-khwedj16.js";
33
+ import {
34
+ getTraceId
35
+ } from "./index-9g9d6r1h.js";
34
36
  import {
35
37
  isRecord,
36
38
  typedEntries
@@ -1223,7 +1225,8 @@ function createToolLogger(config = {}) {
1223
1225
  ok: result.ok,
1224
1226
  code: result.ok ? undefined : result.code,
1225
1227
  durationMs: Math.round(durationMs),
1226
- source: String(context.source)
1228
+ source: String(context.source),
1229
+ traceId: getTraceId()
1227
1230
  };
1228
1231
  const codePart = result.ok ? "" : ` ${result.code}`;
1229
1232
  log(`[tool] ${result.ok ? "ok" : "warn"} ${toolName} (${endpoint.serviceName}.${endpoint.key})${codePart} ${record.durationMs}ms`);
package/llms-full.txt CHANGED
@@ -620,11 +620,47 @@ server. See [Testing & deployment](./testing-and-deployment.md).
620
620
  | `port` / `hostname` | listen address — port defaults to `3000` |
621
621
  | `cors` | CORS policy — `{ origin, credentials, methods, headers, exposeHeaders }` |
622
622
  | `hooks` | lifecycle hooks (see below) |
623
- | `logging` | `true` for built-in request logs, or a custom `StitchLogger` |
624
- | `traceId` | override per-request trace-id resolution |
623
+ | `logging` | `true` for built-in request logs, or a `LoggingConfig` (see below) |
624
+ | `traceId` | override per-request trace-id resolution — may return `undefined` to fall back |
625
+ | `wrapFetch` | compose wrappers around the finished handler (request context, audit) |
625
626
  | `websocket` | Bun WebSocket handlers — e.g. from `createSocketIOServer` |
626
627
  | `routes` / `development` / `bun` | passthrough to `Bun.serve` |
627
628
 
629
+ ### Request logging
630
+
631
+ `logging: true` is shorthand for `logging: {}` — **any object turns logging
632
+ on**, and the fields tune it:
633
+
634
+ ```ts
635
+ createServer({
636
+ services,
637
+ logging: {
638
+ // Route lines into your stack instead of the built-in formatter.
639
+ logger: myLogger,
640
+ // Silence noise. Runs after the built-in filter (framework assets,
641
+ // favicon, preflights), so it can only quieten more.
642
+ skip: (_req, url) => url.pathname === '/health' || url.pathname.startsWith('/socket.io/'),
643
+ // Extra fields on the completion line.
644
+ enrich: (req, _url, { status }) => ({
645
+ userAgent: req.headers.get('user-agent') ?? undefined,
646
+ cacheable: status === 200,
647
+ }),
648
+ },
649
+ })
650
+ ```
651
+
652
+ Three things worth knowing about `enrich`: it reaches the **structured** output
653
+ only (the production JSON line and a custom logger's `data`) — the development
654
+ `←` line stays human-readable, so enriched fields are invisible in dev; it runs
655
+ at close, when the request body is already consumed; and framework fields
656
+ (`traceId`, `status`, `path`, …) always win a key collision. A throw in `skip`
657
+ or `enrich` is swallowed — neither can fail a request.
658
+
659
+ With an observability context active, the line also carries `userId`,
660
+ `serviceName`, `action` and `dimensions` for free — and, like `enrich`'s fields,
661
+ only in the structured output, never on the development `←` line. See
662
+ [Observability](./observability.md).
663
+
628
664
  ## Route groups
629
665
 
630
666
  A group gives a set of services a shared path prefix and its own hooks:
@@ -1752,7 +1788,10 @@ mountMcp(server, services, { hooks: createToolLogger() })
1752
1788
  ```
1753
1789
 
1754
1790
  Pass `log` to redirect the line, or `onRecord` to feed a metrics sink the
1755
- structured `ToolCallRecord`. For a boot-time picture of what is exposed where,
1791
+ structured `ToolCallRecord`. That record carries `traceId` whenever an
1792
+ observability context is active, so a tool call made inside an HTTP request
1793
+ joins that request's log line on one key — see
1794
+ [Observability](./observability.md). For a boot-time picture of what is exposed where,
1756
1795
  `summarizeTransports(services)` returns per-transport operation counts (HTTP /
1757
1796
  MCP / AGENT / CLI) for you to log.
1758
1797
 
@@ -2790,6 +2829,16 @@ Bun.serve({
2790
2829
  })
2791
2830
  ```
2792
2831
 
2832
+ `createServer` and `serveNode` build their own `fetch`, so compose through
2833
+ **`wrapFetch`** instead — same order, the context outermost:
2834
+
2835
+ ```ts
2836
+ createServer({
2837
+ services,
2838
+ wrapFetch: (fetch) => wrapInRequestContext(audit.http(fetch)),
2839
+ })
2840
+ ```
2841
+
2793
2842
  Some fields are filled in late. Set them from the hooks that know:
2794
2843
 
2795
2844
  ```ts
@@ -2829,8 +2878,51 @@ application logs carry one id — by passing `getTraceId` as the resolver:
2829
2878
  createHandler({ /* … */ traceId: getTraceId })
2830
2879
  ```
2831
2880
 
2881
+ `getTraceId` returns `undefined` outside an active context, and the framework
2882
+ falls back to its own resolver — a trusted inbound `x-request-id` / `x-trace-id`,
2883
+ else a fresh id — so the line never carries the string `"undefined"`.
2884
+
2832
2885
  `getRequestContext()` / `getTraceId()` then return the active values from
2833
2886
  anywhere in the call — stamp `getTraceId()` onto every line your logger writes.
2887
+ The **request log picks the context up on its own**: with a context active, each
2888
+ completion line carries `userId`, `serviceName`, `action` and `dimensions`
2889
+ without any configuration.
2890
+
2891
+ ⚠️ In the **structured** output only — the production JSON line and a custom
2892
+ `logger`'s `data`. The development `←` line is a line to read, not a record to
2893
+ query, and never carries them (nor `enrich`'s fields). On `logging: true` in
2894
+ development you will see no difference; check with `NODE_ENV=production` or a
2895
+ custom `logger`.
2896
+
2897
+ ### Correlating with a reverse proxy
2898
+
2899
+ Every response the stitchkit handler produces carries the resolved id as
2900
+ **`x-request-id`**. With `cors` configured it is in the default
2901
+ `Access-Control-Expose-Headers`, so a browser client can read it and quote it in
2902
+ a bug report. Note the deliberate asymmetry: inbound the id may arrive as
2903
+ `X-Trace-Id` *or* `X-Request-Id`; outbound there is one name and no alias.
2904
+
2905
+ Log the same id from nginx and the two logs join on one key. `log_format` and
2906
+ `map` are `http {}`-context directives — put the block there, not inside
2907
+ `server {}`:
2908
+
2909
+ ```nginx
2910
+ log_format stitch '$remote_addr $status $request_time rid=$rid "$request"';
2911
+
2912
+ # Fall back to nginx's own id for responses stitchkit never produced — Bun's
2913
+ # native `routes`, a throwing `onRequest` (which escapes before any response
2914
+ # exists), a redirect whose headers are immutable.
2915
+ map $upstream_http_x_request_id $rid {
2916
+ "" $request_id;
2917
+ default $upstream_http_x_request_id;
2918
+ }
2919
+
2920
+ access_log /var/log/nginx/access.log stitch;
2921
+ ```
2922
+
2923
+ `grep rid=<id>` across both logs then reconstructs the whole request. Tool calls
2924
+ join too: `createToolLogger`'s record carries `traceId`, so an MCP or agent call
2925
+ made inside a request lines up with it.
2834
2926
 
2835
2927
  ### Trace context
2836
2928
 
@@ -3076,10 +3168,13 @@ Notes for a Node host:
3076
3168
 
3077
3169
  - **CORS** — set `cors.origin` to your real front-end origin(s). Do not ship
3078
3170
  `origin: '*'` with credentials.
3079
- - **Logging** — `logging: true` for built-in request logs, or pass a
3080
- `StitchLogger` to route them into your logging stack.
3171
+ - **Logging** — `logging: true` for built-in request logs, or
3172
+ `logging: { logger, skip, enrich }` to route them into your logging stack,
3173
+ drop probe noise and add your own fields.
3081
3174
  - **Trace ids** — override `traceId` to reuse an id your platform already
3082
- assigns, so request logs and application logs share one id.
3175
+ assigns, so request logs and application logs share one id. Every response
3176
+ carries it as `x-request-id`; log `$upstream_http_x_request_id` at the proxy
3177
+ to join the two logs.
3083
3178
  - **Rate limiting** — `createRateLimiter` in `onRequest` for a global limit;
3084
3179
  per-route limits belong in `beforeHandle`.
3085
3180
  - **Auth** — a `createAuthHook` `beforeHandle` guards every transport at once;
@@ -3509,6 +3604,10 @@ Also re-exports the error helpers from `stitchkit/contract`.
3509
3604
  | `BunServer` | _type_ | the `Bun.serve` instance type |
3510
3605
  | `ServerPassthrough` | _type_ | extra `Bun.serve` options |
3511
3606
  | `StitchLogger` | _type_ | the custom-logger interface |
3607
+ | `LoggingConfig` | _type_ | the `logging` object — `logger` / `skip` / `enrich` |
3608
+ | `LogOutcome` | _type_ | how a request finished, as `enrich` sees it |
3609
+ | `FetchHandler` | _type_ | what `createHandler` returns |
3610
+ | `FetchComposition` | _type_ | the `wrapFetch` seam shared by the servers |
3512
3611
 
3513
3612
  ### Auth
3514
3613
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",
@@ -1,40 +0,0 @@
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 };