stitchkit 0.2.0 → 0.4.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 (136) hide show
  1. package/README.md +11 -10
  2. package/dist/browser/client.d.ts.map +1 -1
  3. package/dist/browser/http.d.ts +5 -0
  4. package/dist/browser/http.d.ts.map +1 -1
  5. package/dist/browser/socket-io.d.ts +17 -0
  6. package/dist/browser/socket-io.d.ts.map +1 -1
  7. package/dist/cli.d.ts +23 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +21 -0
  10. package/dist/contract/define.d.ts +35 -2
  11. package/dist/contract/define.d.ts.map +1 -1
  12. package/dist/contract/index.d.ts +1 -1
  13. package/dist/contract/index.d.ts.map +1 -1
  14. package/dist/contract/index.js +2 -1
  15. package/dist/index-0ed3bx43.js +33 -0
  16. package/dist/index-0ma1eqv4.js +1007 -0
  17. package/dist/index-1cf8jkhf.js +219 -0
  18. package/dist/index-37x76zdn.js +4 -0
  19. package/dist/{index-v2z2v3mq.js → index-3qmtdfpa.js} +304 -62
  20. package/dist/index-48ffdxgk.js +6 -0
  21. package/dist/{index-5sxnvwb1.js → index-78q1qm7v.js} +6 -3
  22. package/dist/{index-kckky6zw.js → index-afzt3nmx.js} +1 -1
  23. package/dist/{index-n7bmdwmz.js → index-d4rwrjbc.js} +8 -4
  24. package/dist/index-kzfs85xp.js +9 -0
  25. package/dist/index-mwmpw6j1.js +60 -0
  26. package/dist/{index-a35v22fh.js → index-vhdvv00d.js} +13 -5
  27. package/dist/index-x3fcszf8.js +8 -0
  28. package/dist/index.js +17 -4
  29. package/dist/internal/errors.d.ts +13 -1
  30. package/dist/internal/errors.d.ts.map +1 -1
  31. package/dist/internal/http-input.d.ts +13 -0
  32. package/dist/internal/http-input.d.ts.map +1 -0
  33. package/dist/internal/safe-json.d.ts +19 -0
  34. package/dist/internal/safe-json.d.ts.map +1 -0
  35. package/dist/internal/secure-fetch.d.ts +27 -0
  36. package/dist/internal/secure-fetch.d.ts.map +1 -0
  37. package/dist/internal/within-dir.d.ts +7 -0
  38. package/dist/internal/within-dir.d.ts.map +1 -0
  39. package/dist/node.d.ts +10 -1
  40. package/dist/node.d.ts.map +1 -1
  41. package/dist/node.js +41 -7
  42. package/dist/observability/audit.d.ts.map +1 -1
  43. package/dist/observability/context.d.ts +9 -1
  44. package/dist/observability/context.d.ts.map +1 -1
  45. package/dist/observability/event.d.ts +4 -0
  46. package/dist/observability/event.d.ts.map +1 -1
  47. package/dist/observability/index.js +38 -15
  48. package/dist/observability/sanitize.d.ts.map +1 -1
  49. package/dist/react.js +2 -0
  50. package/dist/server/context.d.ts +3 -2
  51. package/dist/server/context.d.ts.map +1 -1
  52. package/dist/server/create.d.ts.map +1 -1
  53. package/dist/server/event-bus.d.ts +10 -1
  54. package/dist/server/event-bus.d.ts.map +1 -1
  55. package/dist/server/implement.d.ts.map +1 -1
  56. package/dist/server/index.d.ts +6 -3
  57. package/dist/server/index.d.ts.map +1 -1
  58. package/dist/server/index.js +203 -193
  59. package/dist/server/logger.d.ts +5 -4
  60. package/dist/server/logger.d.ts.map +1 -1
  61. package/dist/server/middleware/auth.d.ts +41 -1
  62. package/dist/server/middleware/auth.d.ts.map +1 -1
  63. package/dist/server/middleware/cookies.d.ts.map +1 -1
  64. package/dist/server/middleware/cors.d.ts +7 -0
  65. package/dist/server/middleware/cors.d.ts.map +1 -1
  66. package/dist/server/middleware/pkce.d.ts +17 -0
  67. package/dist/server/middleware/pkce.d.ts.map +1 -0
  68. package/dist/server/multipart.d.ts +2 -1
  69. package/dist/server/multipart.d.ts.map +1 -1
  70. package/dist/server/node.d.ts +9 -0
  71. package/dist/server/node.d.ts.map +1 -1
  72. package/dist/server/openapi.d.ts +52 -0
  73. package/dist/server/openapi.d.ts.map +1 -0
  74. package/dist/server/rate-limit.d.ts +7 -2
  75. package/dist/server/rate-limit.d.ts.map +1 -1
  76. package/dist/server/request.d.ts +27 -4
  77. package/dist/server/request.d.ts.map +1 -1
  78. package/dist/server/router.d.ts +4 -2
  79. package/dist/server/router.d.ts.map +1 -1
  80. package/dist/server/socket-io.d.ts +60 -15
  81. package/dist/server/socket-io.d.ts.map +1 -1
  82. package/dist/server/stream.d.ts +3 -1
  83. package/dist/server/stream.d.ts.map +1 -1
  84. package/dist/server/types.d.ts +17 -1
  85. package/dist/server/types.d.ts.map +1 -1
  86. package/dist/server/websocket.d.ts +73 -0
  87. package/dist/server/websocket.d.ts.map +1 -0
  88. package/dist/tools/cli-args.d.ts +68 -0
  89. package/dist/tools/cli-args.d.ts.map +1 -0
  90. package/dist/tools/cli-format.d.ts +39 -0
  91. package/dist/tools/cli-format.d.ts.map +1 -0
  92. package/dist/tools/cli-wait.d.ts +45 -0
  93. package/dist/tools/cli-wait.d.ts.map +1 -0
  94. package/dist/tools/cli.d.ts +77 -0
  95. package/dist/tools/cli.d.ts.map +1 -0
  96. package/dist/tools/coerce.d.ts +8 -4
  97. package/dist/tools/coerce.d.ts.map +1 -1
  98. package/dist/tools/execute.d.ts +1 -1
  99. package/dist/tools/execute.d.ts.map +1 -1
  100. package/dist/tools/json-schema.d.ts +29 -4
  101. package/dist/tools/json-schema.d.ts.map +1 -1
  102. package/dist/tools/manifest.d.ts +4 -0
  103. package/dist/tools/manifest.d.ts.map +1 -1
  104. package/dist/tools/mcp-app.d.ts +59 -0
  105. package/dist/tools/mcp-app.d.ts.map +1 -0
  106. package/dist/tools/mcp-handler.d.ts +18 -0
  107. package/dist/tools/mcp-handler.d.ts.map +1 -1
  108. package/dist/tools/mcp.d.ts +9 -0
  109. package/dist/tools/mcp.d.ts.map +1 -1
  110. package/dist/tools/mount-download.d.ts +30 -0
  111. package/dist/tools/mount-download.d.ts.map +1 -0
  112. package/dist/tools/mount-upload.d.ts +19 -0
  113. package/dist/tools/mount-upload.d.ts.map +1 -0
  114. package/dist/tools/mount-wait.d.ts +36 -0
  115. package/dist/tools/mount-wait.d.ts.map +1 -0
  116. package/dist/tools/mount.d.ts +8 -4
  117. package/dist/tools/mount.d.ts.map +1 -1
  118. package/dist/tools/native-result.d.ts +17 -0
  119. package/dist/tools/native-result.d.ts.map +1 -0
  120. package/dist/tools/oauth-metadata.d.ts +28 -0
  121. package/dist/tools/oauth-metadata.d.ts.map +1 -0
  122. package/dist/tools/oauth-provider.d.ts +85 -0
  123. package/dist/tools/oauth-provider.d.ts.map +1 -0
  124. package/dist/tools/remote.d.ts +2 -2
  125. package/dist/tools/remote.d.ts.map +1 -1
  126. package/dist/tools/toolkit.d.ts +51 -0
  127. package/dist/tools/toolkit.d.ts.map +1 -0
  128. package/dist/tools/view-file.d.ts +12 -0
  129. package/dist/tools/view-file.d.ts.map +1 -1
  130. package/dist/tools/wait-core.d.ts +33 -0
  131. package/dist/tools/wait-core.d.ts.map +1 -0
  132. package/dist/tools.d.ts +13 -2
  133. package/dist/tools.d.ts.map +1 -1
  134. package/dist/tools.js +637 -424
  135. package/package.json +22 -9
  136. package/dist/index-ke4mx4ea.js +0 -38
