stitchkit 0.80.1 → 0.82.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 (184) hide show
  1. package/CHANGELOG.md +6552 -0
  2. package/README.md +4 -0
  3. package/dist/agent-runtime/provider-failure.d.ts.map +1 -1
  4. package/dist/agent-runtime-coding-tools.js +1 -1
  5. package/dist/agent-runtime-harness.js +7 -5
  6. package/dist/agent-runtime.js +15 -19
  7. package/dist/application/notification-outbox.d.ts +80 -0
  8. package/dist/application/notification-outbox.d.ts.map +1 -0
  9. package/dist/application/process-lifecycle.d.ts +166 -0
  10. package/dist/application/process-lifecycle.d.ts.map +1 -0
  11. package/dist/application/state-store.d.ts +18 -0
  12. package/dist/application/state-store.d.ts.map +1 -0
  13. package/dist/application.d.ts +3 -0
  14. package/dist/application.d.ts.map +1 -1
  15. package/dist/application.js +568 -11
  16. package/dist/browser/http.d.ts +14 -0
  17. package/dist/browser/http.d.ts.map +1 -1
  18. package/dist/browser/resumable.d.ts +6 -0
  19. package/dist/browser/resumable.d.ts.map +1 -1
  20. package/dist/cli.js +9 -7
  21. package/dist/contract/define.d.ts +27 -4
  22. package/dist/contract/define.d.ts.map +1 -1
  23. package/dist/contract/errors-factory.d.ts +22 -3
  24. package/dist/contract/errors-factory.d.ts.map +1 -1
  25. package/dist/contract/index.d.ts +2 -2
  26. package/dist/contract/index.d.ts.map +1 -1
  27. package/dist/contract/index.js +1 -1
  28. package/dist/geo/index.d.ts +4 -0
  29. package/dist/geo/index.d.ts.map +1 -0
  30. package/dist/geo/maxmind.d.ts +4 -0
  31. package/dist/geo/maxmind.d.ts.map +1 -0
  32. package/dist/geo/resolver.d.ts +9 -0
  33. package/dist/geo/resolver.d.ts.map +1 -0
  34. package/dist/geo/types.d.ts +59 -0
  35. package/dist/geo/types.d.ts.map +1 -0
  36. package/dist/geo.d.ts +3 -0
  37. package/dist/geo.d.ts.map +1 -0
  38. package/dist/geo.js +245 -0
  39. package/dist/{index-9s6z8vgf.js → index-1dd82z59.js} +1 -1
  40. package/dist/{index-vwp69871.js → index-27487ay5.js} +4 -4
  41. package/dist/{index-7ag81v2f.js → index-27gm3d6g.js} +10 -321
  42. package/dist/{index-y01f4223.js → index-2bxcmqkb.js} +127 -43
  43. package/dist/{index-dxesg10d.js → index-3ds42w1w.js} +3 -3
  44. package/dist/index-3xwxfj4z.js +334 -0
  45. package/dist/{index-egaabxkz.js → index-5z8tezpx.js} +2 -2
  46. package/dist/{index-fxz0v7vg.js → index-7evdsyez.js} +1 -83
  47. package/dist/{index-xcetq6j3.js → index-90d7h2cr.js} +32 -13
  48. package/dist/{index-t0z5p5w6.js → index-apn8repm.js} +1 -1
  49. package/dist/{index-758zx2ha.js → index-dggwnnjv.js} +2 -2
  50. package/dist/{index-dwf1f2ap.js → index-f9mb610r.js} +1 -62
  51. package/dist/{index-5mtc969c.js → index-fwbkp2jn.js} +1 -1
  52. package/dist/index-p13mwz16.js +16 -0
  53. package/dist/{index-m9kzax52.js → index-p18f59zy.js} +21 -5
  54. package/dist/{index-hb5pf3s4.js → index-qmgs7y68.js} +1 -1
  55. package/dist/{index-2rwwmr7v.js → index-s4ckmrac.js} +1 -1
  56. package/dist/{index-h4pj6fta.js → index-s8cnx02s.js} +8 -5
  57. package/dist/{index-k9ay6v6d.js → index-vchzar7e.js} +74 -23
  58. package/dist/index-vsbzgd7b.js +84 -0
  59. package/dist/{index-dxjjv399.js → index-xbppf54a.js} +95 -15
  60. package/dist/index-y91ry9h2.js +4 -0
  61. package/dist/index-zcgf3gqf.js +83 -0
  62. package/dist/index.js +17 -13
  63. package/dist/internal/error-message.d.ts +3 -0
  64. package/dist/internal/error-message.d.ts.map +1 -0
  65. package/dist/internal/media-type.d.ts +8 -0
  66. package/dist/internal/media-type.d.ts.map +1 -0
  67. package/dist/internal/route-pattern.d.ts +21 -0
  68. package/dist/internal/route-pattern.d.ts.map +1 -1
  69. package/dist/internal/upgrade-plan.d.ts +18 -0
  70. package/dist/internal/upgrade-plan.d.ts.map +1 -0
  71. package/dist/node.js +9 -6
  72. package/dist/observability/audit.d.ts +28 -1
  73. package/dist/observability/audit.d.ts.map +1 -1
  74. package/dist/observability/bounded-logger.d.ts +20 -0
  75. package/dist/observability/bounded-logger.d.ts.map +1 -0
  76. package/dist/observability/context.d.ts +12 -3
  77. package/dist/observability/context.d.ts.map +1 -1
  78. package/dist/observability/index.d.ts +3 -2
  79. package/dist/observability/index.d.ts.map +1 -1
  80. package/dist/observability/index.js +138 -8
  81. package/dist/observability/sanitize.d.ts +17 -0
  82. package/dist/observability/sanitize.d.ts.map +1 -1
  83. package/dist/primitives.js +1 -1
  84. package/dist/react/query-client.d.ts +33 -0
  85. package/dist/react/query-client.d.ts.map +1 -0
  86. package/dist/react.d.ts +1 -0
  87. package/dist/react.d.ts.map +1 -1
  88. package/dist/react.js +83 -1
  89. package/dist/realtime/registry.d.ts +93 -0
  90. package/dist/realtime/registry.d.ts.map +1 -0
  91. package/dist/release/header.d.ts +9 -0
  92. package/dist/release/header.d.ts.map +1 -0
  93. package/dist/release/marker.d.ts +39 -0
  94. package/dist/release/marker.d.ts.map +1 -0
  95. package/dist/release/socket.d.ts +57 -0
  96. package/dist/release/socket.d.ts.map +1 -0
  97. package/dist/release/watcher.d.ts +66 -0
  98. package/dist/release/watcher.d.ts.map +1 -0
  99. package/dist/release.d.ts +15 -0
  100. package/dist/release.d.ts.map +1 -0
  101. package/dist/release.js +196 -0
  102. package/dist/remote.js +12 -7
  103. package/dist/server/context.d.ts +2 -1
  104. package/dist/server/context.d.ts.map +1 -1
  105. package/dist/server/create.d.ts.map +1 -1
  106. package/dist/server/error-hook.d.ts +17 -16
  107. package/dist/server/error-hook.d.ts.map +1 -1
  108. package/dist/server/file-state-store.d.ts +23 -0
  109. package/dist/server/file-state-store.d.ts.map +1 -0
  110. package/dist/server/implement.d.ts.map +1 -1
  111. package/dist/server/index.d.ts +5 -2
  112. package/dist/server/index.d.ts.map +1 -1
  113. package/dist/server/index.js +469 -11
  114. package/dist/server/middleware/cookies.d.ts +33 -1
  115. package/dist/server/middleware/cookies.d.ts.map +1 -1
  116. package/dist/server/middleware/cors.d.ts +16 -1
  117. package/dist/server/middleware/cors.d.ts.map +1 -1
  118. package/dist/server/openapi.d.ts.map +1 -1
  119. package/dist/server/release-signal.d.ts +35 -0
  120. package/dist/server/release-signal.d.ts.map +1 -0
  121. package/dist/server/router.d.ts.map +1 -1
  122. package/dist/server/types.d.ts +26 -2
  123. package/dist/server/types.d.ts.map +1 -1
  124. package/dist/testing/surface-manifest.d.ts.map +1 -1
  125. package/dist/testing.js +7 -4
  126. package/dist/tool-invoker.js +8 -6
  127. package/dist/tools/download-core.d.ts.map +1 -1
  128. package/dist/tools/remote.d.ts.map +1 -1
  129. package/dist/tools/view-file.d.ts.map +1 -1
  130. package/dist/tools.js +20 -16
  131. package/dist/tracking/attribution.d.ts +51 -0
  132. package/dist/tracking/attribution.d.ts.map +1 -0
  133. package/dist/tracking/beacon.d.ts +14 -0
  134. package/dist/tracking/beacon.d.ts.map +1 -0
  135. package/dist/tracking/clicks.d.ts +46 -0
  136. package/dist/tracking/clicks.d.ts.map +1 -0
  137. package/dist/tracking/client.d.ts +121 -0
  138. package/dist/tracking/client.d.ts.map +1 -0
  139. package/dist/tracking/contract.d.ts +57 -0
  140. package/dist/tracking/contract.d.ts.map +1 -0
  141. package/dist/tracking/delivery.d.ts +24 -0
  142. package/dist/tracking/delivery.d.ts.map +1 -0
  143. package/dist/tracking/host.d.ts +43 -0
  144. package/dist/tracking/host.d.ts.map +1 -0
  145. package/dist/tracking/once-per-page.d.ts +17 -0
  146. package/dist/tracking/once-per-page.d.ts.map +1 -0
  147. package/dist/tracking/outbox-storage-indexeddb.d.ts +12 -0
  148. package/dist/tracking/outbox-storage-indexeddb.d.ts.map +1 -0
  149. package/dist/tracking/outbox-storage-memory.d.ts +12 -0
  150. package/dist/tracking/outbox-storage-memory.d.ts.map +1 -0
  151. package/dist/tracking/outbox.d.ts +98 -0
  152. package/dist/tracking/outbox.d.ts.map +1 -0
  153. package/dist/tracking/schemas.d.ts +183 -0
  154. package/dist/tracking/schemas.d.ts.map +1 -0
  155. package/dist/tracking/scroll.d.ts +22 -0
  156. package/dist/tracking/scroll.d.ts.map +1 -0
  157. package/dist/tracking/sequence-reserve.d.ts +34 -0
  158. package/dist/tracking/sequence-reserve.d.ts.map +1 -0
  159. package/dist/tracking/server/active-interval.d.ts +26 -0
  160. package/dist/tracking/server/active-interval.d.ts.map +1 -0
  161. package/dist/tracking/server/bot.d.ts +9 -0
  162. package/dist/tracking/server/bot.d.ts.map +1 -0
  163. package/dist/tracking/server/disposition.d.ts +55 -0
  164. package/dist/tracking/server/disposition.d.ts.map +1 -0
  165. package/dist/tracking/server/hash.d.ts +13 -0
  166. package/dist/tracking/server/hash.d.ts.map +1 -0
  167. package/dist/tracking/server/presence.d.ts +27 -0
  168. package/dist/tracking/server/presence.d.ts.map +1 -0
  169. package/dist/tracking/server/visit-lease.d.ts +92 -0
  170. package/dist/tracking/server/visit-lease.d.ts.map +1 -0
  171. package/dist/tracking/visible-time.d.ts +38 -0
  172. package/dist/tracking/visible-time.d.ts.map +1 -0
  173. package/dist/tracking-server.d.ts +15 -0
  174. package/dist/tracking-server.d.ts.map +1 -0
  175. package/dist/tracking-server.js +173 -0
  176. package/dist/tracking.d.ts +24 -0
  177. package/dist/tracking.d.ts.map +1 -0
  178. package/dist/tracking.js +1091 -0
  179. package/dist/upgrade-cli.d.ts +27 -0
  180. package/dist/upgrade-cli.d.ts.map +1 -0
  181. package/dist/upgrade-cli.js +177 -0
  182. package/llms-full.txt +1001 -29
  183. package/llms.txt +4 -0
  184. package/package.json +30 -5
