stitchkit 0.56.0 → 0.56.2

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.
Files changed (73) hide show
  1. package/README.md +12 -3
  2. package/dist/agent-runtime/compaction.d.ts +33 -0
  3. package/dist/agent-runtime/compaction.d.ts.map +1 -0
  4. package/dist/agent-runtime/coordinator.d.ts +24 -0
  5. package/dist/agent-runtime/coordinator.d.ts.map +1 -0
  6. package/dist/agent-runtime/events.d.ts +454 -0
  7. package/dist/agent-runtime/events.d.ts.map +1 -0
  8. package/dist/agent-runtime/history.d.ts +11 -0
  9. package/dist/agent-runtime/history.d.ts.map +1 -0
  10. package/dist/agent-runtime/managed-tools.d.ts +18 -0
  11. package/dist/agent-runtime/managed-tools.d.ts.map +1 -0
  12. package/dist/agent-runtime/models.d.ts +51 -0
  13. package/dist/agent-runtime/models.d.ts.map +1 -0
  14. package/dist/agent-runtime/observability.d.ts +134 -0
  15. package/dist/agent-runtime/observability.d.ts.map +1 -0
  16. package/dist/agent-runtime/prompt.d.ts +50 -0
  17. package/dist/agent-runtime/prompt.d.ts.map +1 -0
  18. package/dist/agent-runtime/protocol.d.ts +16 -0
  19. package/dist/agent-runtime/protocol.d.ts.map +1 -0
  20. package/dist/agent-runtime/runtime.d.ts +120 -0
  21. package/dist/agent-runtime/runtime.d.ts.map +1 -0
  22. package/dist/agent-runtime/schemas.d.ts +470 -0
  23. package/dist/agent-runtime/schemas.d.ts.map +1 -0
  24. package/dist/agent-runtime/store.d.ts +905 -0
  25. package/dist/agent-runtime/store.d.ts.map +1 -0
  26. package/dist/agent-runtime/testing.d.ts +17 -0
  27. package/dist/agent-runtime/testing.d.ts.map +1 -0
  28. package/dist/agent-runtime-openrouter.d.ts +6 -0
  29. package/dist/agent-runtime-openrouter.d.ts.map +1 -0
  30. package/dist/agent-runtime-openrouter.js +46 -0
  31. package/dist/agent-runtime.d.ts +13 -0
  32. package/dist/agent-runtime.d.ts.map +1 -0
  33. package/dist/agent-runtime.js +1931 -0
  34. package/dist/cli.js +8 -5
  35. package/dist/index-0nc0cddp.js +178 -0
  36. package/dist/{index-6y759j86.js → index-1tkyng3g.js} +9 -57
  37. package/dist/{index-sm2tjx06.js → index-41wm56v0.js} +2 -2
  38. package/dist/index-6djpbnda.js +56 -0
  39. package/dist/{index-j3dem06f.js → index-7c0gkyvj.js} +5 -3
  40. package/dist/{index-n4nfa7gh.js → index-9zn9fb4e.js} +74 -10
  41. package/dist/{index-xy8fmh6w.js → index-f6pymtqe.js} +3 -3
  42. package/dist/{index-jcc611vh.js → index-gnvzyw0k.js} +2 -2
  43. package/dist/{index-qh4xevf5.js → index-mr617n62.js} +4 -2
  44. package/dist/{index-5r13htq1.js → index-ps5pxp3h.js} +1 -1
  45. package/dist/index-sa2mbwa7.js +336 -0
  46. package/dist/index-smpbdg6k.js +27 -0
  47. package/dist/{index-7eq9va6e.js → index-y2rb7dwx.js} +1 -27
  48. package/dist/{index-escqg10p.js → index-zk5zn2nh.js} +32 -334
  49. package/dist/internal/observability-sink.d.ts +26 -0
  50. package/dist/internal/observability-sink.d.ts.map +1 -0
  51. package/dist/node.js +6 -5
  52. package/dist/observability/audit.d.ts +4 -0
  53. package/dist/observability/audit.d.ts.map +1 -1
  54. package/dist/observability/event.d.ts +5 -0
  55. package/dist/observability/event.d.ts.map +1 -1
  56. package/dist/observability/index.js +29 -186
  57. package/dist/remote.js +4 -3
  58. package/dist/server/create.d.ts.map +1 -1
  59. package/dist/server/error-hook.d.ts +10 -8
  60. package/dist/server/error-hook.d.ts.map +1 -1
  61. package/dist/server/index.js +11 -8
  62. package/dist/server/logger.d.ts.map +1 -1
  63. package/dist/server/request-body.d.ts.map +1 -1
  64. package/dist/testing.js +5 -3
  65. package/dist/tools/agent.d.ts.map +1 -1
  66. package/dist/tools/execute.d.ts +7 -0
  67. package/dist/tools/execute.d.ts.map +1 -1
  68. package/dist/tools.d.ts +2 -1
  69. package/dist/tools.d.ts.map +1 -1
  70. package/dist/tools.js +23 -12
  71. package/llms-full.txt +429 -18
  72. package/llms.txt +1 -0
  73. package/package.json +16 -3
