stitchkit 0.2.0 → 0.3.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 (63) hide show
  1. package/dist/browser/http.d.ts +5 -0
  2. package/dist/browser/http.d.ts.map +1 -1
  3. package/dist/{index-a35v22fh.js → index-0t460v7k.js} +12 -4
  4. package/dist/{index-n7bmdwmz.js → index-4b1j82gp.js} +8 -4
  5. package/dist/{index-5sxnvwb1.js → index-4kz3aqpx.js} +2 -2
  6. package/dist/{index-v2z2v3mq.js → index-dpj1jcys.js} +150 -60
  7. package/dist/index-kzfs85xp.js +9 -0
  8. package/dist/index-mwmpw6j1.js +60 -0
  9. package/dist/index-q6ja2qwq.js +7 -0
  10. package/dist/index.js +4 -3
  11. package/dist/internal/errors.d.ts +13 -1
  12. package/dist/internal/errors.d.ts.map +1 -1
  13. package/dist/internal/safe-json.d.ts +19 -0
  14. package/dist/internal/safe-json.d.ts.map +1 -0
  15. package/dist/internal/within-dir.d.ts +7 -0
  16. package/dist/internal/within-dir.d.ts.map +1 -0
  17. package/dist/node.js +6 -3
  18. package/dist/observability/context.d.ts +9 -1
  19. package/dist/observability/context.d.ts.map +1 -1
  20. package/dist/observability/index.js +35 -15
  21. package/dist/observability/sanitize.d.ts.map +1 -1
  22. package/dist/server/context.d.ts +3 -2
  23. package/dist/server/context.d.ts.map +1 -1
  24. package/dist/server/create.d.ts.map +1 -1
  25. package/dist/server/event-bus.d.ts +10 -1
  26. package/dist/server/event-bus.d.ts.map +1 -1
  27. package/dist/server/index.d.ts +1 -1
  28. package/dist/server/index.d.ts.map +1 -1
  29. package/dist/server/index.js +86 -32
  30. package/dist/server/logger.d.ts +5 -4
  31. package/dist/server/logger.d.ts.map +1 -1
  32. package/dist/server/middleware/auth.d.ts +24 -1
  33. package/dist/server/middleware/auth.d.ts.map +1 -1
  34. package/dist/server/middleware/cookies.d.ts.map +1 -1
  35. package/dist/server/middleware/cors.d.ts +7 -0
  36. package/dist/server/middleware/cors.d.ts.map +1 -1
  37. package/dist/server/multipart.d.ts +2 -1
  38. package/dist/server/multipart.d.ts.map +1 -1
  39. package/dist/server/rate-limit.d.ts +7 -2
  40. package/dist/server/rate-limit.d.ts.map +1 -1
  41. package/dist/server/request.d.ts +27 -4
  42. package/dist/server/request.d.ts.map +1 -1
  43. package/dist/server/router.d.ts +4 -2
  44. package/dist/server/router.d.ts.map +1 -1
  45. package/dist/server/stream.d.ts +3 -1
  46. package/dist/server/stream.d.ts.map +1 -1
  47. package/dist/server/types.d.ts +12 -0
  48. package/dist/server/types.d.ts.map +1 -1
  49. package/dist/tools/coerce.d.ts +8 -4
  50. package/dist/tools/coerce.d.ts.map +1 -1
  51. package/dist/tools/execute.d.ts +1 -1
  52. package/dist/tools/execute.d.ts.map +1 -1
  53. package/dist/tools/manifest.d.ts +4 -0
  54. package/dist/tools/manifest.d.ts.map +1 -1
  55. package/dist/tools/mcp-handler.d.ts.map +1 -1
  56. package/dist/tools/mount.d.ts +2 -2
  57. package/dist/tools/mount.d.ts.map +1 -1
  58. package/dist/tools/view-file.d.ts.map +1 -1
  59. package/dist/tools.d.ts +1 -1
  60. package/dist/tools.d.ts.map +1 -1
  61. package/dist/tools.js +140 -93
  62. package/package.json +1 -1
  63. package/dist/index-ke4mx4ea.js +0 -38