@@ -5,88 +5,6 @@ import {
5
5
  isRecord
6
6
  } from "./index-77fekveh.js";
7
7
 
8
- // src/internal/random-hex.ts
9
- function randomHex(bytes) {
10
- const arr = new Uint8Array(bytes);
11
- crypto.getRandomValues(arr);
12
- let hex = "";
13
- for (const byte of arr)
14
- hex += byte.toString(16).padStart(2, "0");
15
- return hex;
16
- }
17
-
18
- // src/observability/trace.ts
19
- var TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(.*)$/i;
20
- function createTraceContext() {
21
- return { traceId: randomHex(16), spanId: randomHex(8) };
22
- }
23
- function parseTraceparent(header) {
24
- if (!header)
25
- return null;
26
- const match = TRACEPARENT_RE.exec(header.trim());
27
- if (!match?.[1] || !match[2] || !match[3] || !match[4] || match[5] === undefined)
28
- return null;
29
- const version = match[1].toLowerCase();
30
- if (version === "ff")
31
- return null;
32
- const suffix = match[5];
33
- if (version === "00" ? suffix !== "" : suffix !== "" && !/^(?:-[0-9a-f]{2,})+$/i.test(suffix)) {
34
- return null;
35
- }
36
- const traceId = match[2].toLowerCase();
37
- const parentSpanId = match[3].toLowerCase();
38
- const traceFlags = match[4].toLowerCase();
39
- if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
40
- return null;
41
- return { traceId, spanId: randomHex(8), parentSpanId, traceFlags };
42
- }
43
- function formatTraceparent(ctx) {
44
- return `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags ?? "01"}`;
45
- }
46
- function resolveTraceContext(req) {
47
- return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
48
- }
49
- function childSpan(parent) {
50
- return {
51
- traceId: parent.traceId,
52
- spanId: randomHex(8),
53
- parentSpanId: parent.spanId,
54
- ...parent.tracestate !== undefined && { tracestate: parent.tracestate },
55
- ...parent.baggage !== undefined && { baggage: parent.baggage },
56
- ...parent.traceFlags !== undefined && { traceFlags: parent.traceFlags }
57
- };
58
- }
59
- var encoder = new TextEncoder;
60
- function boundedPropagationValue(value, maxBytes, maxMembers) {
61
- if (typeof value !== "string")
62
- return;
63
- const trimmed = value.trim();
64
- if (!trimmed || encoder.encode(trimmed).byteLength > maxBytes)
65
- return;
66
- for (const character of trimmed) {
67
- const code = character.charCodeAt(0);
68
- if (code <= 31 || code === 127)
69
- return;
70
- }
71
- const members = trimmed.split(",");
72
- if (members.length > maxMembers || members.some((member) => !member.trim())) {
73
- return;
74
- }
75
- return trimmed;
76
- }
77
- function resolvePropagationContext(metadata, fallback) {
78
- const traceparent = metadata?.traceparent;
79
- const parsed = typeof traceparent === "string" ? parseTraceparent(traceparent) : null;
80
- const trace = traceparent === undefined ? fallback ?? createTraceContext() : parsed ?? createTraceContext();
81
- const tracestate = parsed ? boundedPropagationValue(metadata?.tracestate, 512, 32) : undefined;
82
- const baggage = boundedPropagationValue(metadata?.baggage, 8192, 180);
83
- return {
84
- ...trace,
85
- ...tracestate !== undefined && { tracestate },
86
- ...baggage !== undefined && { baggage }
87
- };
88
- }
89
-
90
8
  // src/internal/errors.ts