package/dist/cli.js CHANGED
@@ -5,14 +5,17 @@ import {
5
5
  emitResult,
6
6
  parseCliArgs,
7
7
  pollUntilDone
8
- } from "./index-escqg10p.js";
8
+ } from "./index-zk5zn2nh.js";
9
+ import"./index-sa2mbwa7.js";
9
10
  import"./index-sbdmyz75.js";
10
- import"./index-6y759j86.js";
11
+ import"./index-1tkyng3g.js";
12
+ import"./index-6djpbnda.js";
11
13
  import"./index-cby4ar3v.js";
12
- import"./index-j3dem06f.js";
13
- import"./index-5r13htq1.js";
14
+ import"./index-7c0gkyvj.js";
15
+ import"./index-ps5pxp3h.js";
14
16
  import"./index-6k1937bx.js";
15
- import"./index-7eq9va6e.js";
17
+ import"./index-y2rb7dwx.js";
18
+ import"./index-smpbdg6k.js";
16
19
  import"./index-1bx83sw4.js";
17
20
  export {
18
21
  DEFAULT_EXIT_CODES,
@@ -0,0 +1,178 @@
1
+ // src/observability/status.ts
2
+ import { z } from "zod";
3
+ var NonNegativeIntegerSchema = z.number().int().nonnegative();
4
+ var ObservabilitySinkStatusSchema = z.object({
5
+ capacity: NonNegativeIntegerSchema,
6
+ received: NonNegativeIntegerSchema,
7
+ accepted: NonNegativeIntegerSchema,
8
+ filtered: NonNegativeIntegerSchema,
9
+ completed: NonNegativeIntegerSchema,
10
+ dropped: NonNegativeIntegerSchema,
11
+ failed: NonNegativeIntegerSchema,
12
+ preparationFailed: NonNegativeIntegerSchema,
13
+ preparing: NonNegativeIntegerSchema,
14
+ pending: NonNegativeIntegerSchema,
15
+ closed: z.boolean()
16
+ }).readonly();
17
+ var ObservabilityStatusObjectSchema = z.object({
18
+ request: ObservabilitySinkStatusSchema.optional(),
19
+ tools: ObservabilitySinkStatusSchema.optional(),
20
+ total: ObservabilitySinkStatusSchema
21
+ });
22
+ var ObservabilityStatusSchema = ObservabilityStatusObjectSchema.readonly();
23
+ var ObservabilityDrainReportSchema = ObservabilityStatusObjectSchema.extend({
24
+ durationMs: z.number().nonnegative()
25
+ }).readonly();
26
+ var SUMMED_STATUS_KEYS = [
27
+ "capacity",
28
+ "received",
29
+ "accepted",
30
+ "filtered",
31
+ "completed",
32
+ "dropped",
33
+ "failed",
34
+ "preparationFailed",
35
+ "preparing",
36
+ "pending"
37
+ ];
38
+ function aggregateObservabilityStatus(surfaces, closed) {
39
+ const totals = {
40
+ capacity: 0,
41
+ received: 0,
42
+ accepted: 0,
43
+ filtered: 0,
44
+ completed: 0,
45
+ dropped: 0,
46
+ failed: 0,
47
+ preparationFailed: 0,
48
+ preparing: 0,
49
+ pending: 0
50
+ };
51
+ for (const surface of surfaces) {
52
+ for (const key of SUMMED_STATUS_KEYS)
53
+ totals[key] += surface[key];
54
+ }
55
+ return ObservabilitySinkStatusSchema.parse({ ...totals, closed });
56
+ }
57
+
58
+ // src/internal/observability-sink.ts
59
+ var DEFAULT_MAX_PENDING = 1000;
60
+ function invokeIsolated(callback) {
61
+ if (!callback)
62
+ return;
63
+ Promise.resolve().then(callback).catch(() => {});
64
+ }
65
+ function createBoundedSinkManager(config) {
66
+ const maxPending = config.maxPending ?? DEFAULT_MAX_PENDING;
67
+ if (!Number.isSafeInteger(maxPending) || maxPending <= 0) {
68
+ throw new TypeError("Observability maxPending must be a positive safe integer");
69
+ }
70
+ let sequence = 0;
71
+ let closed = false;
72
+ let received = 0;
73
+ let accepted = 0;
74
+ let filtered = 0;
75
+ let completed = 0;
76
+ let dropped = 0;
77
+ let failed = 0;
78
+ let preparationFailed = 0;
79
+ let closePromise;
80
+ const preparing = new Map;
81
+ const writes = new Map;
82
+ const reportError = (error, event) => {
83
+ invokeIsolated(config.onSinkError ? () => config.onSinkError?.({ error, ...event !== undefined && { event } }) : undefined);
84
+ };
85
+ const reportDrop = (reason, event) => {
86
+ invokeIsolated(config.onDrop ? () => config.onDrop?.({ reason, event, pending: writes.size }) : undefined);
87
+ };
88
+ const admit = (id, event) => {
89
+ try {
90
+ if (config.filter && !config.filter(event)) {
91
+ filtered += 1;
92
+ return;
93
+ }
94
+ } catch (error) {
95
+ preparationFailed += 1;
96
+ reportError(error, event);
97
+ return;
98
+ }
99
+ if (writes.size >= maxPending) {
100
+ dropped += 1;
101
+ reportDrop("capacity", event);
102
+ return;
103
+ }
104
+ accepted += 1;
105
+ const write = Promise.resolve().then(() => config.write(event)).then(() => {
106
+ completed += 1;
107
+ }).catch((error) => {
108
+ failed += 1;
109
+ reportError(error, event);
110
+ }).finally(() => writes.delete(id));
111
+ writes.set(id, write);
112
+ };
113
+ const awaitGeneration = async (boundary) => {
114
+ const through = (values) => [...values].filter(([id]) => id <= boundary).map(([, value]) => value);
115
+ await Promise.allSettled(through(preparing));
116
+ await Promise.allSettled(through(writes));
117
+ };
118
+ return {
119
+ submit(produce) {
120
+ received += 1;
121
+ const id = ++sequence;
122
+ if (closed) {
123
+ Promise.resolve().then(produce).then((event) => {
124
+ dropped += 1;
125
+ reportDrop("closed", event);
126
+ }).catch((error) => {
127
+ preparationFailed += 1;
128
+ reportError(error);
129
+ });
130
+ return;
131
+ }
132
+ const preparation = Promise.resolve().then(produce).then((event) => admit(id, event)).catch((error) => {
133
+ preparationFailed += 1;
134
+ reportError(error);
135
+ }).finally(() => preparing.delete(id));
136
+ preparing.set(id, preparation);
137
+ },
138
+ flush() {
139
+ return awaitGeneration(sequence);
140
+ },
141
+ getStatus() {
142
+ return ObservabilitySinkStatusSchema.parse({
143
+ capacity: maxPending,
144
+ received,
145
+ accepted,
146
+ filtered,
147
+ completed,
148
+ dropped,
149
+ failed,
150
+ preparationFailed,
151
+ preparing: preparing.size,
152
+ pending: writes.size,
153
+ closed
154
+ });
155
+ },
156
+ close() {
157
+ if (closePromise)
158
+ return closePromise;
159
+ closed = true;
160
+ closePromise = awaitGeneration(sequence).then(() => ObservabilitySinkStatusSchema.parse({
161
+ capacity: maxPending,
162
+ received,
163
+ accepted,
164
+ filtered,
165
+ completed,
166
+ dropped,
167
+ failed,
168
+ preparationFailed,
169
+ preparing: preparing.size,
170
+ pending: writes.size,
171
+ closed
172
+ }));
173
+ return closePromise;
174
+ }
175
+ };
176
+ }
177
+
178
+ export { ObservabilitySinkStatusSchema, ObservabilityStatusSchema, ObservabilityDrainReportSchema, aggregateObservabilityStatus, createBoundedSinkManager };
@@ -1,9 +1,12 @@
1
+ import {
2
+ mergeSchemas
3
+ } from "./index-6djpbnda.js";
1
4
  import {
2
5
  toJsonSchema
3
6
  } from "./index-cby4ar3v.js";
4
7
  import {
5
8
  isRecord
6
- } from "./index-7eq9va6e.js";
9
+ } from "./index-smpbdg6k.js";
7
10
 