package/dist/node.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  createHandler
3
- } from "./index-v2z2v3mq.js";
4
- import"./index-a35v22fh.js";
3
+ } from "./index-dpj1jcys.js";
4
+ import"./index-q6ja2qwq.js";
5
+ import"./index-0t460v7k.js";
5
6
  import"./index-kckky6zw.js";
6
- import"./index-ke4mx4ea.js";
7
+ import"./index-mwmpw6j1.js";
8
+ import"./index-kzfs85xp.js";
9
+ import"./index-809wc1tt.js";
7
10
  // src/server/node.ts
8
11
  import { serve } from "srvx";
9
12
  async function serveNode(config) {
@@ -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"}
@@ -1,9 +1,13 @@
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";
7
11
 
8
12
  // src/observability/context.ts
9
13
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -27,11 +31,11 @@ function parseTraceparent(header) {
27
31
  const match = TRACEPARENT_RE.exec(header.trim());
28
32
  if (!match?.[1] || !match[2])
29
33
  return null;
30
- return {
31
- traceId: match[1].toLowerCase(),
32
- spanId: randomHex(8),
33
- parentSpanId: match[2].toLowerCase()
34
- };
34
+ const traceId = match[1].toLowerCase();
35
+ const parentSpanId = match[2].toLowerCase();
36
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
37
+ return null;
38
+ return { traceId, spanId: randomHex(8), parentSpanId };
35
39
  }
36
40
  function formatTraceparent(ctx) {
37
41
  return `00-${ctx.traceId}-${ctx.spanId}-01`;
@@ -71,15 +75,18 @@ function setRequestError(error) {
71
75
  if (ctx)
72
76
  ctx.error = error;
73
77
  }
74
- function wrapInRequestContext(handler) {
78
+ function wrapInRequestContext(handler, options = {}) {
75
79
  return (req, server) => {
76
80
  const ctx = {
77
81
  trace: resolveTraceContext(req),
78
82
  source: "http",
79
83
  method: req.method,
80
- path: new URL(req.url).pathname,
84
+ path: new URL(req.url, "http://localhost").pathname,
81
85
  startedAt: process.hrtime.bigint(),
82
- ...getClientInfo(req)
86
+ ...getClientInfo(req, {
87
+ trustProxy: options.trustProxy,
88
+ socketIp: resolveSocketIp(req, server)
89
+ })
83
90
  };
84
91
  return runWithRequestContext(ctx, () => handler(req, server));
85
92
  };
@@ -93,6 +100,7 @@ var MASK = "[redacted]";
93
100
  function redact(value, options = {}) {
94
101
  const sensitive = options.sensitiveKeys ?? DEFAULT_SENSITIVE_KEYS;
95
102
  const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
103
+ const ancestors = new Set;
96
104
  const walk = (input, depth) => {
97
105
  if (depth > maxDepth)
98
106
  return "[max depth]";
@@ -111,13 +119,24 @@ function redact(value, options = {}) {
111
119
  return { _type: "formdata", keys: [...input.keys()] };
112
120
  }
113
121
  if (Array.isArray(input)) {
114
- return input.map((item) => walk(item, depth + 1));
122
+ if (ancestors.has(input))
123
+ return "[circular]";
124
+ ancestors.add(input);
125
+ const result = input.map((item) => walk(item, depth + 1));
126
+ ancestors.delete(input);
127
+ return result;
115
128
  }
116
129
  if (isRecord(input)) {
130
+ if (ancestors.has(input))
131
+ return "[circular]";
132
+ ancestors.add(input);
117
133
  const out = {};
118
134
  for (const [key, val] of Object.entries(input)) {
135
+ if (isUnsafeKey(key))
136
+ continue;
119
137
  out[key] = sensitive.test(key) ? MASK : walk(val, depth + 1);
120
138
  }
139
+ ancestors.delete(input);
121
140
  return out;
122
141
  }
123
142
  return String(input);
@@ -126,11 +145,12 @@ function redact(value, options = {}) {
126
145
  }
127
146
  function truncatePreview(value, maxBytes = DEFAULT_MAX_BYTES) {
128
147
  const json = JSON.stringify(value);
129
- if (json.length <= maxBytes)
148
+ const bytes = Buffer.byteLength(json, "utf8");
149
+ if (bytes <= maxBytes)
130
150
  return value;
131
151
  return {
132
152
  _truncated: true,
133
- _originalBytes: json.length,
153
+ _originalBytes: bytes,
134
154
  preview: `${json.slice(0, maxBytes)}…`
135
155
  };
136
156
  }
@@ -147,7 +167,7 @@ function measureSize(value) {
147
167
  if (Array.isArray(value)) {
148
168
  return { resultSize: value.length, responseBytes };
149
169
  }
150
- if (typeof value === "object" && "items" in value && Array.isArray(value.items)) {
170
+ if (isRecord(value) && Array.isArray(value.items) && "nextCursor" in value) {
151
171
  return { resultSize: value.items.length, responseBytes };
152
172
  }
153
173
  return { resultSize: null, responseBytes };
@@ -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"}
@@ -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"}
@@ -8,7 +8,7 @@ export { type CookieDef, type CookieOptions, defineCookie, parseCookies, seriali
8
8
  export { type CorsConfig, corsHeaders, corsPreflightResponse, } from './middleware/cors';
9
9
  export { parseMultipart } from './multipart';
10
10
  export { createRateLimiter, type RateLimitConfig } from './rate-limit';
11
- export { extractIp, generateTraceId, getClientInfo, resolveTraceId, } from './request';
11
+ export { type ClientIpOptions, extractIp, generateTraceId, getClientInfo, resolveSocketIp, resolveTraceId, } from './request';
12
12
  export { staticRoute } from './router';
13
13
  export type { SocketIOServerConfig, SocketIOServerHandle } from './socket-io';
14
14
  export { createSocketIOServer } from './socket-io';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EACL,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseSSE,
3
3
  streamSSE
4
- } from "../index-n7bmdwmz.js";
4
+ } from "../index-4b1j82gp.js";
5
5
  import {
6
6
  corsHeaders,
7
7
  corsPreflightResponse,
@@ -9,8 +9,9 @@ import {
9
9
  createServer,
10
10
  parseMultipart,
11
11
  staticRoute
12
- } from "../index-v2z2v3mq.js";
13
- import"../index-a35v22fh.js";
12
+ } from "../index-dpj1jcys.js";
13
+ import"../index-q6ja2qwq.js";
14
+ import"../index-0t460v7k.js";
14
15
  import {
15
16
  AppError,
16
17
  appError,
@@ -25,8 +26,16 @@ import {
25
26
  extractIp,
26
27
  generateTraceId,
27
28
  getClientInfo,
29
+ resolveSocketIp,
28
30
  resolveTraceId
29
- } from "../index-ke4mx4ea.js";
31
+ } from "../index-mwmpw6j1.js";
32
+ import {
33
+ isUnsafeKey,
34
+ safeJsonParse
35
+ } from "../index-kzfs85xp.js";
36
+ import {
37
+ isRecord
38
+ } from "../index-809wc1tt.js";
30
39
  // src/server/swept-map.ts
31
40
  function createSweptMap(options) {
32
41
  const store = new Map;
@@ -85,7 +94,7 @@ function cacheHeaders(maxAge, scope = "public") {
85
94
  };
86
95
  }
87
96
  // src/server/event-bus.ts
88
- function createEventBus() {
97
+ function createEventBus(options = {}) {
89
98
  const subscriptions = new Map;
90
99
  function add(event, fn, once) {
91
100
  let set = subscriptions.get(event);
@@ -109,11 +118,12 @@ function createEventBus() {
109
118
  set.delete(sub);
110
119
  try {
111
120
  const result = sub.fn(data);
112
- if (result instanceof Promise)
113
- result.catch(() => {
114
- return;
115
- });
116
- } catch {}
121
+ if (result instanceof Promise) {
122
+ result.catch((err) => options.onListenerError?.(err, event));
123
+ }
124
+ } catch (err) {
125
+ options.onListenerError?.(err, event);
126
+ }
117
127
  }
118
128
  },
119
129
  on(event, handler) {
@@ -172,14 +182,17 @@ function parseCookies(header) {
172
182
  return {};
173
183
  const cookies = {};
174
184
  for (const pair of header.split(";")) {
175
- const [key, ...rest] = pair.split("=");
176
- if (!key)
185
+ const eq = pair.indexOf("=");
186
+ if (eq === -1)
187
+ continue;
188
+ const key = pair.slice(0, eq).trim();
189
+ if (!key || isUnsafeKey(key))
177
190
  continue;
178
- const raw = rest.join("=").trim();
191
+ const raw = pair.slice(eq + 1).trim();
179
192
  try {
180
- cookies[key.trim()] = decodeURIComponent(raw);
193
+ cookies[key] = decodeURIComponent(raw);
181
194
  } catch {
182
- cookies[key.trim()] = raw;
195
+ cookies[key] = raw;
183
196
  }
184
197
  }
185
198
  return cookies;
@@ -216,26 +229,37 @@ function defineCookie(config) {
216
229
  }
217
230
 
218
231
  // src/server/middleware/auth.ts
232
+ var MAX_TOKEN_BYTES = 8192;
219
233
  function decodeBase64Url(segment) {
234
+ if (!/^[A-Za-z0-9_-]*$/.test(segment) || segment.length % 4 === 1) {
235
+ throw new Error("invalid base64url segment");
236
+ }
220
237
  const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
221
238
  const padded = b64.padEnd(Math.ceil(b64.length / 4) * 4, "=");
222
239
  return Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
223
240
  }
224
- async function verifyJwt(token, secret) {
241
+ async function verifyJwt(token, secret, options = {}) {
242
+ if (!secret)
243
+ throw new Error("verifyJwt: a non-empty secret is required");
244
+ if (token.length > MAX_TOKEN_BYTES)
245
+ throw unauthorized("Token too large");
225
246
  const [headerB64, payloadB64, signatureB64] = token.split(".");
226
247
  if (!headerB64 || !payloadB64 || !signatureB64)
227
248
  throw unauthorized("Invalid token format");
228
249
  let header;
229
- let payload;
250
+ let payloadRaw;
230
251
  let signature;
231
252
  try {
232
253
  const decoder = new TextDecoder;
233
254
  header = JSON.parse(decoder.decode(decodeBase64Url(headerB64)));
234
- payload = JSON.parse(decoder.decode(decodeBase64Url(payloadB64)));
255
+ payloadRaw = safeJsonParse(decoder.decode(decodeBase64Url(payloadB64)));
235
256
  signature = decodeBase64Url(signatureB64);
236
257
  } catch {
237
258
  throw unauthorized("Malformed token");
238
259
  }
260
+ if (!isRecord(payloadRaw))
261
+ throw unauthorized("Malformed token");
262
+ const payload = payloadRaw;
239
263
  if (header.alg !== "HS256")
240
264
  throw unauthorized("Unsupported token algorithm");
241
265
  const encoder = new TextEncoder;
@@ -244,12 +268,28 @@ async function verifyJwt(token, secret) {
244
268
  const valid = await crypto.subtle.verify("HMAC", key, signature, data);
245
269
  if (!valid)
246
270
  throw unauthorized("Invalid token signature");
271
+ const leeway = options.leewaySeconds ?? 60;
247
272
  const now = Date.now() / 1000;
248
- if (typeof payload.exp === "number" && payload.exp < now) {
249
- throw unauthorized("Token expired");
273
+ if ("exp" in payload) {
274
+ if (typeof payload.exp !== "number")
275
+ throw unauthorized("Malformed token");
276
+ if (payload.exp < now - leeway)
277
+ throw unauthorized("Token expired");
278
+ }
279
+ if ("nbf" in payload) {
280
+ if (typeof payload.nbf !== "number")
281
+ throw unauthorized("Malformed token");
282
+ if (payload.nbf > now + leeway)
283
+ throw unauthorized("Token not yet valid");
250
284
  }
251
- if (typeof payload.nbf === "number" && payload.nbf > now) {
252
- throw unauthorized("Token not yet valid");
285
+ if (options.issuer !== undefined && payload.iss !== options.issuer) {
286
+ throw unauthorized("Token issuer mismatch");
287
+ }
288
+ if (options.audience !== undefined) {
289
+ const aud = payload.aud;
290
+ const ok = Array.isArray(aud) ? aud.includes(options.audience) : aud === options.audience;
291
+ if (!ok)
292
+ throw unauthorized("Token audience mismatch");
253
293
  }
254
294
  return payload;
255
295
  }
@@ -267,15 +307,16 @@ function createAuthHook(config) {
267
307
  const onAnonymous = config.onAnonymous ?? (() => unauthorized());
268
308
  const onForbidden = config.onForbidden ?? (() => forbidden());
269
309
  return async (ctx, endpoint) => {
270
- if (!(ctx.req instanceof Request))
271
- return;
272
- const identity = await config.resolve(ctx);
310
+ const identity = ctx.source === "http" ? await config.resolve(ctx) : await config.resolveFromContext?.(ctx) ?? null;
273
311
  config.inject?.(ctx, identity);
274
312
  const scope = endpoint.scope ?? config.defaultScope;
275
313
  if (!scope)
276
314
  return;
277
315
  const rule = config.rules[scope];
278
- if (!rule || rule === "public")
316
+ if (!rule) {
317
+ throw new Error(`[stitchkit] auth: no rule for scope "${scope}"`);
318
+ }
319
+ if (rule === "public")
279
320
  return;
280
321
  if (!identity) {
281
322
  onAnonymous();
@@ -301,6 +342,7 @@ function refillBucket(entry, config, now) {
301
342
  entry.tokens = Math.min(config.max, entry.tokens + elapsed / config.window * config.max);
302
343
  entry.lastRefill = now;
303
344
  }
345
+ var MAX_BUCKETS = 1e5;
304
346
  function createRateLimiter() {
305
347
  const { store: buckets, destroy } = createSweptMap({
306
348
  intervalMs: 60000,
@@ -310,15 +352,26 @@ function createRateLimiter() {
310
352
  destroy,
311
353
  check(key, config) {
312
354
  const now = Date.now();
313
- let entry = buckets.get(key);
314
- if (!entry) {
315
- entry = { tokens: config.max, lastRefill: now };
355
+ const entry = buckets.get(key);
356
+ if (entry) {
357
+ buckets.delete(key);
316
358
  buckets.set(key, entry);
359
+ refillBucket(entry, config, now);
360
+ if (entry.tokens < 1)
361
+ return false;
362
+ entry.tokens -= 1;
363
+ return true;
364
+ }
365
+ if (buckets.size >= MAX_BUCKETS) {
366
+ const lru = buckets.keys().next().value;
367
+ if (lru !== undefined)
368
+ buckets.delete(lru);
317
369
  }
318
- refillBucket(entry, config, now);
319
- if (entry.tokens < 1)
370
+ const fresh = { tokens: config.max, lastRefill: now };
371
+ buckets.set(key, fresh);
372
+ if (fresh.tokens < 1)
320
373
  return false;
321
- entry.tokens -= 1;
374
+ fresh.tokens -= 1;
322
375
  return true;
323
376
  },
324
377
  remaining(key, config) {
@@ -368,6 +421,7 @@ export {
368
421
  staticRoute,
369
422
  serializeCookie,
370
423
  resolveTraceId,
424
+ resolveSocketIp,
371
425
  rateLimited,
372
426
  parseSSE,
373
427
  parseMultipart,
@@ -1,4 +1,5 @@
1
- export declare function elapsedMs(startTime: bigint): number;
1
+ /** Elapsed milliseconds since a `performance.now()` mark. */
2
+ export declare function elapsedMs(startTime: number): number;
2
3
  /** Map an HTTP status to a log level. */
3
4
  export declare function levelForStatus(status: number): 'error' | 'warn' | 'info';
4
5
  /** The structured fields shared by every completed-request log line. */
@@ -11,11 +12,11 @@ export declare function buildLogFields(method: string, path: string, status: num
11
12
  };
12
13
  export interface RequestLog {
13
14
  traceId: string;
14
- startTime: bigint;
15
+ startTime: number;
15
16
  }
16
17
  export declare function shouldLog(pathname: string, method: string): boolean;
17
18
  /** Open the timing window for a request. Development prints a `→` line. */
18
- export declare function logIncoming(req: Request, pathname: string, traceId: string): RequestLog;
19
+ export declare function logIncoming(req: Request, pathname: string, traceId: string, ipAddress?: string): RequestLog;
19
20
  /** Close a request. Development: `←` line. Production: one structured JSON line. */
20
- export declare function logOutgoing(req: Request, pathname: string, status: number, log: RequestLog): void;
21
+ export declare function logOutgoing(req: Request, pathname: string, status: number, log: RequestLog, ipAddress?: string): void;
21
22
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AA0CA,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEvF;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CASvF;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,GACd,IAAI,CAoBN"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAQD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEvF;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAoBN"}
@@ -3,7 +3,16 @@ import type { MethodDef } from '../types';
3
3
  export interface JwtPayload {
4
4
  [key: string]: unknown;
5
5
  }
6
- export declare function verifyJwt(token: string, secret: string): Promise<JwtPayload>;
6
+ /** Tuning for `verifyJwt`. */
7
+ export interface VerifyJwtOptions {
8
+ /** Clock-skew tolerance for `exp` / `nbf`, in seconds. Default `60`. */
9
+ leewaySeconds?: number;
10
+ /** Required `iss` claim — the token is rejected on mismatch. */
11
+ issuer?: string;
12
+ /** Required `aud` claim — the token is rejected if it does not carry it. */
13
+ audience?: string;
14
+ }
15
+ export declare function verifyJwt(token: string, secret: string, options?: VerifyJwtOptions): Promise<JwtPayload>;
7
16
  export declare function extractToken(req: Request, cookieName?: string): string | null;
8
17
  /**
9
18
  * Per-scope access predicate. `endpoint.scope` selects which rule applies:
@@ -17,6 +26,14 @@ export type AuthRule<TIdentity> = 'public' | 'authenticated' | ((identity: Await
17
26
  export interface AuthHookConfig<TIdentity> {
18
27
  /** Resolve the request identity — cookie / bearer + DB lookup. */
19
28
  resolve: (ctx: RuntimeContext) => Promise<TIdentity | null>;
29
+ /**
30
+ * Resolve identity on a non-HTTP context (a tool call) where there is no
31
+ * `req`. The transport (MCP / agent) has already authenticated the caller;
32
+ * this locates the identity it injected into `ctx` (via `buildMcpServer`'s
33
+ * `context`). Without it, a scoped tool call with no `req` **fails closed**
34
+ * — the scope rule sees no identity and `onAnonymous` rejects the call.
35
+ */
36
+ resolveFromContext?: (ctx: RuntimeContext) => TIdentity | null | Promise<TIdentity | null>;
20
37
  /** Access rule per scope; `endpoint.scope` is the key. */
21
38
  rules: Record<string, AuthRule<TIdentity>>;
22
39
  /** Scope applied when an endpoint declares none. */
@@ -35,6 +52,12 @@ export type AuthHook = (ctx: RuntimeContext, endpoint: MethodDef) => Promise<voi
35
52
  * Identity resolution and the scope vocabulary stay in the project; the
36
53
  * project annotates its `rules` object with `satisfies Record<MyScope, …>` to
37
54
  * keep scope coverage exhaustive.
55
+ *
56
+ * The hook runs on both surfaces: as `createServer`'s `beforeHandle` (HTTP) and
57
+ * as a tool mount's `lifecycle.beforeHandle` (MCP / agent). On HTTP it resolves
58
+ * identity from `ctx.req` via `resolve`; on a tool call — where there is no
59
+ * `req` — it uses `resolveFromContext`. If `resolveFromContext` is omitted, a
60
+ * scoped tool call has no identity and **fails closed** (never silently passes).
38
61
  */
39
62
  export declare function createAuthHook<TIdentity>(config: AuthHookConfig<TIdentity>): AuthHook;
40
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AASD,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA4ClF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7E;AAUD;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,CAAC,SAAS,IAC1B,QAAQ,GACR,eAAe,GACf,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAExF,MAAM,WAAW,cAAc,CAAC,SAAS;IACvC,kEAAkE;IAClE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC5D,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3C,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5E,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC;CAC3B;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnF;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,GAAG,QAAQ,CAuBrF;AAID;;;;GAIG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS;IAC7C,4EAA4E;IAC5E,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACpE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAC5C,MAAM,EAAE,oBAAoB,CAAC,SAAS,CAAC,GACtC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAM7C"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,8BAA8B;AAC9B,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiBD,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,UAAU,CAAC,CAgErB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7E;AAUD;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,CAAC,SAAS,IAC1B,QAAQ,GACR,eAAe,GACf,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAExF,MAAM,WAAW,cAAc,CAAC,SAAS;IACvC,kEAAkE;IAClE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC5D;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC3F,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3C,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5E,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC;CAC3B;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,GAAG,QAAQ,CAgCrF;AAID;;;;GAIG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS;IAC7C,4EAA4E;IAC5E,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACpE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAC5C,MAAM,EAAE,oBAAoB,CAAC,SAAS,CAAC,GACtC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAM7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cookies.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc1E;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACtC;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,aAAkB,GACvB,MAAM,CASR;AAED,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,+EAA+E;IAC/E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,gEAAgE;IAChE,KAAK,IAAI,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAahF"}
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cookies.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB1E;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACtC;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,aAAkB,GACvB,MAAM,CASR;AAED,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,+EAA+E;IAC/E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,gEAAgE;IAChE,KAAK,IAAI,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAahF"}
@@ -4,6 +4,13 @@ export interface CorsConfig {
4
4
  methods?: string;
5
5
  headers?: string;
6
6
  }
7
+ /**
8
+ * Reject an unsafe CORS config at construction. `credentials: true` with a
9
+ * wildcard origin would reflect *any* caller's `Origin` with
10
+ * `Allow-Credentials: true` — every site could make authenticated cross-origin
11
+ * requests. Credentials require an explicit origin allow-list.
12
+ */
13
+ export declare function assertCorsConfig(config: CorsConfig): void;
7
14
  export declare function corsHeaders(config: CorsConfig, requestOrigin?: string | null): Record<string, string>;
8
15
  export declare function corsPreflightResponse(config: CorsConfig, req: Request): Response;
9
16
  //# sourceMappingURL=cors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmCxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,CAKhF"}
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/server/middleware/cors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAOzD;AAoBD,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,CAKhF"}
@@ -2,7 +2,8 @@ import type { ZodType } from 'zod';
2
2
  /** A parsed multipart request — the uploaded `file` and the validated `fields`. */
3
3
  export interface MultipartResult {
4
4
  file: File;
5
- fields: Record<string, unknown>;
5
+ /** Validated when a `fieldsSchema` was given, else the raw decoded fields. */
6
+ fields: unknown;
6
7
  }
7
8
  /**
8
9
  * Parse a `multipart/form-data` request — extract the file at `fileField` and
@@ -1 +1 @@
1
- {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/server/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAGnC,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAKD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAC/B,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CAkC1B"}
1
+ {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/server/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAInC,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,CAAC;IACX,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;CACjB;AA0CD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAC/B,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA6B1B"}
@@ -6,8 +6,13 @@ export interface RateLimitConfig {
6
6
  /**
7
7
  * In-memory token-bucket rate limiter. `check(key, config)` consumes a token
8
8
  * and returns whether the request is allowed; `remaining(key, config)` reports
9
- * the count without consuming. Idle keys are swept on a 60-second timer;
10
- * `destroy()` stops it.
9
+ * the count without consuming. Idle keys are swept on a 60-second timer and the
10
+ * map is capped at `MAX_BUCKETS` (least-recently-used eviction); `destroy()`
11
+ * stops the timer.
12
+ *
13
+ * `config` is per-call — reusing one `key` with two different configs lets
14
+ * whichever call created the bucket fix its `max` / `window`. Key a bucket to
15
+ * one config (one limiter per limit) if that matters.
11
16
  */
12
17
  export declare function createRateLimiter(): {
13
18
  destroy: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/server/rate-limit.ts"],"names":[],"mappings":"AAOA,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AASD;;;;;GAKG;AACH,wBAAgB,iBAAiB;;eAQlB,MAAM,UAAU,eAAe,GAAG,OAAO;mBAiBrC,MAAM,UAAU,eAAe,GAAG,MAAM;EAO1D"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/server/rate-limit.ts"],"names":[],"mappings":"AAOA,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB;;eAQlB,MAAM,UAAU,eAAe,GAAG,OAAO;mBA6BrC,MAAM,UAAU,eAAe,GAAG,MAAM;EAO1D"}