@stacksjs/bun-router 0.0.16 → 0.0.18

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 (176) hide show
  1. package/dist/auth.d.ts +22 -8
  2. package/dist/chunk-1ahs68ys.js +18 -0
  3. package/dist/{chunk-0145g1me.js → chunk-cgptvjdf.js} +147 -75
  4. package/dist/chunk-g3ybefhg.js +1923 -0
  5. package/dist/cli.js +3 -2
  6. package/dist/container/container.d.ts +1 -0
  7. package/dist/container/contextual-binding.d.ts +0 -1
  8. package/dist/container/decorators.d.ts +2 -5
  9. package/dist/container/index.d.ts +16 -0
  10. package/dist/container/index.js +322 -0
  11. package/dist/container/service-provider.d.ts +3 -3
  12. package/dist/development/performance-profiler.d.ts +3 -3
  13. package/dist/development/route-debugger.d.ts +1 -1
  14. package/dist/development/route-inspector.d.ts +2 -2
  15. package/dist/file-serving/static-files.d.ts +16 -0
  16. package/dist/index.d.ts +17 -1
  17. package/dist/index.js +1159 -1380
  18. package/dist/middleware/cors.d.ts +9 -0
  19. package/dist/middleware/csrf.d.ts +7 -0
  20. package/dist/middleware/ddos_protection.d.ts +16 -1
  21. package/dist/middleware/rate_limit.d.ts +7 -1
  22. package/dist/middleware/request_tracer.d.ts +15 -9
  23. package/dist/middleware/response_cache.d.ts +2 -1
  24. package/dist/observability/integration.d.ts +1 -1
  25. package/dist/request/context.d.ts +12 -1
  26. package/dist/request/macros.d.ts +40 -2
  27. package/dist/response/macros.d.ts +4 -4
  28. package/dist/router/fluent-routing.d.ts +50 -13
  29. package/dist/router/handler-resolver.d.ts +8 -0
  30. package/dist/router/index.d.ts +9 -7
  31. package/dist/router/route-compiler.d.ts +8 -10
  32. package/dist/router/route-trie.d.ts +7 -1
  33. package/dist/router/router.d.ts +13 -34
  34. package/dist/router/validation-integration.d.ts +10 -4
  35. package/dist/testing/performance-testing.d.ts +2 -2
  36. package/dist/testing/test-client.d.ts +1 -1
  37. package/dist/testing/websocket-testing.d.ts +1 -1
  38. package/dist/types/middleware-types.d.ts +1 -1
  39. package/dist/types/route-inference.d.ts +9 -2
  40. package/dist/types.d.ts +62 -9
  41. package/dist/utils.d.ts +1 -1
  42. package/package.json +12 -3
  43. package/dist/router/fluent-router.d.ts +0 -315
  44. package/src/auth.ts +0 -469
  45. package/src/cache/lru-cache.ts +0 -457
  46. package/src/cache/middleware-memoization.ts +0 -531
  47. package/src/cache/route-cache-warmer.ts +0 -486
  48. package/src/cache/sqlite-cache.ts +0 -783
  49. package/src/cache/streaming-cache.ts +0 -572
  50. package/src/cli/colors.ts +0 -29
  51. package/src/cli/index.ts +0 -287
  52. package/src/cli/middleware.ts +0 -291
  53. package/src/cli/openapi.ts +0 -407
  54. package/src/cli/router.ts +0 -188
  55. package/src/cli/routes.ts +0 -265
  56. package/src/cli/utils.ts +0 -531
  57. package/src/cli.ts +0 -5
  58. package/src/config.ts +0 -322
  59. package/src/container/container.ts +0 -740
  60. package/src/container/contextual-binding.ts +0 -603
  61. package/src/container/decorators.ts +0 -359
  62. package/src/container/service-provider.ts +0 -596
  63. package/src/development/hot-reload.ts +0 -673
  64. package/src/development/index.ts +0 -499
  65. package/src/development/performance-profiler.ts +0 -717
  66. package/src/development/route-debugger.ts +0 -527
  67. package/src/development/route-inspector.ts +0 -749
  68. package/src/development/typescript-utilities.ts +0 -682
  69. package/src/docs.ts +0 -397
  70. package/src/errors/circuit-breaker.ts +0 -732
  71. package/src/errors/error-handler.ts +0 -569
  72. package/src/errors/error-reporting.ts +0 -672
  73. package/src/errors/exceptions.ts +0 -536
  74. package/src/errors/graceful-degradation.ts +0 -621
  75. package/src/errors/index.ts +0 -21
  76. package/src/errors/router-errors.ts +0 -632
  77. package/src/file-serving/static-files.ts +0 -581
  78. package/src/index.ts +0 -14
  79. package/src/middleware/auth.ts +0 -220
  80. package/src/middleware/content_security_policy.ts +0 -215
  81. package/src/middleware/cors.ts +0 -74
  82. package/src/middleware/csrf.ts +0 -118
  83. package/src/middleware/ddos_protection.ts +0 -255
  84. package/src/middleware/file_security.ts +0 -191
  85. package/src/middleware/file_upload.ts +0 -275
  86. package/src/middleware/helmet.ts +0 -268
  87. package/src/middleware/index.ts +0 -117
  88. package/src/middleware/input_validation.ts +0 -449
  89. package/src/middleware/json_body.ts +0 -37
  90. package/src/middleware/performance_alerting.ts +0 -538
  91. package/src/middleware/performance_dashboard.ts +0 -661
  92. package/src/middleware/performance_monitor.ts +0 -943
  93. package/src/middleware/pipeline.ts +0 -489
  94. package/src/middleware/rate_limit.ts +0 -245
  95. package/src/middleware/request_id.ts +0 -36
  96. package/src/middleware/request_signing.ts +0 -636
  97. package/src/middleware/request_tracer.ts +0 -636
  98. package/src/middleware/response_cache.ts +0 -743
  99. package/src/middleware/security.ts +0 -482
  100. package/src/middleware/security_suite.ts +0 -257
  101. package/src/middleware/session.ts +0 -91
  102. package/src/model-binding/index.ts +0 -18
  103. package/src/model-binding/model-middleware.ts +0 -425
  104. package/src/model-binding/model-registry.ts +0 -550
  105. package/src/model-binding.ts +0 -370
  106. package/src/model-resolver-factory.ts +0 -106
  107. package/src/observability/correlation.ts +0 -691
  108. package/src/observability/health-checks.ts +0 -729
  109. package/src/observability/index.ts +0 -184
  110. package/src/observability/integration.ts +0 -548
  111. package/src/observability/metrics.ts +0 -753
  112. package/src/observability/tracing.ts +0 -638
  113. package/src/optimization/bun-utilities.ts +0 -778
  114. package/src/query-builder-integration.ts +0 -137
  115. package/src/request/context.ts +0 -62
  116. package/src/request/enhanced-request.ts +0 -857
  117. package/src/request/macros.ts +0 -688
  118. package/src/response/macros.ts +0 -665
  119. package/src/response/response-factory.ts +0 -596
  120. package/src/router/api-routes.ts +0 -243
  121. package/src/router/file-based-routing.ts +0 -690
  122. package/src/router/file-streaming.ts +0 -383
  123. package/src/router/fluent-router.ts +0 -927
  124. package/src/router/fluent-routing.ts +0 -797
  125. package/src/router/group-organization.ts +0 -213
  126. package/src/router/handler-resolver.ts +0 -291
  127. package/src/router/http-methods.ts +0 -377
  128. package/src/router/index.ts +0 -187
  129. package/src/router/middleware-groups.ts +0 -222
  130. package/src/router/middleware-integration.ts +0 -399
  131. package/src/router/middleware.ts +0 -231
  132. package/src/router/model-binding.ts +0 -215
  133. package/src/router/optimized-route-matching.ts +0 -253
  134. package/src/router/route-building.ts +0 -221
  135. package/src/router/route-compiler.ts +0 -702
  136. package/src/router/route-matching.ts +0 -349
  137. package/src/router/route-trie.ts +0 -464
  138. package/src/router/router.ts +0 -1604
  139. package/src/router/server.ts +0 -462
  140. package/src/router/validation-integration.ts +0 -443
  141. package/src/router/view-rendering.ts +0 -233
  142. package/src/router/websocket.ts +0 -100
  143. package/src/routing/route-caching.ts +0 -402
  144. package/src/routing/route-throttling.ts +0 -469
  145. package/src/routing/subdomain-routing.ts +0 -492
  146. package/src/session/database-store.ts +0 -109
  147. package/src/session/file-store.ts +0 -148
  148. package/src/session/index.ts +0 -244
  149. package/src/session/memory-store.ts +0 -88
  150. package/src/session/redis-store.ts +0 -93
  151. package/src/streaming/index.ts +0 -17
  152. package/src/streaming/sse-handler.ts +0 -482
  153. package/src/streaming/stream-handler.ts +0 -552
  154. package/src/testing/auth-testing.ts +0 -446
  155. package/src/testing/file-upload-testing.ts +0 -543
  156. package/src/testing/index.ts +0 -10
  157. package/src/testing/middleware-testing.ts +0 -322
  158. package/src/testing/model-binding-testing.ts +0 -645
  159. package/src/testing/performance-testing.ts +0 -738
  160. package/src/testing/test-client.ts +0 -310
  161. package/src/testing/test-request.ts +0 -315
  162. package/src/testing/test-response.ts +0 -332
  163. package/src/testing/types.ts +0 -224
  164. package/src/testing/websocket-testing.ts +0 -590
  165. package/src/types/controller-types.ts +0 -385
  166. package/src/types/core.ts +0 -683
  167. package/src/types/middleware-types.ts +0 -419
  168. package/src/types/request-response-augmentation.ts +0 -489
  169. package/src/types/route-inference.ts +0 -357
  170. package/src/types.ts +0 -2067
  171. package/src/url.ts +0 -126
  172. package/src/utils/index.ts +0 -1
  173. package/src/utils/query-preservation.ts +0 -201
  174. package/src/utils.ts +0 -392
  175. package/src/validation/validator.ts +0 -685
  176. package/src/websocket/clustering.ts +0 -762