@@ -0,0 +1,60 @@
1
+ import {
2
+ isUnsafeKey
3
+ } from "./index-kzfs85xp.js";
4
+ import {
5
+ isRecord
6
+ } from "./index-809wc1tt.js";
7
+
8
+ // src/server/request.ts
9
+ function generateTraceId() {
10
+ return `${Date.now().toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
11
+ }
12
+ function resolveTraceId(req) {
13
+ const header = req.headers.get("x-request-id") ?? req.headers.get("x-trace-id");
14
+ const trimmed = header?.trim();
15
+ if (trimmed && trimmed.length <= 128 && /^[\w.-]+$/.test(trimmed)) {
16
+ return trimmed;
17
+ }
18
+ return generateTraceId();
19
+ }
20
+ function resolveSocketIp(req, server) {
21
+ if (typeof server === "object" && server !== null && "requestIP" in server && typeof server.requestIP === "function") {
22
+ const addr = server.requestIP(req);
23
+ if (isRecord(addr) && typeof addr.address === "string" && addr.address) {
24
+ return addr.address;
25
+ }
26
+ }
27
+ if ("ip" in req && typeof req.ip === "string" && req.ip)
28
+ return req.ip;
29
+ return;
30
+ }
31
+ function extractIp(req, options = {}) {
32
+ if (options.trustProxy) {
33
+ const forwarded = req.headers.get("x-forwarded-for");
34
+ if (forwarded)
35
+ return (forwarded.split(",")[0] ?? "").trim().replace(/^::ffff:/, "");
36
+ const realIp = req.headers.get("x-real-ip");
37
+ if (realIp)
38
+ return realIp.trim().replace(/^::ffff:/, "");
39
+ }
40
+ return (options.socketIp ?? "").replace(/^::ffff:/, "");
41
+ }
42
+ function getClientInfo(req, options = {}) {
43
+ return {
44
+ ipAddress: extractIp(req, options) || undefined,
45
+ userAgent: req.headers.get("user-agent") ?? undefined
46
+ };
47
+ }
48
+ function parseQueryParams(url) {
49
+ const query = {};
50
+ for (const key of new Set(url.searchParams.keys())) {
51
+ if (isUnsafeKey(key))
52
+ continue;
53
+ const values = url.searchParams.getAll(key);
54
+ const [first] = values;
55
+ query[key] = values.length === 1 && first !== undefined ? first : values;
56
+ }
57
+ return query;
58
+ }
59
+
60
+ export { generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AppError
3
- } from "./index-kckky6zw.js";
3
+ } from "./index-afzt3nmx.js";
4
4
 
5
5
  // src/internal/errors.ts
6
6
  import { z } from "zod";
@@ -21,9 +21,17 @@ function normalizeError(err) {
21
21
  if (err instanceof z.ZodError) {
22
22
  return new AppError("VALIDATION_ERROR", formatZodError(err), 400);
23
23
  }
24
- const msg = err instanceof Error ? err.message : String(err);
25
- const safeMessage = msg.length > 200 ? `${msg.slice(0, 200)}...` : msg;
26
- return new AppError("INTERNAL_SERVER_ERROR", safeMessage, 500);
24
+ console.error("[stitchkit] unhandled error:", err);
25
+ return new AppError("INTERNAL_SERVER_ERROR", "Internal server error", 500);
26
+ }
27
+ function validateHandlerOutput(schema, data) {
28
+ const parsed = schema.safeParse(data);
29
+ if (parsed.success)
30
+ return { ok: true, data: parsed.data };
31
+ return {
32
+ ok: false,
33
+ message: `Handler output does not match the contract: ${formatZodError(parsed.error)}`
34
+ };
27
35
  }
28
36
 
29
- export { formatZodError, normalizeError };
37
+ export { formatZodError, normalizeError, validateHandlerOutput };
@@ -0,0 +1,8 @@
1
+ // src/internal/within-dir.ts
2
+ import { sep } from "node:path";
3
+ function isWithinDir(root, target) {
4
+ const base = root.endsWith(sep) ? root.slice(0, -sep.length) : root;
5
+ return target === root || target === base || target.startsWith(base + sep);
6
+ }
7
+
8
+ export { isWithinDir };
package/dist/index.js CHANGED
@@ -3,11 +3,12 @@ import {
3
3
  createClient,
4
4
  createClients,
5
5
  createHttpClient
6
- } from "./index-5sxnvwb1.js";
6
+ } from "./index-78q1qm7v.js";
7
7
  import {
8
8
  parseSSE
9
- } from "./index-n7bmdwmz.js";
10
- import"./index-809wc1tt.js";
9
+ } from "./index-d4rwrjbc.js";
10
+ import"./index-48ffdxgk.js";
11
+ import"./index-vhdvv00d.js";
11
12
  import {
12
13
  ALL_TRANSPORTS,
13
14
  AppError,
@@ -20,9 +21,18 @@ import {
20
21
  paginatedSchema,
21
22
  rateLimited,
22
23
  unauthorized
23
- } from "./index-kckky6zw.js";
24
+ } from "./index-afzt3nmx.js";
25
+ import"./index-809wc1tt.js";
26
+ import"./index-37x76zdn.js";
24
27
  // src/browser/socket-io.ts
25
28
  import { io } from "socket.io-client";
29
+ function toIoAuth(auth) {
30
+ if (typeof auth !== "function")
31
+ return auth;
32
+ return (cb) => {
33
+ Promise.resolve().then(auth).then(cb, () => cb({}));
34
+ };
35
+ }
26
36
  function createSocketIOClient(config) {
27
37
  let socket = null;
28
38
  const connectionListeners = new Set;
@@ -41,6 +51,9 @@ function createSocketIOClient(config) {
41
51
  socket = io(config.url, {
42
52
  path: config.path ?? "/socket.io/",
43
53
  withCredentials: config.withCredentials ?? true,
54
+ auth: toIoAuth(config.auth),
55
+ ...config.query && { query: config.query },
56
+ ...config.extraHeaders && { extraHeaders: config.extraHeaders },
44
57
  transports: config.transports ?? ["websocket", "polling"],
45
58
  autoConnect: false,
46
59
  reconnection: true,
@@ -1,5 +1,17 @@
1
- import { z } from 'zod';
1
+ import { type ZodType, z } from 'zod';
2
2
  import { AppError } from '../contract';
3
3
  export declare function formatZodError(error: z.ZodError): string;
4
4
  export declare function normalizeError(err: unknown): AppError;
5
+ /**
6
+ * Validate a handler's return value against the contract `output` schema. A
7
+ * mismatch is a **server** fault (the handler broke its own contract) — shared
8
+ * by the HTTP and tool transports so both report it identically.
9
+ */
10
+ export declare function validateHandlerOutput(schema: ZodType, data: unknown): {
11
+ ok: true;
12
+ data: unknown;
13
+ } | {
14
+ ok: false;
15
+ message: string;
16
+ };
5
17
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CASxD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAWrD"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/internal/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CASxD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAYrD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,OAAO,GACZ;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAO9D"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Where a method's input travels over HTTP — the single source of truth for the
3
+ * convention shared by the typed client (what it SENDS) and the OpenAPI
4
+ * generator (what it DOCUMENTS), so the two cannot drift. GET and DELETE carry
5
+ * their input as query parameters; the body verbs (POST / PUT / PATCH) carry it
6
+ * as a request body.
7
+ *
8
+ * The server runtime is a tolerant superset of this: it additionally accepts a
9
+ * DELETE *body* when the request carries an `application/json` content-type. The
10
+ * canonical form a client uses and the spec documents is the query form.
11
+ */
12
+ export declare function inputIsQuery(method: string): boolean;
13
+ //# sourceMappingURL=http-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-input.d.ts","sourceRoot":"","sources":["../../src/internal/http-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Prototype-pollution defence for untrusted input. Assigning a `__proto__` key
3
+ * onto a plain object (`obj[key] = value`, a JSON reviver, a merge) invokes the
4
+ * `__proto__` setter and rewires the prototype chain — the single real
5
+ * pollution vector at an assignment boundary. `constructor` / `prototype` as
6
+ * plain own keys are inert (they shadow, they do not poison), so they are NOT
7
+ * stripped — dropping them would silently corrupt legitimate data fields.
8
+ *
9
+ * Every boundary that ingests client-controlled keys (JSON bodies, query
10
+ * strings, cookies, multipart fields, tool arguments) routes through here.
11
+ */
12
+ /** True for a key that must never be copied onto a plain object from untrusted input. */
13
+ export declare function isUnsafeKey(key: string): boolean;
14
+ /**
15
+ * `JSON.parse` that strips the `__proto__` key from the result. Throws on
16
+ * invalid JSON, exactly like `JSON.parse` — callers handle that as a 400.
17
+ */
18
+ export declare function safeJsonParse(text: string): unknown;
19
+ //# sourceMappingURL=safe-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-json.d.ts","sourceRoot":"","sources":["../../src/internal/safe-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,27 @@
1
+ /** True for a loopback / private / link-local / ULA / CGNAT IP literal. */
2
+ export declare function isPrivateIp(ip: string): boolean;
3
+ /**
4
+ * Refuse a URL that is not `http(s)`, has no host, or whose host is — or
5
+ * resolves to — a private/internal address. Called on the initial URL and on
6
+ * every redirect hop, so a public host cannot `302` to an internal address or
7
+ * to a `file:` / `gopher:` / `data:` scheme.
8
+ */
9
+ export declare function assertPublicUrl(url: URL): Promise<void>;
10
+ /**
11
+ * Fetch a URL with the SSRF guard enforced on the initial URL and on every
12
+ * redirect hop — a public host can otherwise `302` to an internal address or a
13
+ * non-http(s) scheme.
14
+ *
15
+ * Note: the DNS resolution here and the resolution `fetch` performs are
16
+ * separate, so a hostile resolver retains a narrow rebinding window. The
17
+ * per-hop re-check is the larger and fully-closed hole; a static private DNS
18
+ * record is rejected outright.
19
+ */
20
+ export declare function fetchGuarded(start: URL, allowPrivate: boolean): Promise<Response>;
21
+ /**
22
+ * Read a response body into a buffer, aborting (and returning `null`) if it
23
+ * exceeds `max` bytes — the size cap that keeps a hostile or unbounded stream
24
+ * from OOM-ing the process. A missing body yields an empty buffer.
25
+ */
26
+ export declare function readCapped(res: Response, max: number): Promise<Buffer | null>;
27
+ //# sourceMappingURL=secure-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-fetch.d.ts","sourceRoot":"","sources":["../../src/internal/secure-fetch.ts"],"names":[],"mappings":"AA8CA,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAkC/C;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B7D;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAavF;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBnF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * True when `target` (an already-`resolve`d absolute path) stays inside `root`.
3
+ * Blocks `..`, absolute and otherwise-escaping paths — the shared containment
4
+ * check behind `staticRoute` and `view_file`'s local-file branch.
5
+ */
6
+ export declare function isWithinDir(root: string, target: string): boolean;
7
+ //# sourceMappingURL=within-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"within-dir.d.ts","sourceRoot":"","sources":["../../src/internal/within-dir.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQjE"}
package/dist/node.d.ts CHANGED
@@ -1,4 +1,13 @@
1
+ /**
2
+ * `stitchkit/node` — the Node entrypoint. Everything a Node app needs without
3
+ * touching the Bun-named `createServer`: the Fetch-clean `createHandler`, the
4
+ * srvx-backed `serveNode`, `implement`, the error helpers and (lazily-loaded,
5
+ * Node-safe) `createSocketIOServer`.
6
+ */
7
+ export { AppError, appError, badRequest, conflict, forbidden, notFound, rateLimited, unauthorized, } from './contract';
1
8
  export { createHandler } from './server/create';
9
+ export { createImplement, implement } from './server/implement';
2
10
  export { type NodeServerConfig, type NodeServerHandle, serveNode } from './server/node';
3
- export type { HandlerConfig } from './server/types';
11
+ export { createSocketIOServer, type SocketIOServerConfig, type SocketIOServerHandle, } from './server/socket-io';
12
+ export type { HandlerConfig, RawRoute, RawRouteContext, ServiceDef, } from './server/types';
4
13
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EAAE,aAAa,EAAE,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,aAAa,EACb,QAAQ,EACR,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC"}
package/dist/node.js CHANGED
@@ -1,16 +1,39 @@
1
1
  import {
2
- createHandler
3
- } from "./index-v2z2v3mq.js";
4
- import"./index-a35v22fh.js";
5
- import"./index-kckky6zw.js";
6
- import"./index-ke4mx4ea.js";
2
+ createHandler,
3
+ createImplement,
4
+ createSocketIOServer,
5
+ implement
6
+ } from "./index-3qmtdfpa.js";
7
+ import"./index-x3fcszf8.js";
8
+ import"./index-vhdvv00d.js";
9
+ import {
10
+ AppError,
11
+ appError,
12
+ badRequest,
13
+ conflict,
14
+ forbidden,
15
+ notFound,
16
+ rateLimited,
17
+ unauthorized
18
+ } from "./index-afzt3nmx.js";
19
+ import"./index-mwmpw6j1.js";
20
+ import"./index-kzfs85xp.js";
21
+ import"./index-809wc1tt.js";
22
+ import"./index-37x76zdn.js";
7
23
  // src/server/node.ts
8
24
  import { serve } from "srvx";
9
25
  async function serveNode(config) {
10
- const { port = 3000, hostname, ...handlerConfig } = config;
26
+ const { port = 3000, hostname, socket, ...handlerConfig } = config;
11
27
  const handler = createHandler(handlerConfig);
12
28
  const server = serve({ port, hostname, fetch: handler });
13
29
  await server.ready();
30
+ if (socket) {
31
+ const nodeServer = server.node?.server;
32
+ if (!nodeServer || !("maxRequestsPerSocket" in nodeServer)) {
33
+ throw new Error("[stitchkit] serveNode: expected a node:http.Server for Socket.IO (none / http2).");
34
+ }
35
+ socket.attach(nodeServer);
36
+ }
14
37
  const listenUrl = server.url ?? `http://${hostname ?? "localhost"}:${port}`;
15
38
  const resolvedPort = Number(new URL(listenUrl).port) || port;
16
39
  const resolvedHost = hostname ?? "localhost";
@@ -21,6 +44,17 @@ async function serveNode(config) {
21
44
  };
22
45
  }