8
11
  // src/tools/portable-formats.ts
9
12
  var PORTABLE_JSON_SCHEMA_FORMATS = new Set([
@@ -557,57 +560,6 @@ function findUntypedProperties(schema, prefix = "") {
557
560
  return found;
558
561
  }
559
562
 
560
- // src/tools/schema.ts
561
- import { z } from "zod";
562
- function objectShapeKeys(schema) {
563
- return schema instanceof z.ZodObject ? Object.keys(schema.shape) : [];
564
- }
565
- function keyPolicyOf(schema) {
566
- return schema.def.catchall;
567
- }
568
- function rebuildObject(source, shape) {
569
- return withKeyPolicy(z.object(shape), keyPolicyOf(source));
570
- }
571
- function withKeyPolicy(object, policy) {
572
- if (policy === undefined)
573
- return object;
574
- return object.catchall(representable(policy));
575
- }
576
- function representable(policy) {
577
- if (policy instanceof z.ZodNever || policy instanceof z.ZodUnknown)
578
- return policy;
579
- if (!(policy instanceof z.ZodType))
580
- return z.unknown();
581
- try {
582
- toJsonSchema(policy, "input");
583
- return policy;
584
- } catch {
585
- return z.unknown();
586
- }
587
- }
588
- function mergeSchemas(paramsSchema, inputSchema) {
589
- if (paramsSchema && !(paramsSchema instanceof z.ZodObject)) {
590
- throw new Error("Tool params schema must be a z.object()");
591
- }
592
- const paramsObject = paramsSchema instanceof z.ZodObject ? paramsSchema : undefined;
593
- if (!inputSchema) {
594
- return paramsObject ?? z.object({});
595
- }
596
- if (inputSchema instanceof z.ZodObject) {
597
- if (paramsObject) {
598
- const conflicts = Object.keys(paramsObject.shape).filter((key) => (key in inputSchema.shape));
599
- if (conflicts.length > 0) {
600
- throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
601
- }
602
- }
603
- return rebuildObject(inputSchema, {
604
- ...paramsObject?.shape ?? {},
605
- ...inputSchema.shape
606
- });
607
- }
608
- return paramsObject ? z.intersection(paramsObject, inputSchema) : inputSchema;
609
- }
610
-
611
563
  // src/tools/names.ts
612
564
  var SINGULAR_EXCEPTIONS = new Set([
613
565
  "analytics",
@@ -674,7 +626,7 @@ function assertUniqueToolName(name, taken, surface) {
674
626
  }
675
627
 
676
628
  // src/tools/presentation.ts
677
- import { z as z2 } from "zod";
629
+ import { z } from "zod";
678
630
  function withoutDialect(schema) {
679
631
  const result = {};
680
632
  for (const [key, value] of Object.entries(schema)) {
@@ -768,7 +720,7 @@ function buildToolPresentationSchema(config) {
768
720
  };
769
721
  }
770
722
  if (config.extendSchema) {
771
- const extra = namespaceLocalReferences(schemaFromZod(z2.object(config.extendSchema), unrepresentable, flatten), "extend");
723
+ const extra = namespaceLocalReferences(schemaFromZod(z.object(config.extendSchema), unrepresentable, flatten), "extend");
772
724
  if (extra) {
773
725
  presentation = mergeObjectSchemas(withoutDialect(extra), withoutDialect(presentation), true);
774
726
  }
@@ -789,7 +741,7 @@ function presentationMetadata(schema) {
789
741
  }
790
742
 
791
743
  // src/tools/internal/surface-projector.ts
792
- import { z as z3 } from "zod";
744
+ import { z as z2 } from "zod";
793
745
 
794
746
  // src/tools/mcp-round-policy.ts
795
747
  function validateMcpRoundPolicy(tool, policy, runtime) {
@@ -817,7 +769,7 @@ function validateMcpRoundPolicy(tool, policy, runtime) {
817
769
 
818
770
  // src/tools/internal/surface-projector.ts
819
771
  function assertToolExtensionCompatible(base, extra) {
820
- if (!(base instanceof z3.ZodObject))
772
+ if (!(base instanceof z2.ZodObject))
821
773
  return;
822
774
  const conflicts = Object.keys(extra).filter((key) => (key in base.shape));
823
775
  if (conflicts.length > 0) {
@@ -1028,4 +980,4 @@ function prepareProjectedMcpTools(tools, config = {}) {
1028
980
  return prepared;
1029
981
  }
1030
982
 
1031
- export { objectShapeKeys, rebuildObject, mergeSchemas, validateMcpRoundPolicy, assertToolName, assertUniqueToolName, PORTABLE_JSON_SCHEMA_FORMATS, findNonPortableFormats, flattenToolJsonSchema, buildToolPresentationSchema, presentationMetadata, findUntypedProperties, assertToolExtensionCompatible, projectRuntimeTool, projectToolSurface, mcpProjectionCandidate, prepareProjectedMcpTools };
983
+ export { validateMcpRoundPolicy, assertToolName, assertUniqueToolName, PORTABLE_JSON_SCHEMA_FORMATS, findNonPortableFormats, flattenToolJsonSchema, buildToolPresentationSchema, presentationMetadata, findUntypedProperties, assertToolExtensionCompatible, projectRuntimeTool, projectToolSurface, mcpProjectionCandidate, prepareProjectedMcpTools };
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isUnsafeKey,
3
3
  mergeMeta
4
- } from "./index-5r13htq1.js";
4
+ } from "./index-ps5pxp3h.js";
5
5
  import {
6
6
  callRuntimeHandler,
7
7
  isRecord,
8
8
  transportResult,
9
9
  typedEntries
10
- } from "./index-7eq9va6e.js";
10
+ } from "./index-smpbdg6k.js";
11
11
 
12
12
  // src/server/middleware/cors.ts
13
13
  var DEFAULT_CORS_ALLOW_HEADERS = "Content-Type, Authorization, X-Trace-Id, traceparent, tracestate";
@@ -0,0 +1,56 @@
1
+ import {
2
+ toJsonSchema
3
+ } from "./index-cby4ar3v.js";
4
+
5
+ // src/tools/schema.ts
6
+ import { z } from "zod";
7
+ function objectShapeKeys(schema) {
8
+ return schema instanceof z.ZodObject ? Object.keys(schema.shape) : [];
9
+ }
10
+ function keyPolicyOf(schema) {
11
+ return schema.def.catchall;
12
+ }
13
+ function rebuildObject(source, shape) {
14
+ return withKeyPolicy(z.object(shape), keyPolicyOf(source));
15
+ }
16
+ function withKeyPolicy(object, policy) {
17
+ if (policy === undefined)
18
+ return object;
19
+ return object.catchall(representable(policy));
20
+ }
21
+ function representable(policy) {
22
+ if (policy instanceof z.ZodNever || policy instanceof z.ZodUnknown)
23
+ return policy;
24
+ if (!(policy instanceof z.ZodType))
25
+ return z.unknown();
26
+ try {
27
+ toJsonSchema(policy, "input");
28
+ return policy;
29
+ } catch {
30
+ return z.unknown();
31
+ }
32
+ }
33
+ function mergeSchemas(paramsSchema, inputSchema) {
34
+ if (paramsSchema && !(paramsSchema instanceof z.ZodObject)) {
35
+ throw new Error("Tool params schema must be a z.object()");
36
+ }
37
+ const paramsObject = paramsSchema instanceof z.ZodObject ? paramsSchema : undefined;
38
+ if (!inputSchema) {
39
+ return paramsObject ?? z.object({});
40
+ }
41
+ if (inputSchema instanceof z.ZodObject) {
42
+ if (paramsObject) {
43
+ const conflicts = Object.keys(paramsObject.shape).filter((key) => (key in inputSchema.shape));
44
+ if (conflicts.length > 0) {
45
+ throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
46
+ }
47
+ }
48
+ return rebuildObject(inputSchema, {
49
+ ...paramsObject?.shape ?? {},
50
+ ...inputSchema.shape
51
+ });
52
+ }
53
+ return paramsObject ? z.intersection(paramsObject, inputSchema) : inputSchema;
54
+ }
55
+
56
+ export { objectShapeKeys, rebuildObject, mergeSchemas };
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  AppError,
3
3
  isUnsafeKey
4
- } from "./index-5r13htq1.js";
4
+ } from "./index-ps5pxp3h.js";
5
5
  import {
6
- isRecord,
7
6
  resolveTraceContext
8
- } from "./index-7eq9va6e.js";
7
+ } from "./index-y2rb7dwx.js";
8
+ import {
9
+ isRecord
10
+ } from "./index-smpbdg6k.js";
9
11
 
10
12
  // src/internal/errors.ts
11
13
  import { z } from "zod";
@@ -7,7 +7,7 @@ import {
7
7
  defaultSignalSource,
8
8
  guardSignalCallback,
9
9
  reportSignalError
10
- } from "./index-sm2tjx06.js";
10
+ } from "./index-41wm56v0.js";
11
11
  import {
12
12
  errorCode,
13
13
  extractIp,
@@ -23,19 +23,21 @@ import {
23
23
  setRequestError,
24
24
  validateDeclaredOutput,
25
25
  zodIssues
26
- } from "./index-j3dem06f.js";
26
+ } from "./index-7c0gkyvj.js";
27
27
  import {
28
28
  AppError,
29
29
  badRequest,
30
30
  isUnsafeKey,
31
31
  safeJsonParse
32
- } from "./index-5r13htq1.js";
32
+ } from "./index-ps5pxp3h.js";
33
33
  import {
34
- isRecord,
35
34
  parseTrailingWildcard,
36
- resolveTraceContext,
35
+ resolveTraceContext
36
+ } from "./index-y2rb7dwx.js";
37
+ import {
38
+ isRecord,
37
39
  transportResult
38
- } from "./index-7eq9va6e.js";
40
+ } from "./index-smpbdg6k.js";
39
41
  import {
40
42
  __require
41
43
  } from "./index-1bx83sw4.js";
@@ -466,12 +468,20 @@ async function parseMultipart(req, descriptor, fieldsSchema, receivers) {
466
468
  }
467
469
 
468
470
  // src/server/request-body.ts
471
+ function requestAbortReason(req) {
472
+ return req.signal.reason ?? new DOMException("The connection was closed", "AbortError");
473
+ }
474
+ function throwIfRequestAborted(req) {
475
+ if (req.signal.aborted)
476
+ throw requestAbortReason(req);
477
+ }
469
478
  function assertJsonBodyLimit(maxBytes, owner) {
470
479
  if (maxBytes !== undefined && (!Number.isSafeInteger(maxBytes) || maxBytes <= 0)) {
471
480
  throw new Error(`${owner} must be a positive safe integer, received ${maxBytes}`);
472
481
  }
473
482
  }
474
483
  async function readRequestText(req, maxBytes) {
484
+ throwIfRequestAborted(req);
475
485
  if (maxBytes === undefined)
476
486
  return req.text();
477
487
  assertJsonBodyLimit(maxBytes, "maxJsonBodyBytes");
@@ -480,9 +490,25 @@ async function readRequestText(req, maxBytes) {
480
490
  return "";
481
491
  const chunks = [];
482
492
  let total = 0;
493
+ let rejectAbortedRead = (_reason) => {
494
+ return;
495
+ };
496
+ const abortedRead = new Promise((_resolve, reject) => {
497
+ rejectAbortedRead = reject;
498
+ });
499
+ const onAbort = () => {
500
+ const reason = requestAbortReason(req);
501
+ rejectAbortedRead(reason);
502
+ reader.cancel(reason).catch(() => {
503
+ return;
504
+ });
505
+ };
506
+ req.signal.addEventListener("abort", onAbort, { once: true });
507
+ if (req.signal.aborted)
508
+ onAbort();
483
509
  try {
484
510
  while (true) {
485
- const { done, value } = await reader.read();
511
+ const { done, value } = await Promise.race([reader.read(), abortedRead]);
486
512
  if (done)
487
513
  break;
488
514
  total += value.byteLength;
@@ -493,7 +519,9 @@ async function readRequestText(req, maxBytes) {
493
519
  chunks.push(value);
494
520
  }
495
521
  } finally {
496
- reader.releaseLock();
522
+ req.signal.removeEventListener("abort", onAbort);
523
+ if (!req.signal.aborted)
524
+ reader.releaseLock();
497
525
  }
498
526
  const bytes = new Uint8Array(total);
499
527
  let offset = 0;
@@ -630,6 +658,8 @@ function safePath(pathname) {
630
658
  return out;
631
659
  }
632
660
  function levelForStatus(status) {
661
+ if (status === 499)
662
+ return "info";
633
663
  if (status >= 500)
634
664
  return "error";
635
665
  if (status >= 400)
@@ -1037,6 +1067,29 @@ function validateRawRoutes(rawRoutes) {
1037
1067
 
1038
1068
  // src/server/create.ts
1039
1069
  var BODY_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
1070
+ var MAX_REQUEST_ABORT_CAUSE_DEPTH = 8;
1071
+ function containsRequestAbortReason(error, reason) {
1072
+ let current = error;
1073
+ const visited = new Set;
1074
+ for (let depth = 0;depth <= MAX_REQUEST_ABORT_CAUSE_DEPTH; depth += 1) {
1075
+ if (current === reason)
1076
+ return true;
1077
+ if (depth === MAX_REQUEST_ABORT_CAUSE_DEPTH || !isRecord(current))
1078
+ return false;
1079
+ if (visited.has(current))
1080
+ return false;
1081
+ visited.add(current);
1082
+ current = current.cause;
1083
+ }
1084
+ return false;
1085
+ }
1086
+ function isClientClosedRequest(req, error) {
1087
+ if (!req.signal.aborted)
1088
+ return false;
1089
+ if (isRecord(error) && error.name === "AbortError")
1090
+ return true;
1091
+ return req.signal.reason !== undefined && containsRequestAbortReason(error, req.signal.reason);
1092
+ }
1040
1093
  function createHandler(config) {
1041
1094
  const { cors, hooks, logging = false, observability, trustProxy = false } = config;
1042
1095
  if (cors)
@@ -1100,7 +1153,7 @@ function createHandler(config) {
1100
1153
  } catch {}
1101
1154
  }
1102
1155
  let completed = false;
1103
- const complete = (status, errorCode2) => {
1156
+ const complete = (status, errorCode2, outcome) => {
1104
1157
  if (completed)
1105
1158
  return;
1106
1159
  completed = true;
@@ -1148,11 +1201,22 @@ function createHandler(config) {
1148
1201
  const context = getRequestContext();
1149
1202
  if (observability && context) {
1150
1203
  try {
1151
- observability.complete({ context, statusCode: status, durationMs, payload });
1204
+ observability.complete({
1205
+ context,
1206
+ statusCode: status,
1207
+ durationMs,
1208
+ payload,
1209
+ ...outcome !== undefined && { outcome }
1210
+ });
1152
1211
  } catch {}
1153
1212
  }
1154
1213
  };
1155
1214
  const respondError = async (err, errCtx, endpoint) => {
1215
+ if (isClientClosedRequest(req, err)) {
1216
+ const response = applyCors(new Response(null, { status: 499, statusText: "Client Closed Request" }), cors, req);
1217
+ complete(response.status, undefined, "cancelled");
1218
+ return response;
1219
+ }
1156
1220
  const recordFailure = (normalized) => {
1157
1221
  if (getRequestContext()?.error !== undefined)
1158
1222
  return;
@@ -2,7 +2,7 @@ import {
2
2
  contextContributionDelta,
3
3
  mergeContextContribution,
4
4
  prepareContextContribution
5
- } from "./index-sm2tjx06.js";
5
+ } from "./index-41wm56v0.js";
6
6
  import {
7
7
  base64UrlToBytes,
8
8
  bytesToBase64Url,
@@ -10,10 +10,10 @@ import {
10
10
  isUnsafeKey,
11
11
  safeJsonParse,
12
12
  unauthorized
13
- } from "./index-5r13htq1.js";
13
+ } from "./index-ps5pxp3h.js";
14
14
  import {
15
15
  isRecord
16
- } from "./index-7eq9va6e.js";
16
+ } from "./index-smpbdg6k.js";
17
17
 
18
18
  // src/server/middleware/cookies.ts
19
19
  function parseCookies(header) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  isUnsafeKey
3
- } from "./index-5r13htq1.js";
3
+ } from "./index-ps5pxp3h.js";
4
4
  import {
5
5
  isRecord
6
- } from "./index-7eq9va6e.js";
6
+ } from "./index-smpbdg6k.js";
7
7
 
8
8
  // src/observability/sanitize.ts
9
9
  var SENSITIVE_WORDS = new Set([
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  inputIsQuery
3
3
  } from "./index-48ffdxgk.js";
4
+ import {
5
+ parseTrailingWildcard
6
+ } from "./index-y2rb7dwx.js";
4
7
  import {
5
8
  isRecord,
6
9
  mapObject,
7
- parseTrailingWildcard,
8
10
  typedEntries
9
- } from "./index-7eq9va6e.js";
11
+ } from "./index-smpbdg6k.js";
10
12
 
11
13
  // src/browser/cancellation.ts
12
14
  class RequestCancellationError extends Error {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseTrailingWildcard
3
- } from "./index-7eq9va6e.js";
3
+ } from "./index-y2rb7dwx.js";
4
4
 
5
5
  // src/contract/errors.ts
6
6
  var APP_ERROR_BRAND = Symbol.for("stitchkit.AppError");