package/dist/auth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EnhancedRequest, JwtPayload } from './types';
1
+ import type { EnhancedRequest, JwtHeader, JwtPayload } from './types';
2
2
  export interface JwtVerifyOptions {
3
3
  issuer?: string;
4
4
  audience?: string;
@@ -19,9 +19,23 @@ export interface JwtSignOptions {
19
19
  keyid?: string;
20
20
  jwtid?: string;
21
21
  noTimestamp?: boolean;
22
- header?: Record<string, any>;
22
+ header?: Partial<JwtHeader>;
23
23
  encoding?: string;
24
24
  }
25
+ /**
26
+ * Token endpoint response for the OAuth2 authorization-code flow
27
+ * (RFC 6749 §5.1). Providers may include extra fields — they're preserved
28
+ * under the index signature.
29
+ */
30
+ export interface OAuth2TokenResponse {
31
+ access_token: string;
32
+ token_type: string;
33
+ expires_in?: number;
34
+ refresh_token?: string;
35
+ scope?: string;
36
+ id_token?: string;
37
+ [key: string]: string | number | undefined;
38
+ }
25
39
  export interface ApiKeyOptions {
26
40
  source?: 'header' | 'query' | 'cookie';
27
41
  keyName?: string;
@@ -46,17 +60,17 @@ export declare class JWT {
46
60
  /**
47
61
  * Sign payload into a JWT token
48
62
  */
49
- sign(payload: Record<string, any>, options?: JwtSignOptions): string;
63
+ sign(payload: JwtPayload, options?: JwtSignOptions): string;
50
64
  /**
51
65
  * Verify a JWT token and return the decoded payload
52
66
  */
53
- verify(token: string, options?: JwtVerifyOptions): Record<string, any> | null;
67
+ verify(token: string, options?: JwtVerifyOptions): JwtPayload | null;
54
68
  /**
55
69
  * Decode a JWT token without verifying the signature
56
70
  */
57
71
  decode(token: string): {
58
- header: Record<string, any>;
59
- payload: Record<string, any>;
72
+ header: JwtHeader;
73
+ payload: JwtPayload;
60
74
  } | null;
61
75
  /**
62
76
  * Simple signature creation - Note: This is NOT secure for production
@@ -117,11 +131,11 @@ export declare class OAuth2Helper {
117
131
  /**
118
132
  * Exchange authorization code for access token
119
133
  */
120
- exchangeCodeForToken(code: string): Promise<Record<string, any>>;
134
+ exchangeCodeForToken(code: string): Promise<OAuth2TokenResponse>;
121
135
  /**
122
136
  * Refresh an access token using a refresh token
123
137
  */
124
- refreshToken(refreshToken: string): Promise<Record<string, any>>;
138
+ refreshToken(refreshToken: string): Promise<OAuth2TokenResponse>;
125
139
  }
126
140
  /**
127
141
  * Authentication helpers namespace
@@ -0,0 +1,18 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __require = import.meta.require;
17
+
18
+ export { __export, __require };
@@ -1,19 +1,7 @@
1
1
  // @bun
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
- var __require = import.meta.require;
2
+ import {
3
+ __require
4
+ } from "./chunk-1ahs68ys.js";
17
5
 
18
6
  // src/config.ts
19
7
  import process19 from "process";
@@ -40,7 +28,7 @@ import process2 from "process";
40
28
  import { existsSync as existsSync22, mkdirSync, readdirSync, writeFileSync } from "fs";
41
29
  import { dirname, resolve } from "path";
42
30
  import process from "process";
43
- import { Buffer } from "buffer";
31
+ import { Buffer as Buffer2 } from "buffer";
44
32
  import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
45
33
  import { closeSync, createReadStream, createWriteStream, existsSync as existsSync222, fsyncSync, openSync, writeFileSync as writeFileSync2 } from "fs";
46
34
  import { access, constants, mkdir, readdir, rename, stat, unlink, writeFile } from "fs/promises";
@@ -50,7 +38,7 @@ import { pipeline } from "stream/promises";
50
38
  import { createGzip } from "zlib";
51
39
  import process4 from "process";
52
40
  import process3 from "process";
53
- import { Buffer as Buffer2 } from "buffer";
41
+ import { Buffer as Buffer22 } from "buffer";
54
42
  import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
55
43
  import { closeSync as closeSync2, createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync4, fsyncSync as fsyncSync2, openSync as openSync2, writeFileSync as writeFileSync4 } from "fs";
56
44
  import { access as access2, constants as constants2, mkdir as mkdir2, readdir as readdir2, rename as rename2, stat as stat2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
@@ -323,23 +311,23 @@ class PerformanceMonitor {
323
311
  }
324
312
  var globalCache = new ConfigCache;
325
313
  var globalPerformanceMonitor = new PerformanceMonitor;
326
- var __defProp2 = Object.defineProperty;
327
- var __returnValue2 = (v) => v;
328
- function __exportSetter2(name, newValue) {
329
- this[name] = __returnValue2.bind(null, newValue);
314
+ var __defProp = Object.defineProperty;
315
+ var __returnValue = (v) => v;
316
+ function __exportSetter(name, newValue) {
317
+ this[name] = __returnValue.bind(null, newValue);
330
318
  }
331
- var __export2 = (target, all) => {
319
+ var __export = (target, all) => {
332
320
  for (var name in all)
333
- __defProp2(target, name, {
321
+ __defProp(target, name, {
334
322
  get: all[name],
335
323
  enumerable: true,
336
324
  configurable: true,
337
- set: __exportSetter2.bind(all, name)
325
+ set: __exportSetter.bind(all, name)
338
326
  });
339
327
  };
340
328
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
341
329
  var exports_dist = {};
342
- __export2(exports_dist, {
330
+ __export(exports_dist, {
343
331
  withErrorRecovery: () => withErrorRecovery,
344
332
  tryLoadConfig: () => tryLoadConfig3,
345
333
  loadConfigWithResult: () => loadConfigWithResult,
@@ -1028,7 +1016,7 @@ class Logger {
1028
1016
  }
1029
1017
  if (cancelled)
1030
1018
  throw new Error("Operation cancelled: Logger was destroyed");
1031
- const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer.from(data);
1019
+ const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer2.from(data);
1032
1020
  try {
1033
1021
  if (!existsSync222(this.currentLogFile)) {
1034
1022
  await writeFile(this.currentLogFile, "", { mode: 420 });
@@ -1196,13 +1184,13 @@ class Logger {
1196
1184
  const { key } = this.getCurrentKey();
1197
1185
  const iv = randomBytes(16);
1198
1186
  const cipher = createCipheriv("aes-256-gcm", key, iv);
1199
- const encrypted = Buffer.concat([
1187
+ const encrypted = Buffer2.concat([
1200
1188
  cipher.update(data, "utf8"),
1201
1189
  cipher.final()
1202
1190
  ]);
1203
1191
  const authTag = cipher.getAuthTag();
1204
1192
  return {
1205
- encrypted: Buffer.concat([iv, encrypted, authTag]),
1193
+ encrypted: Buffer2.concat([iv, encrypted, authTag]),
1206
1194
  iv
1207
1195
  };
1208
1196
  }
@@ -1211,7 +1199,7 @@ class Logger {
1211
1199
  const gzip = createGzip();
1212
1200
  const chunks = [];
1213
1201
  gzip.on("data", (chunk2) => chunks.push(chunk2));
1214
- gzip.on("end", () => resolve32(Buffer.from(Buffer.concat(chunks))));
1202
+ gzip.on("end", () => resolve32(Buffer2.from(Buffer2.concat(chunks))));
1215
1203
  gzip.on("error", reject);
1216
1204
  gzip.write(data);
1217
1205
  gzip.end();
@@ -1700,13 +1688,13 @@ class Logger {
1700
1688
  throw new Error("No valid encryption key available");
1701
1689
  const key = this.keys.get(this.currentKeyId);
1702
1690
  try {
1703
- const encryptedData = Buffer.isBuffer(data) ? data : Buffer.from(data, "base64");
1691
+ const encryptedData = Buffer2.isBuffer(data) ? data : Buffer2.from(data, "base64");
1704
1692
  const iv = encryptedData.slice(0, 16);
1705
1693
  const authTag = encryptedData.slice(-16);
1706
1694
  const ciphertext = encryptedData.slice(16, -16);
1707
1695
  const decipher = createDecipheriv("aes-256-gcm", key, iv);
1708
1696
  decipher.setAuthTag(authTag);
1709
- const decrypted = Buffer.concat([
1697
+ const decrypted = Buffer2.concat([
1710
1698
  decipher.update(ciphertext),
1711
1699
  decipher.final()
1712
1700
  ]);
@@ -2603,7 +2591,7 @@ class Logger2 {
2603
2591
  }
2604
2592
  if (cancelled)
2605
2593
  throw new Error("Operation cancelled: Logger was destroyed");
2606
- const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer2.from(data);
2594
+ const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer22.from(data);
2607
2595
  try {
2608
2596
  if (!existsSync4(this.currentLogFile)) {
2609
2597
  await writeFile2(this.currentLogFile, "", { mode: 420 });
@@ -2773,12 +2761,12 @@ class Logger2 {
2773
2761
  const { key } = this.getCurrentKey();
2774
2762
  const iv = randomBytes2(16);
2775
2763
  const cipher = createCipheriv2("aes-256-gcm", key, iv);
2776
- const input = Buffer2.isBuffer(data) ? data : Buffer2.from(data, "utf8");
2764
+ const input = Buffer22.isBuffer(data) ? data : Buffer22.from(data, "utf8");
2777
2765
  const part1 = cipher.update(input);
2778
2766
  const part2 = cipher.final();
2779
2767
  const totalCipherLen = part1.length + part2.length;
2780
2768
  const authTag = cipher.getAuthTag();
2781
- const out = Buffer2.allocUnsafe(16 + totalCipherLen + 16);
2769
+ const out = Buffer22.allocUnsafe(16 + totalCipherLen + 16);
2782
2770
  iv.copy(out, 0);
2783
2771
  part1.copy(out, 16);
2784
2772
  part2.copy(out, 16 + part1.length);
@@ -2793,7 +2781,7 @@ class Logger2 {
2793
2781
  const gzip = createGzip2();
2794
2782
  const chunks = [];
2795
2783
  gzip.on("data", (chunk2) => chunks.push(chunk2));
2796
- gzip.on("end", () => resolve52(Buffer2.from(Buffer2.concat(chunks))));
2784
+ gzip.on("end", () => resolve52(Buffer22.from(Buffer22.concat(chunks))));
2797
2785
  gzip.on("error", reject);
2798
2786
  gzip.write(data);
2799
2787
  gzip.end();
@@ -3388,7 +3376,7 @@ class Logger2 {
3388
3376
  throw new Error("No valid encryption key available");
3389
3377
  const key = this.keys.get(this.currentKeyId);
3390
3378
  try {
3391
- const encryptedData = Buffer2.isBuffer(data) ? data : Buffer2.from(data, "base64");
3379
+ const encryptedData = Buffer22.isBuffer(data) ? data : Buffer22.from(data, "base64");
3392
3380
  const iv = encryptedData.subarray(0, 16);
3393
3381
  const authTag = encryptedData.subarray(encryptedData.length - 16);
3394
3382
  const ciphertext = encryptedData.subarray(16, encryptedData.length - 16);
@@ -3397,7 +3385,7 @@ class Logger2 {
3397
3385
  const d1 = decipher.update(ciphertext);
3398
3386
  const d2 = decipher.final();
3399
3387
  const totalLen = d1.length + d2.length;
3400
- const out = Buffer2.allocUnsafe(totalLen);
3388
+ const out = Buffer22.allocUnsafe(totalLen);
3401
3389
  d1.copy(out, 0);
3402
3390
  d2.copy(out, d1.length);
3403
3391
  return out.toString("utf8");
@@ -9138,26 +9126,55 @@ var DEFAULT_CORS_HEADERS = {
9138
9126
  "Access-Control-Allow-Origin": "*",
9139
9127
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
9140
9128
  "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, Accept, Origin",
9141
- "Access-Control-Max-Age": "86400",
9142
- "Access-Control-Allow-Credentials": "true"
9129
+ "Access-Control-Max-Age": "86400"
9143
9130
  };
9144
9131
 
9145
9132
  class Cors {
9146
- getCorsHeaders() {
9133
+ resolveAllowOrigin(configuredOrigin, credentials, requestOrigin) {
9134
+ if (Array.isArray(configuredOrigin)) {
9135
+ if (requestOrigin && configuredOrigin.includes(requestOrigin)) {
9136
+ return { value: requestOrigin, vary: true };
9137
+ }
9138
+ return { value: null, vary: true };
9139
+ }
9140
+ const origin = configuredOrigin || "*";
9141
+ if (origin === "*") {
9142
+ if (credentials) {
9143
+ if (requestOrigin) {
9144
+ return { value: requestOrigin, vary: true };
9145
+ }
9146
+ return { value: null, vary: true };
9147
+ }
9148
+ return { value: "*", vary: false };
9149
+ }
9150
+ return { value: origin, vary: false };
9151
+ }
9152
+ getCorsHeaders(req) {
9147
9153
  const corsConfig = config5.server?.cors;
9154
+ const requestOrigin = req.headers.get("origin");
9148
9155
  if (corsConfig && corsConfig.enabled) {
9149
- return {
9150
- "Access-Control-Allow-Origin": corsConfig.origin || "*",
9156
+ const credentials = Boolean(corsConfig.credentials);
9157
+ const { value: allowOrigin, vary } = this.resolveAllowOrigin(corsConfig.origin, credentials, requestOrigin);
9158
+ const headers = {
9151
9159
  "Access-Control-Allow-Methods": Array.isArray(corsConfig.methods) ? corsConfig.methods.join(", ") : DEFAULT_CORS_HEADERS["Access-Control-Allow-Methods"],
9152
9160
  "Access-Control-Allow-Headers": Array.isArray(corsConfig.allowedHeaders) ? corsConfig.allowedHeaders.join(", ") : DEFAULT_CORS_HEADERS["Access-Control-Allow-Headers"],
9153
- "Access-Control-Max-Age": String(corsConfig.maxAge || 86400),
9154
- "Access-Control-Allow-Credentials": String(corsConfig.credentials || false)
9161
+ "Access-Control-Max-Age": String(corsConfig.maxAge || 86400)
9155
9162
  };
9163
+ if (allowOrigin !== null) {
9164
+ headers["Access-Control-Allow-Origin"] = allowOrigin;
9165
+ }
9166
+ if (credentials && allowOrigin !== null && allowOrigin !== "*") {
9167
+ headers["Access-Control-Allow-Credentials"] = "true";
9168
+ }
9169
+ if (vary) {
9170
+ headers.Vary = "Origin";
9171
+ }
9172
+ return headers;
9156
9173
  }
9157
9174
  return { ...DEFAULT_CORS_HEADERS };
9158
9175
  }
9159
9176
  async handle(req, next) {
9160
- const corsHeaders = this.getCorsHeaders();
9177
+ const corsHeaders = this.getCorsHeaders(req);
9161
9178
  if (req.method === "OPTIONS") {
9162
9179
  return new Response(null, { status: 204, headers: corsHeaders });
9163
9180
  }
@@ -9195,15 +9212,14 @@ class Cors {
9195
9212
  }
9196
9213
 
9197
9214
  // src/middleware/csrf.ts
9198
- import { createHash, randomBytes as randomBytes4 } from "crypto";
9215
+ import { createHash, randomBytes as randomBytes4, timingSafeEqual } from "crypto";
9216
+ var MAX_TOKENS = 1e4;
9217
+ var TOKEN_TTL_MS = 2 * 60 * 60 * 1000;
9218
+
9199
9219
  class Csrf {
9200
9220
  static tokens = new Map;
9201
9221
  async handle(req, next) {
9202
- const csrfConfig = config5.server?.security?.csrf || {};
9203
- if (["GET", "HEAD", "OPTIONS"].includes(req.method)) {
9204
- const response2 = await next();
9205
- return response2 || new Response("Not Found", { status: 404 });
9206
- }
9222
+ const csrfConfig = config5.server?.security?.csrf ?? {};
9207
9223
  const method = req.method.toUpperCase();
9208
9224
  const ignoredMethods = ["GET", "HEAD", "OPTIONS", ...csrfConfig?.ignoreMethods || []];
9209
9225
  if (ignoredMethods.includes(method)) {
@@ -9227,7 +9243,7 @@ class Csrf {
9227
9243
  }
9228
9244
  const newHeaders = new Headers(response2.headers);
9229
9245
  newHeaders.append("Set-Cookie", cookieOptions.join("; "));
9230
- Csrf.tokens.set(token2, token2);
9246
+ Csrf.storeToken(token2);
9231
9247
  return new Response(response2.body, {
9232
9248
  status: response2.status,
9233
9249
  statusText: response2.statusText,
@@ -9239,10 +9255,11 @@ class Csrf {
9239
9255
  const response2 = await next();
9240
9256
  return response2 || new Response("Not Found", { status: 404 });
9241
9257
  }
9242
- const token = req.headers.get("X-CSRF-TOKEN") || req.jsonBody?.csrf_token || req.jsonBody?._token || null;
9258
+ const rawToken = req.headers.get("X-CSRF-TOKEN") || req.jsonBody?.csrf_token || req.jsonBody?._token || null;
9259
+ const token = typeof rawToken === "string" ? rawToken : null;
9243
9260
  const cookies = this.parseCookies(req);
9244
9261
  const cookieToken = cookies[csrfConfig?.cookie?.name || "csrf-token"];
9245
- if (!token || !cookieToken || token !== cookieToken || !Csrf.tokens.has(token)) {
9262
+ if (!token || !cookieToken || !Csrf.safeCompare(token, cookieToken) || !Csrf.isTokenValid(token)) {
9246
9263
  return new Response(JSON.stringify({ error: "CSRF token validation failed" }), {
9247
9264
  status: 403,
9248
9265
  headers: { "Content-Type": "application/json" }
@@ -9251,6 +9268,34 @@ class Csrf {
9251
9268
  const response = await next();
9252
9269
  return response || new Response("Not Found", { status: 404 });
9253
9270
  }
9271
+ static safeCompare(a, b) {
9272
+ const bufA = Buffer.from(a);
9273
+ const bufB = Buffer.from(b);
9274
+ if (bufA.length !== bufB.length) {
9275
+ return false;
9276
+ }
9277
+ return timingSafeEqual(bufA, bufB);
9278
+ }
9279
+ static storeToken(token) {
9280
+ if (Csrf.tokens.size >= MAX_TOKENS) {
9281
+ const oldest = Csrf.tokens.keys().next().value;
9282
+ if (oldest !== undefined) {
9283
+ Csrf.tokens.delete(oldest);
9284
+ }
9285
+ }
9286
+ Csrf.tokens.set(token, Date.now());
9287
+ }
9288
+ static isTokenValid(token) {
9289
+ const issuedAt = Csrf.tokens.get(token);
9290
+ if (issuedAt === undefined) {
9291
+ return false;
9292
+ }
9293
+ if (Date.now() - issuedAt > TOKEN_TTL_MS) {
9294
+ Csrf.tokens.delete(token);
9295
+ return false;
9296
+ }
9297
+ return true;
9298
+ }
9254
9299
  generateToken(secret) {
9255
9300
  const randomString = randomBytes4(16).toString("hex");
9256
9301
  return createHash("sha256").update(`${randomString}${secret}`).digest("hex");
@@ -9259,11 +9304,17 @@ class Csrf {
9259
9304
  const cookieHeader = req.headers.get("cookie");
9260
9305
  if (!cookieHeader)
9261
9306
  return {};
9262
- return cookieHeader.split(";").reduce((cookies, cookie) => {
9263
- const [name, value] = cookie.trim().split("=");
9264
- cookies[name] = value;
9265
- return cookies;
9266
- }, {});
9307
+ const cookies = {};
9308
+ for (const cookie of cookieHeader.split(";")) {
9309
+ const eqIndex = cookie.indexOf("=");
9310
+ if (eqIndex === -1)
9311
+ continue;
9312
+ const name = cookie.slice(0, eqIndex).trim();
9313
+ if (!name)
9314
+ continue;
9315
+ cookies[name] = cookie.slice(eqIndex + 1).trim();
9316
+ }
9317
+ return cookies;
9267
9318
  }
9268
9319
  }
9269
9320
 
@@ -9318,18 +9369,18 @@ import process72 from "process";
9318
9369
  import { existsSync as existsSync62, readdirSync as readdirSync22 } from "fs";
9319
9370
  import { extname as extname2, resolve as resolve62 } from "path";
9320
9371
  import process82 from "process";
9321
- var __defProp3 = Object.defineProperty;
9322
- var __returnValue3 = (v) => v;
9323
- function __exportSetter3(name, newValue) {
9324
- this[name] = __returnValue3.bind(null, newValue);
9372
+ var __defProp2 = Object.defineProperty;
9373
+ var __returnValue2 = (v) => v;
9374
+ function __exportSetter2(name, newValue) {
9375
+ this[name] = __returnValue2.bind(null, newValue);
9325
9376
  }
9326
- var __export3 = (target, all) => {
9377
+ var __export2 = (target, all) => {
9327
9378
  for (var name in all)
9328
- __defProp3(target, name, {
9379
+ __defProp2(target, name, {
9329
9380
  get: all[name],
9330
9381
  enumerable: true,
9331
9382
  configurable: true,
9332
- set: __exportSetter3.bind(all, name)
9383
+ set: __exportSetter2.bind(all, name)
9333
9384
  });
9334
9385
  };
9335
9386
  var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -12880,7 +12931,7 @@ export type ConfigOf = Config
12880
12931
  }
12881
12932
  var init_plugin = () => {};
12882
12933
  var exports_src = {};
12883
- __export3(exports_src, {
12934
+ __export2(exports_src, {
12884
12935
  withErrorRecovery: () => withErrorRecovery3,
12885
12936
  tryLoadConfig: () => tryLoadConfig4,
12886
12937
  loadConfigWithResult: () => loadConfigWithResult2,
@@ -13748,6 +13799,7 @@ class InMemoryNonceStore {
13748
13799
  cleanupInterval = null;
13749
13800
  constructor(cleanupIntervalMs = 60000) {
13750
13801
  this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);
13802
+ this.cleanupInterval.unref?.();
13751
13803
  }
13752
13804
  has(nonce) {
13753
13805
  const expiry = this.nonces.get(nonce);
@@ -14753,6 +14805,7 @@ class DDoSProtection {
14753
14805
  }
14754
14806
  }
14755
14807
  }, this.options.windowSize / 2);
14808
+ this.cleanupInterval.unref?.();
14756
14809
  }
14757
14810
  isWhitelisted(ip) {
14758
14811
  return this.options.whitelistedIPs?.includes(ip) ?? false;
@@ -14763,6 +14816,15 @@ class DDoSProtection {
14763
14816
  getRateLimitInfo(key, now) {
14764
14817
  let info = this.requestStore.get(key);
14765
14818
  if (!info) {
14819
+ if (this.requestStore.size >= 1e5) {
14820
+ let toEvict = Math.ceil(this.requestStore.size / 10);
14821
+ for (const oldestKey of this.requestStore.keys()) {
14822
+ this.requestStore.delete(oldestKey);
14823
+ if (--toEvict <= 0) {
14824
+ break;
14825
+ }
14826
+ }
14827
+ }
14766
14828
  info = {
14767
14829
  count: 0,
14768
14830
  firstRequest: now,
@@ -15350,6 +15412,9 @@ class Helmet {
15350
15412
  }
15351
15413
 
15352
15414
  // src/middleware/input_validation.ts
15415
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/;
15416
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
15417
+
15353
15418
  class InputValidation {
15354
15419
  options;
15355
15420
  constructor(options = {}) {
@@ -15446,8 +15511,7 @@ class InputValidation {
15446
15511
  }
15447
15512
  break;
15448
15513
  case "email": {
15449
- const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/;
15450
- if (typeof value === "string" && !emailRegex.test(value)) {
15514
+ if (typeof value === "string" && !EMAIL_REGEX.test(value)) {
15451
15515
  errors.push({
15452
15516
  field: fieldPath,
15453
15517
  message: "Must be a valid email address",
@@ -15470,8 +15534,7 @@ class InputValidation {
15470
15534
  }
15471
15535
  break;
15472
15536
  case "uuid": {
15473
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
15474
- if (typeof value === "string" && !uuidRegex.test(value)) {
15537
+ if (typeof value === "string" && !UUID_REGEX.test(value)) {
15475
15538
  errors.push({
15476
15539
  field: fieldPath,
15477
15540
  message: "Must be a valid UUID",
@@ -15525,7 +15588,7 @@ class InputValidation {
15525
15588
  rule: "enum"
15526
15589
  });
15527
15590
  }
15528
- if (rule.pattern && typeof value === "string" && !rule.pattern.test(value)) {
15591
+ if (rule.type !== "regex" && rule.pattern && typeof value === "string" && !rule.pattern.test(value)) {
15529
15592
  errors.push({
15530
15593
  field: fieldPath,
15531
15594
  message: "Does not match required pattern",
@@ -15808,6 +15871,7 @@ class PerformanceAlerting {
15808
15871
  this.cleanupOldNotifications();
15809
15872
  this.autoResolveAlerts();
15810
15873
  }, 1e4);
15874
+ this.checkInterval.unref?.();
15811
15875
  }
15812
15876
  evaluateRules() {
15813
15877
  const now = Date.now();
@@ -16692,6 +16756,7 @@ class PerformanceMonitor5 {
16692
16756
  this.cleanupInterval = setInterval(() => {
16693
16757
  this.cleanupOldMetrics();
16694
16758
  }, 60000);
16759
+ this.cleanupInterval.unref?.();
16695
16760
  }
16696
16761
  cleanupOldMetrics() {
16697
16762
  const now = Date.now();
@@ -17194,6 +17259,7 @@ class RequestTracer {
17194
17259
  console.warn("Error exporting spans:", error);
17195
17260
  }
17196
17261
  }, 100);
17262
+ this.exportInterval.unref?.();
17197
17263
  }
17198
17264
  shouldSample() {
17199
17265
  return Math.random() < (this.options.sampleRate || 1);
@@ -17314,11 +17380,17 @@ class RequestTracer {
17314
17380
  }
17315
17381
  }
17316
17382
  async exportSpans() {
17317
- console.warn(`[RequestTracer] Exporting spans, queue size: ${this.exportQueue.length}, active spans: ${this.spans.size}`);
17383
+ if (this.spans.size > 0) {
17384
+ const cutoff = performance.now() - 60000;
17385
+ for (const [spanId, span] of this.spans) {
17386
+ if (span.endTime === undefined && span.startTime < cutoff) {
17387
+ this.spans.delete(spanId);
17388
+ }
17389
+ }
17390
+ }
17318
17391
  if (this.exportQueue.length === 0) {
17319
17392
  const finishedSpans = Array.from(this.spans.values()).filter((span) => span.endTime !== undefined);
17320
17393
  if (finishedSpans.length > 0) {
17321
- console.warn(`[RequestTracer] Found ${finishedSpans.length} finished spans to export`);
17322
17394
  this.exportQueue.push(...finishedSpans);
17323
17395
  for (const span of finishedSpans) {
17324
17396
  this.spans.delete(span.spanId);
@@ -18056,4 +18128,4 @@ var middleware = new Proxy({}, {
18056
18128
  }
18057
18129
  });
18058
18130
 
18059
- export { __export, __require, defaultConfig4 as defaultConfig, getConfig, config5 as config, extractBasicAuth, extractBearerToken, extractApiKey, basicAuth, bearerAuth, jwtAuth, apiKeyAuth, oauth2Auth, Cors, Csrf, JsonBody, RateLimit, rateLimit, RequestId, SignatureError, InMemoryNonceStore, RequestSigning, requestSigning, signRequest, verifySignature, MemorySessionStore, FileSessionStore, RedisSessionStore, DatabaseSessionStore, createSessionStore, SessionManager, generateSessionId, Session, ContentSecurityPolicy, contentSecurityPolicy, DDoSProtection, ddosProtection, FileSecurity, FileUpload, fileUpload, singleFileUpload, multipleFileUpload, imageUpload, documentUpload, Helmet, InputValidation, inputValidation, PerformanceAlerting, performanceAlerting, PerformanceDashboard, performanceDashboard, PerformanceMonitor5 as PerformanceMonitor, performanceMonitor, RequestTracer, requestTracer, Security, security, SecuritySuite, securitySuite, cors, jsonBody, requestId, session, csrf, auth, middleware };
18131
+ export { defaultConfig4 as defaultConfig, getConfig, config5 as config, extractBasicAuth, extractBearerToken, extractApiKey, basicAuth, bearerAuth, jwtAuth, apiKeyAuth, oauth2Auth, Cors, Csrf, JsonBody, RateLimit, rateLimit, RequestId, SignatureError, InMemoryNonceStore, RequestSigning, requestSigning, signRequest, verifySignature, MemorySessionStore, FileSessionStore, RedisSessionStore, DatabaseSessionStore, createSessionStore, SessionManager, generateSessionId, Session, ContentSecurityPolicy, contentSecurityPolicy, DDoSProtection, ddosProtection, FileSecurity, FileUpload, fileUpload, singleFileUpload, multipleFileUpload, imageUpload, documentUpload, Helmet, InputValidation, inputValidation, PerformanceAlerting, performanceAlerting, PerformanceDashboard, performanceDashboard, PerformanceMonitor5 as PerformanceMonitor, performanceMonitor, RequestTracer, requestTracer, Security, security, SecuritySuite, securitySuite, cors, jsonBody, requestId, session, csrf, auth, middleware };