23
46
  export {
47
+ unauthorized,
24
48
  serveNode,
25
- createHandler
49
+ rateLimited,
50
+ notFound,
51
+ implement,
52
+ forbidden,
53
+ createSocketIOServer,
54
+ createImplement,
55
+ createHandler,
56
+ conflict,
57
+ badRequest,
58
+ appError,
59
+ AppError
26
60
  };
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/observability/audit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAe,KAAK,eAAe,EAAmB,MAAM,YAAY,CAAC;AAGhF,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,EACN,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KACpD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD;;;OAGG;IACH,QAAQ,EAAE,aAAa,CAAC;CACzB;AAmBD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CA6F9D"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/observability/audit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAe,KAAK,eAAe,EAAmB,MAAM,YAAY,CAAC;AAGhF,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,EACN,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KACpD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD;;;OAGG;IACH,QAAQ,EAAE,aAAa,CAAC;CACzB;AAmBD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CA+F9D"}
@@ -46,6 +46,14 @@ export declare function setRequestError(error: {
46
46
  code?: string;
47
47
  message?: string;
48
48
  }): void;
49
+ /** Options for `wrapInRequestContext`. */
50
+ export interface WrapRequestContextOptions {
51
+ /**
52
+ * Trust `x-forwarded-for` for the client IP — enable only behind a proxy
53
+ * that rewrites it. Default `false`: the real socket peer IP is used.
54
+ */
55
+ trustProxy?: boolean;
56
+ }
49
57
  /**
50
58
  * Wrap a fetch handler so it runs inside a fresh `RequestContext` — trace ids
51
59
  * (the inbound `traceparent` continued, or freshly minted), timing and client
@@ -56,5 +64,5 @@ export declare function setRequestError(error: {
56
64
  * logs share one id), pass `traceId: getTraceId` to `createServer` /
57
65
  * `createHandler`.
58
66
  */
