stitchkit 0.110.5 → 0.111.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/agent-runtime/branch-observations.d.ts +16 -16
  3. package/dist/agent-runtime/sandbox-broker.d.ts.map +1 -1
  4. package/dist/browser/stream.d.ts +3 -2
  5. package/dist/browser/stream.d.ts.map +1 -1
  6. package/dist/contract/runtime-context.d.ts +3 -1
  7. package/dist/contract/runtime-context.d.ts.map +1 -1
  8. package/dist/entrypoints/agent-runtime/coding-tools.js +2 -2
  9. package/dist/entrypoints/agent-runtime/sandbox.js +15 -29
  10. package/dist/entrypoints/agent-runtime/sqlite/bun.js +4 -4
  11. package/dist/entrypoints/agent-runtime/sqlite/node.js +4 -4
  12. package/dist/entrypoints/agent-runtime/testing.js +4 -4
  13. package/dist/entrypoints/agent-runtime.js +4 -4
  14. package/dist/entrypoints/bin/upgrade-cli.d.ts.map +1 -1
  15. package/dist/entrypoints/bin/upgrade-cli.js +123 -29
  16. package/dist/entrypoints/cli/publish.js +1 -1
  17. package/dist/entrypoints/cli.js +2 -2
  18. package/dist/entrypoints/http.d.ts +2 -0
  19. package/dist/entrypoints/http.d.ts.map +1 -1
  20. package/dist/entrypoints/http.js +5 -1
  21. package/dist/entrypoints/index.d.ts +1 -0
  22. package/dist/entrypoints/index.d.ts.map +1 -1
  23. package/dist/entrypoints/index.js +5 -1
  24. package/dist/entrypoints/node.d.ts +1 -0
  25. package/dist/entrypoints/node.d.ts.map +1 -1
  26. package/dist/entrypoints/node.js +3 -1
  27. package/dist/entrypoints/observability.js +24 -9
  28. package/dist/entrypoints/process.js +1 -1
  29. package/dist/entrypoints/remote.js +1 -1
  30. package/dist/entrypoints/server.d.ts +2 -0
  31. package/dist/entrypoints/server.d.ts.map +1 -1
  32. package/dist/entrypoints/server.js +79 -6
  33. package/dist/entrypoints/telegram.js +3 -3
  34. package/dist/entrypoints/testing.js +1 -1
  35. package/dist/entrypoints/tools/connections.js +16 -31
  36. package/dist/entrypoints/tools.js +39 -7
  37. package/dist/{index-mpg1t7nv.js → index-0z3kfphz.js} +1 -1
  38. package/dist/{index-jk44mbqb.js → index-1y0arq4z.js} +3 -57
  39. package/dist/{index-5pbtbce0.js → index-7c957abz.js} +1 -1
  40. package/dist/{index-e1sjcjfy.js → index-7r4knwf8.js} +94 -23
  41. package/dist/index-cjbn98zt.js +68 -0
  42. package/dist/{index-bm180f2d.js → index-ey15wx6j.js} +1 -1
  43. package/dist/{index-s0xbnpfh.js → index-kdnfe0sr.js} +1 -1
  44. package/dist/{index-s6d8zsha.js → index-krng2a5j.js} +64 -110
  45. package/dist/{index-9ket8wzx.js → index-mnk5vgdr.js} +1 -1
  46. package/dist/index-qndsr7f0.js +55 -0
  47. package/dist/{index-n7hrpngg.js → index-syzngt7v.js} +1 -1
  48. package/dist/{index-3h0ztg0z.js → index-t65erk4z.js} +5 -21
  49. package/dist/internal/bounded-body.d.ts +44 -0
  50. package/dist/internal/bounded-body.d.ts.map +1 -0
  51. package/dist/internal/bounded-lines.d.ts +1 -2
  52. package/dist/internal/bounded-lines.d.ts.map +1 -1
  53. package/dist/internal/secure-fetch.d.ts.map +1 -1
  54. package/dist/internal/stream-chunks.d.ts +13 -0
  55. package/dist/internal/stream-chunks.d.ts.map +1 -0
  56. package/dist/internal/upgrade-affects.d.ts +5 -0
  57. package/dist/internal/upgrade-affects.d.ts.map +1 -1
  58. package/dist/internal/upgrade-plan.d.ts +18 -3
  59. package/dist/internal/upgrade-plan.d.ts.map +1 -1
  60. package/dist/internal/upgrade-usage.d.ts +21 -5
  61. package/dist/internal/upgrade-usage.d.ts.map +1 -1
  62. package/dist/observability/audit.d.ts +10 -0
  63. package/dist/observability/audit.d.ts.map +1 -1
  64. package/dist/observability/event.d.ts +5 -0
  65. package/dist/observability/event.d.ts.map +1 -1
  66. package/dist/process/group-diagnostics.d.ts +20 -0
  67. package/dist/process/group-diagnostics.d.ts.map +1 -0
  68. package/dist/process/group-settlement.d.ts +1 -1
  69. package/dist/process/group-settlement.d.ts.map +1 -1
  70. package/dist/process/group.d.ts.map +1 -1
  71. package/dist/server/bun.d.ts +9 -0
  72. package/dist/server/bun.d.ts.map +1 -1
  73. package/dist/server/multipart.d.ts.map +1 -1
  74. package/dist/server/oauth/endpoints.d.ts.map +1 -1
  75. package/dist/server/oauth/provider.d.ts +5 -0
  76. package/dist/server/oauth/provider.d.ts.map +1 -1
  77. package/dist/server/proxy-origin.d.ts +12 -0
  78. package/dist/server/proxy-origin.d.ts.map +1 -0
  79. package/dist/server/raw.d.ts +6 -3
  80. package/dist/server/raw.d.ts.map +1 -1
  81. package/dist/server/request-body.d.ts.map +1 -1
  82. package/dist/server/request-completion.d.ts.map +1 -1
  83. package/dist/server/request-ingress.d.ts +31 -0
  84. package/dist/server/request-ingress.d.ts.map +1 -0
  85. package/dist/server/unix-client-body.d.ts.map +1 -1
  86. package/dist/tools/connections/limits.d.ts.map +1 -1
  87. package/llms/http.txt +3 -0
  88. package/llms/observability.txt +19 -2
  89. package/llms/server.2.txt +135 -0
  90. package/llms/server.5.txt +3 -1
  91. package/llms/server.txt +97 -131
  92. package/llms/stitchkit.2.txt +28 -0
  93. package/llms/stitchkit.txt +3 -3
  94. package/llms/tools.3.txt +1 -1
  95. package/llms/tools.txt +4 -0
  96. package/llms/{upgrading-0.101.0-0.110.0.txt → upgrading-0.101.0-0.111.0.txt} +29 -3
  97. package/llms/upgrading.txt +8 -2
  98. package/llms-full.txt +192 -8
  99. package/llms.txt +6 -6
  100. package/package.json +1 -1