91
9
  import { z } from "zod";
92
10
  function issuePath(path) {
@@ -191,4 +109,4 @@ function validateDeclaredOutput(schema, data, onStripped) {
191
109
  return validateHandlerOutput(schema, data, onStripped);
192
110
  }
193
111
 
194
- export { randomHex, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, resolvePropagationContext, formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput };
112
+ export { formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput };
@@ -2,11 +2,11 @@ import {
2
2
  contextContributionDelta,
3
3
  mergeContextContribution,
4
4
  prepareContextContribution
5
- } from "./index-m9kzax52.js";
5
+ } from "./index-p18f59zy.js";
6
6
  import {
7
7
  base64UrlToBytes,
8
8
  bytesToBase64Url
9
- } from "./index-y01f4223.js";
9
+ } from "./index-2bxcmqkb.js";
10
10
  import {
11
11
  forbidden,
12
12
  unauthorized
@@ -20,23 +20,32 @@ import {
20
20
  } from "./index-77fekveh.js";
21
21
 
22
22
  // src/server/middleware/cookies.ts
23
- function parseCookies(header) {
23
+ function parseCookieHeader(header) {
24
24
  if (!header)
25
- return {};
26
- const cookies = {};
25
+ return [];
26
+ const pairs = [];
27
27
  for (const pair of header.split(";")) {
28
28
  const eq = pair.indexOf("=");
29
29
  if (eq === -1)
30
30
  continue;
31
31
  const key = pair.slice(0, eq).trim();
32
- if (!key || isUnsafeKey(key))
32
+ if (!key)
33
33
  continue;
34
34
  const raw = pair.slice(eq + 1).trim();
35
+ let value = raw;
35
36
  try {
36
- cookies[key] = decodeURIComponent(raw);
37
- } catch {
38
- cookies[key] = raw;
39
- }
37
+ value = decodeURIComponent(raw);
38
+ } catch {}
39
+ pairs.push([key, value]);
40
+ }
41
+ return pairs;
42
+ }
43
+ function parseCookies(header) {
44
+ const cookies = {};
45
+ for (const [key, value] of parseCookieHeader(header)) {
46
+ if (isUnsafeKey(key))
47
+ continue;
48
+ cookies[key] = value;
40
49
  }
41
50
  return cookies;
42
51
  }
@@ -57,11 +66,21 @@ function serializeCookie(name, value, opts = {}) {
57
66
  return cookie;
58
67
  }
59
68
  function defineCookie(config) {
60
- const { name, ...options } = config;
69
+ const { name, duplicates = "last", ...options } = config;
70
+ const getAll = (req) => parseCookieHeader(req.headers.get("cookie")).flatMap(([key, value]) => key === name ? [value] : []);
61
71
  return {
62
72
  get(req) {
63
- return parseCookies(req.headers.get("cookie"))[name];
73
+ const values = getAll(req);
74
+ if (values.length === 0)
75
+ return;
76
+ if (duplicates === "first")
77
+ return values[0];
78
+ if (duplicates === "reject") {
79
+ return new Set(values).size === 1 ? values[0] : undefined;
80
+ }
81
+ return values[values.length - 1];
64
82
  },
83
+ getAll,
65
84
  set(value) {
66
85
  return serializeCookie(name, value, options);
67
86
  },
@@ -304,4 +323,4 @@ async function verifyPkce(verifier, challenge) {
304
323
  return derived === challenge;
305
324
  }
306
325
 
307
- export { parseCookies, serializeCookie, defineCookie, verifyJwt, signJwt, extractToken, createAuthHook, composeAuthHooks, createBearerResolver, deriveCodeChallenge, verifyPkce };
326
+ export { parseCookieHeader, parseCookies, serializeCookie, defineCookie, verifyJwt, signJwt, extractToken, createAuthHook, composeAuthHooks, createBearerResolver, deriveCodeChallenge, verifyPkce };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-2qzskm8h.js";
5
5
  import {
6
6
  zodIssues
7
- } from "./index-fxz0v7vg.js";
7
+ } from "./index-7evdsyez.js";
8
8
  import {
9
9
  AppError
10
10
  } from "./index-0w9abg87.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getRequestContext,
3
3
  runWithRequestContext
4
- } from "./index-dwf1f2ap.js";
4
+ } from "./index-vsbzgd7b.js";
5
5
  import {
6
6
  objectShapeKeys
7
7
  } from "./index-mgtxfe6b.js";