59
- export declare function wrapInRequestContext<S>(handler: (req: Request, server: S) => Promise<Response>): (req: Request, server: S) => Promise<Response>;
67
+ export declare function wrapInRequestContext<S>(handler: (req: Request, server: S) => Promise<Response>, options?: WrapRequestContextOptions): (req: Request, server: S) => Promise<Response>;
60
68
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAUA,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,sDAAsD;IACtD,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;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;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,GACtD,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAYhD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/observability/context.ts"],"names":[],"mappings":"AAUA,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,sDAAsD;IACtD,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;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;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGhF;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"}
@@ -39,6 +39,10 @@ export interface RequestEvent {
39
39
  responseBytes: number;
40
40
  /** Resolved user id, when authenticated. */
41
41
  userId?: string;
42
+ /** How the caller authenticated, when the app records it on the context. */
43
+ authMethod?: string;
44
+ /** Client id the call was made under (e.g. an OAuth client), when recorded. */
45
+ clientId?: string;
42
46
  /** Client IP. */
43
47
  ipAddress?: string;
44
48
  /** Client user-agent. */
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/observability/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/observability/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -1,9 +1,14 @@
1
+ import {
2
+ getClientInfo,
3
+ resolveSocketIp
4
+ } from "../index-mwmpw6j1.js";
5
+ import {
6
+ isUnsafeKey
7
+ } from "../index-kzfs85xp.js";
1
8
  import {
2
9
  isRecord
3
10
  } from "../index-809wc1tt.js";
4
- import {
5
- getClientInfo
6
- } from "../index-ke4mx4ea.js";
11
+ import"../index-37x76zdn.js";
7
12
 
8
13
  // src/observability/context.ts
9
14
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -27,11 +32,11 @@ function parseTraceparent(header) {
27
32
  const match = TRACEPARENT_RE.exec(header.trim());
28
33
  if (!match?.[1] || !match[2])
29
34
  return null;
30
- return {
31
- traceId: match[1].toLowerCase(),
32
- spanId: randomHex(8),
33
- parentSpanId: match[2].toLowerCase()
34
- };
35
+ const traceId = match[1].toLowerCase();
36
+ const parentSpanId = match[2].toLowerCase();
37
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
38
+ return null;
39
+ return { traceId, spanId: randomHex(8), parentSpanId };
35
40
  }
36
41
  function formatTraceparent(ctx) {
37
42
  return `00-${ctx.traceId}-${ctx.spanId}-01`;
@@ -71,15 +76,18 @@ function setRequestError(error) {
71
76
  if (ctx)
72
77
  ctx.error = error;
73
78
  }
74
- function wrapInRequestContext(handler) {
79
+ function wrapInRequestContext(handler, options = {}) {
75
80
  return (req, server) => {
76
81
  const ctx = {
77
82
  trace: resolveTraceContext(req),
78
83
  source: "http",
79
84
  method: req.method,
80
- path: new URL(req.url).pathname,
85
+ path: new URL(req.url, "http://localhost").pathname,
81
86
  startedAt: process.hrtime.bigint(),
82
- ...getClientInfo(req)
87
+ ...getClientInfo(req, {
88
+ trustProxy: options.trustProxy,
89
+ socketIp: resolveSocketIp(req, server)
90
+ })
83
91
  };
84
92
  return runWithRequestContext(ctx, () => handler(req, server));
85
93
  };
@@ -93,6 +101,7 @@ var MASK = "[redacted]";
93
101
  function redact(value, options = {}) {
94
102
  const sensitive = options.sensitiveKeys ?? DEFAULT_SENSITIVE_KEYS;
95
103
  const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
104
+ const ancestors = new Set;
96
105
  const walk = (input, depth) => {
97
106
  if (depth > maxDepth)
98
107
  return "[max depth]";
@@ -111,13 +120,24 @@ function redact(value, options = {}) {
111
120
  return { _type: "formdata", keys: [...input.keys()] };
112
121
  }
113
122
  if (Array.isArray(input)) {
114
- return input.map((item) => walk(item, depth + 1));
123
+ if (ancestors.has(input))
124
+ return "[circular]";
125
+ ancestors.add(input);
126
+ const result = input.map((item) => walk(item, depth + 1));
127
+ ancestors.delete(input);
128
+ return result;
115
129
  }
116
130
  if (isRecord(input)) {
131
+ if (ancestors.has(input))
132
+ return "[circular]";
133
+ ancestors.add(input);
117
134
  const out = {};
118
135
  for (const [key, val] of Object.entries(input)) {
136
+ if (isUnsafeKey(key))
137
+ continue;
119
138
  out[key] = sensitive.test(key) ? MASK : walk(val, depth + 1);
120
139
  }
140
+ ancestors.delete(input);
121
141
  return out;
122
142
  }
123
143
  return String(input);
@@ -126,11 +146,12 @@ function redact(value, options = {}) {
126
146
  }
127
147
  function truncatePreview(value, maxBytes = DEFAULT_MAX_BYTES) {
128
148
  const json = JSON.stringify(value);
129
- if (json.length <= maxBytes)
149
+ const bytes = Buffer.byteLength(json, "utf8");
150
+ if (bytes <= maxBytes)
130
151
  return value;
131
152
  return {
132
153
  _truncated: true,
133
- _originalBytes: json.length,
154
+ _originalBytes: bytes,
134
155
  preview: `${json.slice(0, maxBytes)}…`
135
156
  };
136
157
  }
@@ -147,7 +168,7 @@ function measureSize(value) {
147
168
  if (Array.isArray(value)) {
148
169
  return { resultSize: value.length, responseBytes };
149
170
  }
150
- if (typeof value === "object" && "items" in value && Array.isArray(value.items)) {
171
+ if (isRecord(value) && Array.isArray(value.items) && "nextCursor" in value) {
151
172
  return { resultSize: value.items.length, responseBytes };
152
173
  }
153
174
  return { resultSize: null, responseBytes };
@@ -237,6 +258,8 @@ function createAuditHook(config) {
237
258
  resultSize: measure.resultSize,
238
259
  responseBytes: measure.responseBytes,
239
260
  userId: readString(context.userId),
261
+ authMethod: readString(context.authMethod),
262
+ clientId: readString(context.clientId),
240
263
  ipAddress: readString(context.ipAddress),
241
264
  userAgent: readString(context.userAgent),
242
265
  startedAt: new Date(Date.now() - durationMs)
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/observability/sanitize.ts"],"names":[],"mappings":"AAMA,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8BAA8B;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB;AASD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB,GAAG,SAAS,CAsC/E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,SAAoB,GAAG,SAAS,CAQzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,SAAS,GAAG,IAAI,CAGlB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAYvD"}
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/observability/sanitize.ts"],"names":[],"mappings":"AAOA,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8BAA8B;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB;AASD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB,GAAG,SAAS,CAoD/E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,SAAoB,GAAG,SAAS,CASzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,SAAS,GAAG,IAAI,CAGlB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAcvD"}
package/dist/react.js CHANGED
@@ -1,3 +1,5 @@
1
+ import"./index-37x76zdn.js";
2
+
1
3
  // src/react/cache-bridge.ts
2
4
  function createCacheBridge(config) {
3
5
  const freshWindow = config.freshWindow ?? 500;
@@ -3,7 +3,8 @@
3
3
  * endpoint schemas and gathers request metadata (trace id, client info).
4
4
  */
5
5
  import { type RuntimeContext } from '../contract';
6
+ import { type ClientIpOptions } from './request';
6
7
  import type { MethodDef } from './types';
7
- export declare function buildContext(req: Request, url: URL, method: MethodDef, pathParams: Record<string, string>, traceId: string): Promise<RuntimeContext>;
8
- export declare function buildErrorContext(req: Request, url: URL, traceId: string): RuntimeContext;
8
+ export declare function buildContext(req: Request, url: URL, method: MethodDef, pathParams: Record<string, string>, traceId: string, clientIp: ClientIpOptions): Promise<RuntimeContext>;
9
+ export declare function buildErrorContext(req: Request, url: URL, traceId: string, clientIp: ClientIpOptions): RuntimeContext;
9
10
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AA2BzC,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAyCzB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAWzF"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmCzC,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CA2CzB;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,cAAc,CAWhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA0BA,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,CAiLxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA8BA,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,CAwMxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
@@ -19,6 +19,15 @@ export interface EventBus<M extends Record<string, unknown> = DefaultEventMap> {
19
19
  off<K extends keyof M & string>(event: K, handler: EventHandler<M[K]>): void;
20
20
  clear(): void;
21
21
  }
22
- export declare function createEventBus<M extends Record<string, unknown> = DefaultEventMap>(): EventBus<M>;
22
+ /** Options for `createEventBus`. */
23
+ export interface EventBusOptions {
24
+ /**
25
+ * Called when a listener throws or rejects. A bus listener's failure must
26
+ * never break the bus, so it is caught — but without this hook it is also
27
+ * invisible. Wire it to a logger to surface listener bugs.
28
+ */
29
+ onListenerError?: (error: unknown, event: string) => void;
30
+ }
31
+ export declare function createEventBus<M extends Record<string, unknown> = DefaultEventMap>(options?: EventBusOptions): EventBus<M>;
23
32
  export {};
24
33
  //# sourceMappingURL=event-bus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/server/event-bus.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnE,sEAAsE;AACtE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe;IAC3E,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7D,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAClF,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IACpF,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7E,KAAK,IAAI,IAAI,CAAC;CACf;AAYD,wBAAgB,cAAc,CAC5B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,KAChD,QAAQ,CAAC,CAAC,CAAC,CAuDf"}
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/server/event-bus.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnE,sEAAsE;AACtE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe;IAC3E,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7D,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAClF,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IACpF,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7E,KAAK,IAAI,IAAI,CAAC;CACf;AAYD,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAChF,OAAO,GAAE,eAAoB,GAC5B,QAAQ,CAAC,CAAC,CAAC,CA0Db"}
@@ -1 +1 @@
1
- {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CAoC3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,MACjD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,UAAU,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,UAAU,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,KAC1B,UAAU,CACd"}
1
+ {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CAsC3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,MACjD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,UAAU,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,UAAU,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,KAC1B,UAAU,CACd"}
@@ -3,15 +3,18 @@ export { cacheHeaders, createCache } from './cache';
3
3
  export { createHandler, createServer } from './create';
4
4
  export { createEventBus, type EventBus } from './event-bus';
5
5
  export { createImplement, implement } from './implement';
6
- export { type AuthHook, type AuthHookConfig, type AuthRule, type BearerResolverConfig, createAuthHook, createBearerResolver, extractToken, type JwtPayload, verifyJwt, } from './middleware/auth';
6
+ export { type AuthHook, type AuthHookConfig, type AuthRule, type BearerResolverConfig, createAuthHook, createBearerResolver, extractToken, type JwtPayload, type SignJwtOptions, signJwt, verifyJwt, } from './middleware/auth';
7
7
  export { type CookieDef, type CookieOptions, defineCookie, parseCookies, serializeCookie, } from './middleware/cookies';
8
8
  export { type CorsConfig, corsHeaders, corsPreflightResponse, } from './middleware/cors';
9
+ export { deriveCodeChallenge, type PkceMethod, verifyPkce } from './middleware/pkce';
9
10
  export { parseMultipart } from './multipart';
11
+ export { generateOpenApiDocument, type OpenApiConfig, type OpenApiDocument, type OpenApiInfo, type OpenApiServer, openApiRoute, } from './openapi';
10
12
  export { createRateLimiter, type RateLimitConfig } from './rate-limit';
11
- export { extractIp, generateTraceId, getClientInfo, resolveTraceId, } from './request';
13
+ export { type ClientIpOptions, extractIp, generateTraceId, getClientInfo, resolveSocketIp, resolveTraceId, } from './request';
12
14
  export { staticRoute } from './router';
13
15
  export type { SocketIOServerConfig, SocketIOServerHandle } from './socket-io';
14
- export { createSocketIOServer } from './socket-io';
16
+ export { createSocketIOServer, socketIoLane } from './socket-io';
15
17
  export { type ParseSSEOptions, parseSSE, streamSSE } from './stream';
16
18
  export type { BunServer, BunServerConfig, HandlerConfig, Handlers, LifecycleHooks, MethodDef, RawRoute, RawRouteContext, RouteGroup, ServerPassthrough, ServiceDef, StitchLogger, } from './types';
19
+ export { type ComposedLane, composeWebSocketHandlers, type WebSocketComposeConfig, type WebSocketLane, webSocketLane, } from './websocket';
17
20
  //# sourceMappingURL=index.d.ts.map