@@ -14,10 +14,6 @@ import {
14
14
  withUploadProgress,
15
15
  parseApiErrorBody
16
16
  } from "./index-p6apg0jg.js";
17
- import {
18
- abortReason,
19
- untilAborted
20
- } from "./index-a5qr2rj6.js";
21
17
  import {
22
18
  inputIsQuery
23
19
  } from "./index-xhzq2qvj.js";
@@ -25,6 +21,9 @@ import {
25
21
  ApiError2,
26
22
  refuseLocally
27
23
  } from "./index-kfjkb396.js";
24
+ import {
25
+ chunksOf
26
+ } from "./index-cjbn98zt.js";
28
27
  import {
29
28
  assertPositiveSafeInteger
30
29
  } from "./index-0s4xebbg.js";
@@ -131,59 +130,6 @@ function createBoundedLineDecoder(maxLineBytes, requireFinalNewline = false) {
131
130
  const { push, end } = createLineSplitter(maxLineBytes, requireFinalNewline);
132
131
  return { push, end };
133
132
  }
134
- async function* chunksOf(source, signal) {
135
- signal?.throwIfAborted();
136
- const stream = source instanceof Response ? source.body : source;
137
- if (stream === null)
138
- return;
139
- if (stream instanceof ReadableStream) {
140
- const reader = stream.getReader();
141
- const abort = () => {
142
- if (signal)
143
- reader.cancel(abortReason(signal)).catch(() => {
144
- return;
145
- });
146
- };
147
- signal?.addEventListener("abort", abort, { once: true });
148
- try {
149
- for (;; ) {
150
- const chunk = await reader.read();
151
- signal?.throwIfAborted();
152
- if (chunk.done)
153
- return;
154
- yield chunk.value;
155
- }
156
- } finally {
157
- signal?.removeEventListener("abort", abort);
158
- await reader.cancel().catch(() => {
159
- return;
160
- });
161
- reader.releaseLock();
162
- }
163
- }
164
- const iterator = stream[Symbol.asyncIterator]();
165
- let finished = false;
166
- try {
167
- for (;; ) {
168
- const pending = iterator.next();
169
- const next = await (signal ? untilAborted(pending, signal) : pending);
170
- if (next.done) {
171
- finished = true;
172
- return;
173
- }
174
- yield next.value;
175
- }
176
- } finally {
177
- if (!finished && signal?.aborted)
178
- iterator.return?.().catch(() => {
179
- return;
180
- });
181
- else if (!finished)
182
- await iterator.return?.().catch(() => {
183
- return;
184
- });
185
- }
186
- }
187
133
  async function* readBoundedUtf8Lines(source, maxLineBytes, requireFinalNewline = false, signal) {
188
134
  const splitter = createLineSplitter(maxLineBytes, requireFinalNewline);
189
135
  for await (const chunk of chunksOf(source, signal)) {
@@ -19,7 +19,7 @@ import {
19
19
  appendEventIn,
20
20
  ArchiveProjectionSchema,
21
21
  createAgentRuntimeStore2
22
- } from "./index-mpg1t7nv.js";
22
+ } from "./index-0z3kfphz.js";
23
23
  import {
24
24
  AgentConversationPageSchema2,
25
25
  AgentConversationMessagePageSchema2
@@ -23,6 +23,62 @@ import {
23
23
  assertPositiveSafeInteger
24
24
  } from "./index-0s4xebbg.js";
25
25
 
26
+ // src/process/group-diagnostics.ts
27
+ import { z } from "zod";
28
+ var ObservationSchema = z.object({
29
+ failure: z.enum(["deadline", "observation"]),
30
+ groupId: z.number().int().positive(),
31
+ observations: z.number().int().nonnegative(),
32
+ lastStates: z.array(z.string().max(32)).max(16),
33
+ elapsedMs: z.number().int().nonnegative()
34
+ });
35
+ var observations = new WeakMap;
36
+
37
+ class GroupSettlementError extends Error {
38
+ constructor(message, observation, cause = observation) {
39
+ super(`${message}: ${JSON.stringify(observation)}`, { cause });
40
+ observations.set(this, { ...observation, lastStates: [...observation.lastStates] });
41
+ }
42
+ }
43
+ function ownData(value, key) {
44
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
45
+ return descriptor && "value" in descriptor ? descriptor.value : undefined;
46
+ }
47
+ function groupSettlementDiagnostics(cause) {
48
+ const pending = [{ value: cause, depth: 0 }];
49
+ const seen = new Set;
50
+ const found = [];
51
+ for (let visited = 0;pending.length && visited < 32 && found.length < 4; visited++) {
52
+ const entry = pending.pop();
53
+ if (!entry || seen.has(entry.value))
54
+ continue;
55
+ seen.add(entry.value);
56
+ try {
57
+ if (entry.value instanceof Error) {
58
+ const observation = observations.get(entry.value);
59
+ if (observation)
60
+ found.push(observation);
61
+ }
62
+ if (!(entry.value instanceof Error) || entry.depth >= 8)
63
+ continue;
64
+ if (entry.value instanceof AggregateError) {
65
+ const errors = ownData(entry.value, "errors");
66
+ if (Array.isArray(errors)) {
67
+ for (let index = 0;index < 16; index++) {
68
+ const value = ownData(errors, String(index));
69
+ if (value !== undefined)
70
+ pending.push({ value, depth: entry.depth + 1 });
71
+ }
72
+ }
73
+ }
74
+ const nested = ownData(entry.value, "cause");
75
+ if (nested !== undefined)
76
+ pending.push({ value: nested, depth: entry.depth + 1 });
77
+ } catch {}
78
+ }
79
+ return found;
80
+ }
81
+
26
82
  // src/process/group-presence.ts
27
83
  function processGroupExists(pid) {
28
84
  try {
@@ -57,36 +113,49 @@ function processGroups(timeoutMs) {
57
113
  return new Promise((resolve, reject) => {
58
114
  execFile("ps", ["-axo", "pgid=,stat="], { encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 1024 * 1024 }, (error, stdout) => {
59
115
  if (error)
60
- reject(new Error("Could not observe command process group settlement", { cause: error }));
116
+ reject(error);
61
117
  else
62
118
  resolve(stdout);
63
119
  });
64
120
  });
65
121
  }
66
- async function waitForProcessGroupExit(pid, deadline) {
122
+ async function waitForProcessGroupExit(pid, deadline, killLiveMembers) {
67
123
  if (pid === undefined)
68
124
  return;
69
125
  let observations = 0;
70
126
  let lastStates = [];
71
- for (;; ) {
72
- const remaining = Math.ceil(deadline - performance.now());
73
- if (remaining <= 0)
74
- throw new Error("Command process group settlement was not confirmed after SIGKILL", {
75
- cause: { groupId: pid, observations, lastStates }
76
- });
77
- if (!processGroupExists(pid))
78
- return;
79
- const table = await processGroups(remaining);
80
- observations++;
81
- if (!hasLiveGroupMember(table, pid))
82
- return;
83
- lastStates = table.split(/\r?\n/).flatMap((row) => {
84
- const fields = /^\s*(\d+)\s+(\S+)\s*$/.exec(row);
85
- return Number(fields?.[1]) === pid ? [fields?.[2] ?? "unknown"] : [];
86
- }).slice(0, 16);
87
- if (!processGroupExists(pid))
88
- return;
89
- await sleep(Math.min(5, Math.max(0, deadline - performance.now())));
127
+ const startedAt = performance.now();
128
+ const observation = () => ({
129
+ groupId: pid,
130
+ observations,
131
+ lastStates,
132
+ elapsedMs: Math.max(0, Math.ceil(performance.now() - startedAt))
133
+ });
134
+ try {
135
+ for (;; ) {
136
+ const remaining = Math.ceil(deadline - performance.now());
137
+ if (remaining <= 0)
138
+ throw new GroupSettlementError("Command process group settlement was not confirmed after SIGKILL", { ...observation(), failure: "deadline" });
139
+ if (!processGroupExists(pid))
140
+ return;
141
+ const table = await processGroups(remaining);
142
+ observations++;
143
+ if (!hasLiveGroupMember(table, pid))
144
+ return;
145
+ lastStates = table.split(/\r?\n/).flatMap((row) => {
146
+ const fields = /^\s*(\d+)\s+(\S+)\s*$/.exec(row);
147
+ return Number(fields?.[1]) === pid ? [(fields?.[2] ?? "unknown").slice(0, 32)] : [];
148
+ }).slice(0, 16);
149
+ if (!processGroupExists(pid))
150
+ return;
151
+ if (killLiveMembers && performance.now() < deadline && !await killLiveMembers())
152
+ return;
153
+ await sleep(Math.min(5, Math.max(0, deadline - performance.now())));
154
+ }
155
+ } catch (cause) {
156
+ if (cause instanceof GroupSettlementError)
157
+ throw cause;
158
+ throw new GroupSettlementError("Could not observe command process group settlement", { ...observation(), failure: "observation" }, cause);
90
159
  }
91
160
  }
92
161
 
@@ -151,7 +220,7 @@ async function killAndSettleGroup(pid, deadline, cleanupTimeoutMs) {
151
220
  const cleanupDeadline = Math.min(deadline, performance.now() + cleanupTimeoutMs);
152
221
  const signalled = await signalUntilSettled(pid, "SIGKILL", cleanupDeadline);
153
222
  if (signalled)
154
- await waitForProcessGroupExit(pid, cleanupDeadline);
223
+ await waitForProcessGroupExit(pid, cleanupDeadline, () => signalUntilSettled(pid, "SIGKILL", cleanupDeadline));
155
224
  return signalled;
156
225
  }
157
226
  async function stopCommandGroup(stop) {
@@ -235,7 +304,9 @@ async function stopLeaderAlone(stop) {
235
304
  return send("SIGKILL") || signalled;
236
305
  }
237
306
  function commandCleanupError(cause) {
238
- return new NativeCommandError2("COMMAND_CLEANUP", "Command cleanup did not complete", {
307
+ const observations = groupSettlementDiagnostics(cause);
308
+ const message = observations.length ? `Command cleanup did not complete: ${JSON.stringify(observations)}` : "Command cleanup did not complete";
309
+ return new NativeCommandError2("COMMAND_CLEANUP", message, {
239
310
  cause
240
311
  });
241
312
  }
@@ -0,0 +1,68 @@
1
+ import {
2
+ abortReason,
3
+ untilAborted
4
+ } from "./index-a5qr2rj6.js";
5
+
6
+ // src/internal/stream-chunks.ts
7
+ async function* chunksOf(source, signal) {
8
+ signal?.throwIfAborted();
9
+ const stream = source instanceof Response ? source.body : source;
10
+ if (stream === null)
11
+ return;
12
+ if (stream instanceof ReadableStream) {
13
+ const reader = stream.getReader();
14
+ const abort = () => {
15
+ if (signal)
16
+ reader.cancel(abortReason(signal)).catch(() => {
17
+ return;
18
+ });
19
+ };
20
+ signal?.addEventListener("abort", abort, { once: true });
21
+ try {
22
+ for (;; ) {
23
+ const pending = reader.read();
24
+ const chunk = await (signal ? untilAborted(pending, signal) : pending);
25
+ signal?.throwIfAborted();
26
+ if (chunk.done)
27
+ return;
28
+ yield chunk.value;
29
+ }
30
+ } finally {
31
+ signal?.removeEventListener("abort", abort);
32
+ if (signal?.aborted) {
33
+ reader.cancel(abortReason(signal)).catch(() => {
34
+ return;
35
+ });
36
+ } else {
37
+ await reader.cancel().catch(() => {
38
+ return;
39
+ });
40
+ reader.releaseLock();
41
+ }
42
+ }
43
+ }
44
+ const iterator = stream[Symbol.asyncIterator]();
45
+ let finished = false;
46
+ try {
47
+ for (;; ) {
48
+ const pending = iterator.next();
49
+ const next = await (signal ? untilAborted(pending, signal) : pending);
50
+ if (next.done) {
51
+ finished = true;
52
+ return;
53
+ }
54
+ yield next.value;
55
+ }
56
+ } finally {
57
+ if (!finished && signal?.aborted)
58
+ iterator.return?.().catch(() => {
59
+ return;
60
+ });
61
+ else if (!finished)
62
+ await iterator.return?.().catch(() => {
63
+ return;
64
+ });
65
+ }
66
+ }
67
+
68
+ export { chunksOf };
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  CommandStopped,
9
9
  startNativeCommand
10
- } from "./index-e1sjcjfy.js";
10
+ } from "./index-7r4knwf8.js";
11
11
  import {
12
12
  NumericFileHandle,
13
13
  descriptorPath,
@@ -5,7 +5,7 @@ import {
5
5
  fetchGuarded,
6
6
  PrivateAddressRefusal,
7
7
  readCapped
8
- } from "./index-3h0ztg0z.js";
8
+ } from "./index-t65erk4z.js";
9
9
  import {
10
10
  writeFileAtomicSync2
11
11
  } from "./index-07dcf2yn.js";
@@ -27,6 +27,14 @@ import {
27
27
  bindContract,
28
28
  mediaTypeEssence
29
29
  } from "./index-pzw0fpek.js";
30
+ import {
31
+ readBoundedChunks,
32
+ concatChunks,
33
+ readBoundedBody2
34
+ } from "./index-qndsr7f0.js";
35
+ import {
36
+ abortReason
37
+ } from "./index-a5qr2rj6.js";
30
38
  import {
31
39
  assertPositiveSafeInteger
32
40
  } from "./index-0s4xebbg.js";
@@ -418,27 +426,10 @@ async function collectFile(part, stream) {
418
426
  });
419
427
  }
420
428
  async function readText(stream, maxBytes) {
421
- const chunks = [];
422
- const reader = stream.getReader();
423
- let total = 0;
424
- while (true) {
425
- const result = await reader.read();
426
- if (result.done)
427
- break;
428
- total += result.value.length;
429
- if (total > maxBytes) {
430
- await reader.cancel();
431
- badRequest2(`Multipart text field exceeds ${maxBytes} bytes`);
432
- }
433
- chunks.push(result.value);
434
- }
435
- const value = new Uint8Array(total);
436
- let offset = 0;
437
- for (const chunk of chunks) {
438
- value.set(chunk, offset);
439
- offset += chunk.length;
440
- }
441
- return decoder.decode(value);
429
+ const result = await readBoundedChunks(stream, { maxBytes });
430
+ if (result.kind === "over-limit")
431
+ badRequest2(`Multipart text field exceeds ${maxBytes} bytes`);
432
+ return decoder.decode(concatChunks(result.chunks, result.total));
442
433
  }
443
434
  function required(policy) {
444
435
  return policy.required !== false;
@@ -896,63 +887,16 @@ function mergeContextContribution(ctx, value, scope) {
896
887
  }
897
888
 
898
889
  // src/server/request-body.ts
899
- function requestAbortReason(req) {
900
- return req.signal.reason ?? new DOMException("The connection was closed", "AbortError");
901
- }
902
- function throwIfRequestAborted(req) {
903
- if (req.signal.aborted)
904
- throw requestAbortReason(req);
905
- }
906
890
  async function readRequestText(req, maxBytes) {
907
- throwIfRequestAborted(req);
891
+ if (req.signal.aborted)
892
+ throw abortReason(req.signal);
908
893
  if (maxBytes === undefined)
909
894
  return req.text();
910
895
  assertPositiveSafeInteger("maxJsonBodyBytes", maxBytes, Error);
911
- const reader = req.body?.getReader();
912
- if (!reader)
913
- return "";
914
- const chunks = [];
915
- let total = 0;
916
- let rejectAbortedRead = (_reason) => {
917
- return;
918
- };
919
- const abortedRead = new Promise((_resolve, reject) => {
920
- rejectAbortedRead = reject;
921
- });
922
- const onAbort = () => {
923
- const reason = requestAbortReason(req);
924
- rejectAbortedRead(reason);
925
- reader.cancel(reason).catch(() => {
926
- return;
927
- });
928
- };
929
- req.signal.addEventListener("abort", onAbort, { once: true });
930
- if (req.signal.aborted)
931
- onAbort();
932
- try {
933
- while (true) {
934
- const { done, value } = await Promise.race([reader.read(), abortedRead]);
935
- if (done)
936
- break;
937
- total += value.byteLength;
938
- if (total > maxBytes) {
939
- await reader.cancel();
940
- badRequest2(`JSON body exceeds the ${maxBytes}-byte limit`);
941
- }
942
- chunks.push(value);
943
- }
944
- } finally {
945
- req.signal.removeEventListener("abort", onAbort);
946
- if (!req.signal.aborted)
947
- reader.releaseLock();
948
- }
949
- const bytes = new Uint8Array(total);
950
- let offset = 0;
951
- for (const chunk of chunks) {
952
- bytes.set(chunk, offset);
953
- offset += chunk.byteLength;
954
- }
955
- return new TextDecoder().decode(bytes);
896
+ const result = await readBoundedChunks(req.body, { maxBytes, signal: req.signal });
897
+ if (result.kind === "over-limit")
898
+ badRequest2(`JSON body exceeds the ${maxBytes}-byte limit`);
899
+ return new TextDecoder().decode(concatChunks(result.chunks, result.total));
956
900
  }
957
901
 
958
902
  // src/server/context.ts
@@ -1979,13 +1923,25 @@ function logOutgoing(entry) {
1979
1923
 
1980
1924
  // src/server/request-completion.ts
1981
1925
  var BODY_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
1926
+ var DEFAULT_PAYLOAD_LOG_BYTES = 1024 * 1024;
1927
+ async function readPayload(clone, maxBytes) {
1928
+ try {
1929
+ const result = await readBoundedChunks(clone.body, { maxBytes, signal: clone.signal });
1930
+ if (result.kind === "over-limit")
1931
+ return { value: undefined, truncated: true };
1932
+ return {
1933
+ value: JSON.parse(new TextDecoder().decode(concatChunks(result.chunks, result.total))),
1934
+ truncated: false
1935
+ };
1936
+ } catch {
1937
+ return { value: undefined, truncated: false };
1938
+ }
1939
+ }
1982
1940
  function openRequestCompletion(state, window) {
1983
1941
  const { logConfig, customLogger, useDefaultLog, observability } = state;
1984
1942
  const { req, url, traceId, startedAt, ipAddress } = window;
1985
1943
  const shouldLogRequest = logConfig !== null && shouldLog(url.pathname, req.method) && !shouldSkipLog(logConfig, req, url);
1986
- const payload = observability?.includePayload && BODY_METHODS.has(req.method) ? req.clone().json().catch(() => {
1987
- return;
1988
- }) : undefined;
1944
+ const payloadRead = observability?.includePayload && BODY_METHODS.has(req.method) ? readPayload(req.clone(), observability.payloadMaxBytes ?? state.config.maxJsonBodyBytes ?? DEFAULT_PAYLOAD_LOG_BYTES) : undefined;
1989
1945
  const logFormat = resolveLogFormat(logConfig?.format);
1990
1946
  let reqLog;
1991
1947
  if (shouldLogRequest && useDefaultLog) {
@@ -2026,7 +1982,10 @@ function openRequestCompletion(state, window) {
2026
1982
  context,
2027
1983
  statusCode: status,
2028
1984
  durationMs,
2029
- payload,
1985
+ ...payloadRead && {
1986
+ payload: payloadRead.then((read) => read.value),
1987
+ payloadTruncated: payloadRead.then((read) => read.truncated)
1988
+ },
2030
1989
  ...outcome !== undefined && { outcome }
2031
1990
  });
2032
1991
  } catch {}
@@ -2367,6 +2326,23 @@ function bindProcessSignals2(handle, options = {}) {
2367
2326
  return { promise, close };
2368
2327
  }
2369
2328
 
2329
+ // src/server/request-ingress.ts
2330
+ function defineRequestIngress2(name) {
2331
+ const values = new WeakMap;
2332
+ return {
2333
+ name,
2334
+ attach(request, value) {
2335
+ if (values.has(request)) {
2336
+ throw new TypeError(`[stitchkit] request ingress ${JSON.stringify(name)} is already attached to this request`);
2337
+ }
2338
+ values.set(request, value);
2339
+ },
2340
+ from(source) {
2341
+ return source.req && values.get(source.req);
2342
+ }
2343
+ };
2344
+ }
2345
+
2370
2346
  // src/server/websocket.ts
2371
2347
  function webSocketLane2(lane) {
2372
2348
  const { match, handlers } = lane;
@@ -2630,39 +2606,17 @@ import {
2630
2606
 
2631
2607
  // src/server/unix-client-body.ts
2632
2608
  async function readBoundedRequestBody(request, maxBytes) {
2633
- const body = request.body;
2634
- if (!body)
2609
+ if (!request.body)
2635
2610
  return;
2611
+ const tooLarge = () => new UnixClientTransportError2("UNIX_REQUEST_TOO_LARGE", `Unix request body exceeds the ${maxBytes} byte limit`, "not-dispatched");
2636
2612
  const declared = request.headers.get("content-length");
2637
- if (declared !== null && Number(declared) > maxBytes) {
2638
- throw new UnixClientTransportError2("UNIX_REQUEST_TOO_LARGE", `Unix request body exceeds the ${maxBytes} byte limit`, "not-dispatched");
2639
- }
2640
- const reader = body.getReader();
2641
- const chunks = [];
2642
- let total = 0;
2643
- try {
2644
- for (;; ) {
2645
- if (request.signal.aborted)
2646
- throw request.signal.reason;
2647
- const chunk = await reader.read();
2648
- if (chunk.done)
2649
- break;
2650
- total += chunk.value.byteLength;
2651
- if (total > maxBytes) {
2652
- throw new UnixClientTransportError2("UNIX_REQUEST_TOO_LARGE", `Unix request body exceeds the ${maxBytes} byte limit`, "not-dispatched");
2653
- }
2654
- chunks.push(chunk.value);
2655
- }
2656
- } finally {
2657
- reader.releaseLock();
2658
- }
2659
- const result = new Uint8Array(total);
2660
- let offset = 0;
2661
- for (const chunk of chunks) {
2662
- result.set(chunk, offset);
2663
- offset += chunk.byteLength;
2664
- }
2665
- return result;
2613
+ if (declared !== null && Number(declared) > maxBytes)
2614
+ throw tooLarge();
2615
+ return readBoundedBody2(request.body, {
2616
+ maxBytes,
2617
+ signal: request.signal,
2618
+ limitError: tooLarge
2619
+ });
2666
2620
  }
2667
2621
  function incomingResponseBody(response, maxBytes, onDone) {
2668
2622
  let finished = false;
@@ -3474,4 +3428,4 @@ function createUnixClientTransport2(config) {
3474
3428
  };
3475
3429
  }
3476
3430
 
3477
- export { contextContributionDelta, prepareContextContribution, mergeContextContribution, parseMultipart2, DEFAULT_STREAM_HEARTBEAT_MS2, streamingRoute2, ndjsonRoute2, sseRoute2, createHandler2, createScopedImplementRegistry2, implementRegistry2, createImplementRegistry2, bindProcessSignals2, webSocketLane2, composeWebSocketHandlers2, createSocketIOServer2, socketIoLane2, UnixClientTransportError2, createUnixClientTransport2 };
3431
+ export { contextContributionDelta, prepareContextContribution, mergeContextContribution, parseMultipart2, DEFAULT_STREAM_HEARTBEAT_MS2, streamingRoute2, ndjsonRoute2, sseRoute2, createHandler2, createScopedImplementRegistry2, implementRegistry2, createImplementRegistry2, bindProcessSignals2, defineRequestIngress2, webSocketLane2, composeWebSocketHandlers2, createSocketIOServer2, socketIoLane2, UnixClientTransportError2, createUnixClientTransport2 };
@@ -17,7 +17,7 @@ import {
17
17
  replaceMessage,
18
18
  ArchiveSpillSchema,
19
19
  createAgentRuntimeStore2
20
- } from "./index-mpg1t7nv.js";
20
+ } from "./index-0z3kfphz.js";
21
21
 
22
22
  // src/agent-runtime/store-memory.ts
23
23
  import { z as z2 } from "zod";
@@ -0,0 +1,55 @@
1
+ import {
2
+ chunksOf
3
+ } from "./index-cjbn98zt.js";
4
+ import {
5
+ abortReason
6
+ } from "./index-a5qr2rj6.js";
7
+ import {
8
+ assertPositiveSafeInteger
9
+ } from "./index-0s4xebbg.js";
10
+
11
+ // src/internal/bounded-body.ts
12
+ async function readBoundedChunks(source, options) {
13
+ options.signal?.throwIfAborted();
14
+ const chunks = [];
15
+ let total = 0;
16
+ if (source === null)
17
+ return { kind: "complete", chunks, total };
18
+ for await (const chunk of chunksOf(source, options.signal)) {
19
+ if (!(chunk instanceof Uint8Array)) {
20
+ throw new TypeError("A bounded body source must yield bytes (Uint8Array chunks)");
21
+ }
22
+ total += chunk.byteLength;
23
+ options.onChunk?.(chunk);
24
+ if (total > options.maxBytes)
25
+ return { kind: "over-limit", total };
26
+ chunks.push(chunk);
27
+ }
28
+ return { kind: "complete", chunks, total };
29
+ }
30
+ function concatChunks(chunks, total) {
31
+ const bytes = new Uint8Array(total);
32
+ let offset = 0;
33
+ for (const chunk of chunks) {
34
+ bytes.set(chunk, offset);
35
+ offset += chunk.byteLength;
36
+ }
37
+ return bytes;
38
+ }
39
+ async function readBoundedBody2(source, options) {
40
+ assertPositiveSafeInteger("maxBytes", options.maxBytes);
41
+ let result;
42
+ try {
43
+ result = await readBoundedChunks(source, options);
44
+ } catch (error) {
45
+ const { signal, abortError } = options;
46
+ if (signal?.aborted && abortError)
47
+ throw abortError(abortReason(signal));
48
+ throw error;
49
+ }
50
+ if (result.kind === "over-limit")
51
+ throw options.limitError(result.total);
52
+ return concatChunks(result.chunks, result.total);
53
+ }
54
+
55
+ export { readBoundedChunks, concatChunks, readBoundedBody2 };
@@ -26,7 +26,7 @@ import {
26
26
  import {
27
27
  fetchGuarded,
28
28
  readCapped
29
- } from "./index-3h0ztg0z.js";
29
+ } from "./index-t65erk4z.js";
30
30
  import {
31
31
  isWithinDir2
32
32
  } from "./index-5cc6r990.js";
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  raceAbort
3
3
  } from "./index-b0kddvzw.js";
4
+ import {
5
+ readBoundedChunks
6
+ } from "./index-qndsr7f0.js";
4
7
 
5
8
  // src/internal/secure-fetch.ts
6
9
  import { lookup } from "node:dns/promises";
@@ -259,27 +262,8 @@ async function fetchPinnedDocument(start, options) {
259
262
  throw new Error("too many redirects");
260
263
  }
261
264
  async function readCapped(res, max) {
262
- const reader = res.body?.getReader();
263
- if (!reader)
264
- return Buffer.alloc(0);
265
- const chunks = [];
266
- let total = 0;
267
- try {
268
- while (true) {
269
- const { done, value } = await reader.read();
270
- if (done)
271
- break;
272
- total += value.length;
273
- if (total > max) {
274
- await reader.cancel();
275
- return null;
276
- }
277
- chunks.push(value);
278
- }
279
- } finally {
280
- reader.releaseLock();
281
- }
282
- return Buffer.concat(chunks);
265
+ const result = await readBoundedChunks(res.body, { maxBytes: max });
266
+ return result.kind === "over-limit" ? null : Buffer.concat(result.chunks);
283
267
  }
284
268
 
285
269
  export { fetchGuarded, PrivateAddressRefusal, fetchPinnedDocument, readCapped };