@@ -12,7 +12,7 @@ import {
12
12
  formatZodError,
13
13
  normalizeError,
14
14
  validateDeclaredOutput
15
- } from "./index-fxz0v7vg.js";
15
+ } from "./index-7evdsyez.js";
16
16
  import {
17
17
  AppError,
18
18
  STITCH_ERROR_STATUS,
@@ -1,6 +1,3 @@
1
- import {
2
- resolveTraceContext
3
- } from "./index-fxz0v7vg.js";
4
1
  import {
5
2
  isUnsafeKey
6
3
  } from "./index-kzfs85xp.js";
@@ -177,62 +174,4 @@ function isPublicIp(value) {
177
174
  return true;
178
175
  }
179
176
 
180
- // src/observability/context.ts
181
- import { AsyncLocalStorage } from "node:async_hooks";
182
- var storage;
183
- var requestStorage = () => {
184
- storage ??= new AsyncLocalStorage;
185
- return storage;
186
- };
187
- function runWithRequestContext(ctx, fn) {
188
- return requestStorage().run(ctx, fn);
189
- }
190
- function getRequestContext() {
191
- return requestStorage().getStore();
192
- }
193
- function getTraceId() {
194
- return requestStorage().getStore()?.trace.traceId;
195
- }
196
- function getUserId() {
197
- return requestStorage().getStore()?.userId;
198
- }
199
- function setRequestUser(userId) {
200
- const ctx = requestStorage().getStore();
201
- if (ctx)
202
- ctx.userId = userId;
203
- }
204
- function setRequestEndpoint(serviceName, action) {
205
- const ctx = requestStorage().getStore();
206
- if (ctx) {
207
- ctx.serviceName = serviceName;
208
- ctx.action = action;
209
- }
210
- }
211
- function setRequestDimensions(dimensions) {
212
- const ctx = requestStorage().getStore();
213
- if (ctx)
214
- ctx.dimensions = { ...ctx.dimensions, ...dimensions };
215
- }
216
- function setRequestError(error) {
217
- const ctx = requestStorage().getStore();
218
- if (ctx)
219
- ctx.error = error;
220
- }
221
- function wrapInRequestContext(handler, options = {}) {
222
- return (req, server) => {
223
- const ctx = {
224
- trace: resolveTraceContext(req),
225
- source: "http",
226
- method: req.method,
227
- path: new URL(req.url, "http://localhost").pathname,
228
- startedAt: process.hrtime.bigint(),
229
- ...getClientInfo(req, {
230
- trustProxy: options.trustProxy,
231
- socketIp: resolveSocketIp(req, server)
232
- })
233
- };
234
- return runWithRequestContext(ctx, () => handler(req, server));
235
- };
236
- }
237
-
238
- export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, isPublicIp, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
177
+ export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, isPublicIp };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  executeToolMethod
3
- } from "./index-758zx2ha.js";
3
+ } from "./index-dggwnnjv.js";
4
4
  import {
5
5
  assertToolExtensionCompatible,
6
6
  mergeSchemas,
@@ -0,0 +1,16 @@
1
+ import {
2
+ isRecord
3
+ } from "./index-77fekveh.js";
4
+
5
+ // src/internal/error-message.ts
6
+ function messageOf(value) {
7
+ if (value instanceof Error)
8
+ return value.message;
9
+ if (typeof value === "string")
10
+ return value;
11
+ if (isRecord(value) && typeof value.message === "string")
12
+ return value.message;
13
+ return "";
14
+ }
15
+
16
+ export { messageOf };
@@ -1,6 +1,7 @@
1
1
  import {
2
- mergeMeta
3
- } from "./index-y01f4223.js";
2
+ mergeMeta,
3
+ resolveRouteParamsSchema
4
+ } from "./index-2bxcmqkb.js";
4
5
  import {
5
6
  isUnsafeKey
6
7
  } from "./index-kzfs85xp.js";
@@ -92,7 +93,7 @@ function bindContract(contract, handlers) {
92
93
  toolName: "toolName" in endpoint ? endpoint.toolName : undefined,
93
94
  expose: endpoint.rawResponse || endpoint.rawBody || endpoint.responseMeta || "stream" in endpoint && endpoint.stream ? HTTP_ONLY : endpoint.expose,
94
95
  scope: endpoint.scope ?? groupScope,
95
- paramsSchema: endpoint.params,
96
+ paramsSchema: resolveRouteParamsSchema(endpoint.path, endpoint.params),
96
97
  inputSchema: endpoint.input,
97
98
  outputSchema: endpoint.output,
98
99
  stream: "stream" in endpoint ? endpoint.stream : undefined,
@@ -106,6 +107,7 @@ function bindContract(contract, handlers) {
106
107
  meta: mergeMeta(contract.meta.meta, endpoint.meta),
107
108
  rawResponse: endpoint.rawResponse,
108
109
  rawBody: endpoint.rawBody,
110
+ safelistedBody: endpoint.safelistedBody,
109
111
  responseMeta: endpoint.responseMeta,
110
112
  contentType: "contentType" in endpoint ? endpoint.contentType : undefined,
111
113
  handler: streamingHandler ? (ctx) => streamingHandler.execute(ctx, ctx.files ?? {}) : (ctx) => {
@@ -196,7 +198,7 @@ function createImplementRegistry() {
196
198
 
197
199
  // src/server/middleware/cors.ts
198
200
  var DEFAULT_CORS_ALLOW_HEADERS = "Content-Type, Authorization, X-Trace-Id, traceparent, tracestate";
199
- var DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Request-Id";
201
+ var DEFAULT_CORS_EXPOSE_HEADERS = "Content-Disposition, Content-Length, Content-Range, Accept-Ranges, ETag, Last-Modified, X-Request-Id, X-Build-Id";
200
202
  function assertCorsConfig(config) {
201
203
  if (config.credentials && (config.origin === undefined || config.origin === "*")) {
202
204
  throw new Error("[stitchkit] cors: `credentials: true` cannot be combined with a wildcard origin. " + "Set `origin` to an explicit string or list.");
@@ -222,6 +224,15 @@ function resolveOrigin(config, requestOrigin) {
222
224
  }
223
225
  return config.origin;
224
226
  }
227
+ function isOriginAllowed(config, requestOrigin) {
228
+ if (!config || config.origin === undefined || config.origin === "*")
229
+ return false;
230
+ if (!requestOrigin || requestOrigin === "null")
231
+ return false;
232
+ const lower = requestOrigin.toLowerCase();
233
+ const allowed = Array.isArray(config.origin) ? config.origin : [config.origin];
234
+ return allowed.some((origin) => origin.toLowerCase() === lower);
235
+ }
225
236
  function corsHeaders(config, requestOrigin) {
226
237
  const allowOrigin = resolveOrigin(config, requestOrigin);
227
238
  const headers = {
@@ -250,6 +261,11 @@ function corsPreflightResponse(config, req) {
250
261
  });
251
262
  }
252
263
 
264
+ // src/internal/media-type.ts
265
+ function mediaTypeEssence(contentType) {
266
+ return (contentType ?? "").split(";", 1)[0]?.trim().toLowerCase() ?? "";
267
+ }
268
+
253
269
  // src/server/process-signal-common.ts
254
270
  var DEFAULT_PROCESS_SIGNALS = ["SIGINT", "SIGTERM"];
255
271
  var defaultSignalSource = {
@@ -373,4 +389,4 @@ function mergeContextContribution(ctx, value, scope) {
373
389
  Object.assign(ctx, prepareContextContribution(value, scope));
374
390
  }
375
391
 
376
- export { defineMultipartStream, createMultipartStream, contractOnlyService, implement, createImplement, createScopedImplement, createScopedImplementRegistry, implementRegistry, createImplementRegistry, DEFAULT_CORS_ALLOW_HEADERS, DEFAULT_CORS_EXPOSE_HEADERS, assertCorsConfig, corsHeaders, corsPreflightResponse, DEFAULT_PROCESS_SIGNALS, defaultSignalSource, reportSignalError, guardSignalCallback, RUNTIME_CONTEXT_RESERVED_KEYS, contextContributionDelta, prepareContextContribution, mergeContextContribution };
392
+ export { mediaTypeEssence, defineMultipartStream, createMultipartStream, contractOnlyService, implement, createImplement, createScopedImplement, createScopedImplementRegistry, implementRegistry, createImplementRegistry, DEFAULT_CORS_ALLOW_HEADERS, DEFAULT_CORS_EXPOSE_HEADERS, assertCorsConfig, isOriginAllowed, corsHeaders, corsPreflightResponse, DEFAULT_PROCESS_SIGNALS, defaultSignalSource, reportSignalError, guardSignalCallback, RUNTIME_CONTEXT_RESERVED_KEYS, contextContributionDelta, prepareContextContribution, mergeContextContribution };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normalizeError
3
- } from "./index-fxz0v7vg.js";
3
+ } from "./index-7evdsyez.js";
4
4
 
5
5
  // src/internal/bounded-lines.ts
6
6
  var DEFAULT_STREAM_LINE_BYTES = 1024 * 1024;
@@ -3,7 +3,7 @@ import {
3
3
  } from "./index-dx9xehwt.js";
4
4
  import {
5
5
  contractToolMountable
6
- } from "./index-5mtc969c.js";
6
+ } from "./index-fwbkp2jn.js";
7
7
  import {
8
8
  projectToolSurface
9
9
  } from "./index-mgtxfe6b.js";
@@ -8,15 +8,18 @@ var BackoffPolicySchema = z.object({
8
8
  }).strict().readonly().refine((policy) => policy.maxDelayMs >= policy.minDelayMs, {
9
9
  message: "maxDelayMs must be at least minDelayMs"
10
10
  });
11
+ function backoffDelay(policy, attempt, random = Math.random) {
12
+ const exponential = Math.min(policy.maxDelayMs, policy.minDelayMs * 2 ** Math.max(0, attempt - 1));
13
+ const spread = exponential * policy.jitter * random();
14
+ return Math.max(1, Math.round(exponential - spread));
15
+ }
11
16
  function createBackoff(policy, random = Math.random) {
12
- const { minDelayMs, maxDelayMs, jitter } = BackoffPolicySchema.parse(policy);
17
+ const parsed = BackoffPolicySchema.parse(policy);
13
18
  let attempt = 0;
14
19
  return {
15
20
  next() {
16
- const exponential = Math.min(maxDelayMs, minDelayMs * 2 ** attempt);
17
21
  attempt += 1;
18
- const spread = exponential * jitter * random();
19
- return Math.max(1, Math.round(exponential - spread));
22
+ return backoffDelay(parsed, attempt, random);
20
23
  },
21
24
  reset() {
22
25
  attempt = 0;
@@ -84,4 +87,4 @@ async function* resumableIterator(config) {
84
87
  }
85
88
  }
86
89
 
87
- export { BackoffPolicySchema, createBackoff, resumableIterator };
90
+ export { BackoffPolicySchema, backoffDelay, createBackoff, resumableIterator };
@@ -1,3 +1,6 @@
1
+ import {
2
+ RELEASE_HEADER
3
+ } from "./index-y91ry9h2.js";
1
4
  import {
2
5
  ShutdownOptionsSchema,
3
6
  isStreamCancellation,
@@ -7,7 +10,7 @@ import {
7
10
  import {
8
11
  createValidatedRealtimeSocket,
9
12
  isModuleNotFound
10
- } from "./index-t0z5p5w6.js";
13
+ } from "./index-apn8repm.js";
11
14
  import {
12
15
  DEFAULT_PROCESS_SIGNALS,
13
16
  RUNTIME_CONTEXT_RESERVED_KEYS,
@@ -16,35 +19,42 @@ import {
16
19
  corsPreflightResponse,
17
20
  defaultSignalSource,
18
21
  guardSignalCallback,
22
+ isOriginAllowed,
23
+ mediaTypeEssence,
19
24
  reportSignalError
20
- } from "./index-m9kzax52.js";
25
+ } from "./index-p18f59zy.js";
21
26
  import {
22
- extractIp,
23
- getClientInfo,
24
27
  getRequestContext,
25
- parseQueryParams,
26
- resolveSocketIp,
27
- resolveTraceId,
28
28
  runWithRequestContext,
29
29
  setRequestEndpoint,
30
30
  setRequestError
31
- } from "./index-dwf1f2ap.js";
31
+ } from "./index-vsbzgd7b.js";
32
+ import {
33
+ extractIp,
34
+ getClientInfo,
35
+ parseQueryParams,
36
+ resolveSocketIp,
37
+ resolveTraceId
38
+ } from "./index-f9mb610r.js";
32
39
  import {
33
40
  errorCode,
34
41
  normalizeError,
35
42
  recordedErrorMessage,
36
- resolveTraceContext,
37
43
  validateDeclaredOutput
38
- } from "./index-fxz0v7vg.js";
44
+ } from "./index-7evdsyez.js";
39
45
  import {
40
46
  DEFAULT_CONTRACT_STREAM_FRAME_BYTES,
41
47
  joinRoutePath,
42
48
  parseTrailingWildcard
43
- } from "./index-y01f4223.js";
49
+ } from "./index-2bxcmqkb.js";
44
50
  import {
45
51
  AppError,
46
- badRequest
52
+ badRequest,
53
+ forbidden
47
54
  } from "./index-0w9abg87.js";
55
+ import {
56
+ resolveTraceContext
57
+ } from "./index-zcgf3gqf.js";
48
58
  import {
49
59
  isUnsafeKey,
50
60
  safeJsonParse
@@ -829,11 +839,23 @@ async function readRequestText(req, maxBytes) {
829
839
  }
830
840
 
831
841
  // src/server/context.ts
832
- function parseJsonBody(req, text) {
842
+ function parseJsonBody(req, text, method, cors) {
833
843
  if (text.trim() === "")
834
844
  return {};
835
- if (!req.headers.get("content-type")?.includes("application/json")) {
836
- badRequest("Request body must be application/json");
845
+ const essence = mediaTypeEssence(req.headers.get("content-type"));
846
+ if (essence !== "application/json") {
847
+ if (!method.safelistedBody || essence !== "text/plain") {
848
+ badRequest("Request body must be application/json");
849
+ }
850
+ const origin = req.headers.get("origin");
851
+ if (!cors || cors.origin === undefined || cors.origin === "*") {
852
+ forbidden("A text/plain body requires an explicit cors.origin allow-list on the server");
853
+ }
854
+ if (!origin)
855
+ forbidden("A text/plain body requires an Origin header");
856
+ if (!isOriginAllowed(cors, origin)) {
857
+ forbidden("A text/plain body is accepted only from an allowed origin");
858
+ }
837
859
  }
838
860
  try {
839
861
  return safeJsonParse(text);
@@ -865,7 +887,7 @@ function parsePathParamsInto(ctx, method) {
865
887
  ctx.params = method.paramsSchema.parse(ctx.params);
866
888
  }
867
889
  }
868
- async function parseRequestPayloadInto(ctx, req, url, method, maxJsonBodyBytes) {
890
+ async function parseRequestPayloadInto(ctx, req, url, method, maxJsonBodyBytes, cors) {
869
891
  if (method.multipart) {
870
892
  const multipart = await parseMultipart(req, method.multipart, method.inputSchema, method.multipartReceivers);
871
893
  ctx.input = multipart.fields;
@@ -876,12 +898,11 @@ async function parseRequestPayloadInto(ctx, req, url, method, maxJsonBodyBytes)
876
898
  if (req.method === "GET") {
877
899
  ctx.input = method.inputSchema.parse(parseQueryParams(url));
878
900
  } else if (req.method === "DELETE") {
879
- const ct = req.headers.get("content-type");
880
- if (ct?.includes("application/json")) {
901
+ if (mediaTypeEssence(req.headers.get("content-type")) === "application/json") {
881
902
  const text = await readRequestText(req, method.maxJsonBodyBytes ?? maxJsonBodyBytes);
882
903
  if (method.rawBody)
883
904
  ctx.rawBody = text;
884
- ctx.input = method.inputSchema.parse(parseJsonBody(req, text));
905
+ ctx.input = method.inputSchema.parse(parseJsonBody(req, text, method, cors));
885
906
  } else {
886
907
  ctx.input = method.inputSchema.parse(parseQueryParams(url));
887
908
  }
@@ -889,7 +910,7 @@ async function parseRequestPayloadInto(ctx, req, url, method, maxJsonBodyBytes)
889
910
  const text = await readRequestText(req, method.maxJsonBodyBytes ?? maxJsonBodyBytes);
890
911
  if (method.rawBody)
891
912
  ctx.rawBody = text;
892
- ctx.input = method.inputSchema.parse(parseJsonBody(req, text));
913
+ ctx.input = method.inputSchema.parse(parseJsonBody(req, text, method, cors));
893
914
  }
894
915
  }
895
916
  return;
@@ -1331,16 +1352,29 @@ function matchSegments(patternSegments, requestSegments) {
1331
1352
  if (actual === undefined)
1332
1353
  return null;
1333
1354
  if (pattern.startsWith(":")) {
1334
- params[pattern.slice(1)] = decodeURIComponent(actual);
1355
+ const decoded = decodeSegment(actual);
1356
+ if (decoded === null)
1357
+ return null;
1358
+ params[pattern.slice(1)] = decoded;
1335
1359
  } else if (pattern !== actual) {
1336
1360
  return null;
1337
1361
  }
1338
1362
  }
1339
1363
  if (wildcardName) {
1340
- params[wildcardName] = requestSegments.slice(prefixLength).map(decodeURIComponent).join("/");
1364
+ const decoded = requestSegments.slice(prefixLength).map(decodeSegment);
1365
+ if (decoded.some((segment) => segment === null))
1366
+ return null;
1367
+ params[wildcardName] = decoded.join("/");
1341
1368
  }
1342
1369
  return params;
1343
1370
  }
1371
+ function decodeSegment(segment) {
1372
+ try {
1373
+ return decodeURIComponent(segment);
1374
+ } catch {
1375
+ return null;
1376
+ }
1377
+ }
1344
1378
  function segmentRank(segment) {
1345
1379
  if (segment?.startsWith("*"))
1346
1380
  return 2;
@@ -1473,6 +1507,17 @@ function matchRawRoute(rawRoutes, httpMethod, pathname) {
1473
1507
  }
1474
1508
  function validateRawRoutes(rawRoutes) {
1475
1509
  const routes = rawRoutes ?? [];
1510
+ for (const route of routes) {
1511
+ if (route.serviceName !== undefined && route.serviceName.trim().length === 0) {
1512
+ throw new Error(`Raw route ${route.method} ${route.path} has an empty serviceName`);
1513
+ }
1514
+ if (route.action !== undefined && route.action.trim().length === 0) {
1515
+ throw new Error(`Raw route ${route.method} ${route.path} has an empty action`);
1516
+ }
1517
+ if (route.action !== undefined && route.serviceName === undefined) {
1518
+ throw new Error(`Raw route ${route.method} ${route.path} declares action without serviceName`);
1519
+ }
1520
+ }
1476
1521
  const shapes = routes.map((route) => rawRouteShape(route.path));
1477
1522
  const conflicts = [];
1478
1523
  for (const [laterIndex, later] of routes.entries()) {
@@ -1720,6 +1765,9 @@ function createHandler(config) {
1720
1765
  if (config.rawRoutes) {
1721
1766
  const rawMatch = matchRawRoute(config.rawRoutes, req.method, url.pathname);
1722
1767
  if (rawMatch) {
1768
+ if (rawMatch.route.serviceName !== undefined) {
1769
+ setRequestEndpoint(rawMatch.route.serviceName, rawMatch.route.action);
1770
+ }
1723
1771
  try {
1724
1772
  const res = await rawMatch.route.handler(req, {
1725
1773
  params: rawMatch.params,
@@ -1756,7 +1804,7 @@ function createHandler(config) {
1756
1804
  if (groupHooks?.authorize) {
1757
1805
  await groupHooks.authorize(ctx, method);
1758
1806
  }
1759
- multipartLifecycle = await parseRequestPayloadInto(ctx, req, url, method, config.maxJsonBodyBytes);
1807
+ multipartLifecycle = await parseRequestPayloadInto(ctx, req, url, method, config.maxJsonBodyBytes, cors);
1760
1808
  if (hooks?.beforeHandle) {
1761
1809
  await hooks.beforeHandle(ctx, method);
1762
1810
  }
@@ -1851,6 +1899,9 @@ function createHandler(config) {
1851
1899
  const response = await dispatch(req, url, traceId2, server, clientIp, startedAt);
1852
1900
  try {
1853
1901
  response.headers.set("x-request-id", traceId2);
1902
+ const buildId = config.release?.current();
1903
+ if (buildId)
1904
+ response.headers.set(RELEASE_HEADER, buildId);
1854
1905
  } catch {}
1855
1906
  return response;
1856
1907
  };