@stacksjs/bun-router 0.0.2 → 0.0.3

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 (128) hide show
  1. package/dist/{chunk-r15a48wc.js → chunk-cjdekj87.js} +536 -98
  2. package/dist/cli.d.ts +1 -0
  3. package/dist/cli.js +2 -2
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +454 -119
  6. package/package.json +6 -8
  7. package/dist/auth.d.ts +0 -77
  8. package/dist/cache/lru-cache.d.ts +0 -88
  9. package/dist/cache/middleware-memoization.d.ts +0 -101
  10. package/dist/cache/route-cache-warmer.d.ts +0 -125
  11. package/dist/cache/sqlite-cache.d.ts +0 -114
  12. package/dist/cache/streaming-cache.d.ts +0 -86
  13. package/dist/cli/colors.d.ts +0 -12
  14. package/dist/cli/index.d.ts +0 -10
  15. package/dist/cli/middleware.d.ts +0 -31
  16. package/dist/cli/openapi.d.ts +0 -17
  17. package/dist/cli/router.d.ts +0 -15
  18. package/dist/cli/routes.d.ts +0 -30
  19. package/dist/cli/utils.d.ts +0 -68
  20. package/dist/config.d.ts +0 -274
  21. package/dist/container/container.d.ts +0 -141
  22. package/dist/container/contextual-binding.d.ts +0 -112
  23. package/dist/container/decorators.d.ts +0 -114
  24. package/dist/container/service-provider.d.ts +0 -221
  25. package/dist/development/hot-reload.d.ts +0 -129
  26. package/dist/development/index.d.ts +0 -144
  27. package/dist/development/performance-profiler.d.ts +0 -152
  28. package/dist/development/route-debugger.d.ts +0 -102
  29. package/dist/development/route-inspector.d.ts +0 -142
  30. package/dist/development/typescript-utilities.d.ts +0 -116
  31. package/dist/docs.d.ts +0 -10
  32. package/dist/errors/circuit-breaker.d.ts +0 -138
  33. package/dist/errors/error-handler.d.ts +0 -57
  34. package/dist/errors/error-reporting.d.ts +0 -135
  35. package/dist/errors/exceptions.d.ts +0 -178
  36. package/dist/errors/graceful-degradation.d.ts +0 -130
  37. package/dist/errors/index.d.ts +0 -6
  38. package/dist/errors/router-errors.d.ts +0 -97
  39. package/dist/file-serving/static-files.d.ts +0 -98
  40. package/dist/middleware/auth.d.ts +0 -34
  41. package/dist/middleware/content_security_policy.d.ts +0 -54
  42. package/dist/middleware/cors.d.ts +0 -5
  43. package/dist/middleware/csrf.d.ts +0 -7
  44. package/dist/middleware/ddos_protection.d.ts +0 -47
  45. package/dist/middleware/file_security.d.ts +0 -23
  46. package/dist/middleware/file_upload.d.ts +0 -41
  47. package/dist/middleware/helmet.d.ts +0 -54
  48. package/dist/middleware/index.d.ts +0 -55
  49. package/dist/middleware/input_validation.d.ts +0 -46
  50. package/dist/middleware/json_body.d.ts +0 -4
  51. package/dist/middleware/performance_alerting.d.ts +0 -88
  52. package/dist/middleware/performance_dashboard.d.ts +0 -97
  53. package/dist/middleware/performance_monitor.d.ts +0 -236
  54. package/dist/middleware/pipeline.d.ts +0 -90
  55. package/dist/middleware/rate_limit.d.ts +0 -33
  56. package/dist/middleware/request_id.d.ts +0 -4
  57. package/dist/middleware/request_signing.d.ts +0 -96
  58. package/dist/middleware/request_tracer.d.ts +0 -76
  59. package/dist/middleware/response_cache.d.ts +0 -90
  60. package/dist/middleware/security.d.ts +0 -70
  61. package/dist/middleware/security_suite.d.ts +0 -46
  62. package/dist/middleware/session.d.ts +0 -7
  63. package/dist/model-binding/index.d.ts +0 -17
  64. package/dist/model-binding/model-middleware.d.ts +0 -80
  65. package/dist/model-binding/model-registry.d.ts +0 -125
  66. package/dist/model-binding.d.ts +0 -123
  67. package/dist/model-resolver-factory.d.ts +0 -31
  68. package/dist/observability/correlation.d.ts +0 -131
  69. package/dist/observability/health-checks.d.ts +0 -129
  70. package/dist/observability/index.d.ts +0 -92
  71. package/dist/observability/integration.d.ts +0 -112
  72. package/dist/observability/metrics.d.ts +0 -135
  73. package/dist/observability/tracing.d.ts +0 -112
  74. package/dist/optimization/bun-utilities.d.ts +0 -106
  75. package/dist/query-builder-integration.d.ts +0 -24
  76. package/dist/request/enhanced-request.d.ts +0 -143
  77. package/dist/request/macros.d.ts +0 -267
  78. package/dist/response/macros.d.ts +0 -207
  79. package/dist/response/response-factory.d.ts +0 -93
  80. package/dist/router/file-based-routing.d.ts +0 -40
  81. package/dist/router/file-streaming.d.ts +0 -6
  82. package/dist/router/fluent-router.d.ts +0 -179
  83. package/dist/router/fluent-routing.d.ts +0 -198
  84. package/dist/router/group-organization.d.ts +0 -5
  85. package/dist/router/handler-resolver.d.ts +0 -13
  86. package/dist/router/http-methods.d.ts +0 -10
  87. package/dist/router/index.d.ts +0 -114
  88. package/dist/router/middleware-integration.d.ts +0 -86
  89. package/dist/router/middleware.d.ts +0 -5
  90. package/dist/router/model-binding.d.ts +0 -7
  91. package/dist/router/optimized-route-matching.d.ts +0 -6
  92. package/dist/router/route-building.d.ts +0 -5
  93. package/dist/router/route-compiler.d.ts +0 -67
  94. package/dist/router/route-matching.d.ts +0 -5
  95. package/dist/router/route-trie.d.ts +0 -69
  96. package/dist/router/router.d.ts +0 -133
  97. package/dist/router/server.d.ts +0 -5
  98. package/dist/router/validation-integration.d.ts +0 -116
  99. package/dist/router/view-rendering.d.ts +0 -5
  100. package/dist/router/websocket.d.ts +0 -5
  101. package/dist/routing/route-caching.d.ts +0 -105
  102. package/dist/routing/route-throttling.d.ts +0 -112
  103. package/dist/routing/subdomain-routing.d.ts +0 -159
  104. package/dist/streaming/index.d.ts +0 -15
  105. package/dist/streaming/sse-handler.d.ts +0 -81
  106. package/dist/streaming/stream-handler.d.ts +0 -81
  107. package/dist/testing/auth-testing.d.ts +0 -107
  108. package/dist/testing/file-upload-testing.d.ts +0 -139
  109. package/dist/testing/index.d.ts +0 -10
  110. package/dist/testing/middleware-testing.d.ts +0 -99
  111. package/dist/testing/model-binding-testing.d.ts +0 -132
  112. package/dist/testing/performance-testing.d.ts +0 -202
  113. package/dist/testing/test-client.d.ts +0 -58
  114. package/dist/testing/test-request.d.ts +0 -43
  115. package/dist/testing/test-response.d.ts +0 -45
  116. package/dist/testing/types.d.ts +0 -206
  117. package/dist/testing/websocket-testing.d.ts +0 -170
  118. package/dist/types/controller-types.d.ts +0 -303
  119. package/dist/types/core.d.ts +0 -526
  120. package/dist/types/middleware-types.d.ts +0 -315
  121. package/dist/types/request-response-augmentation.d.ts +0 -373
  122. package/dist/types/route-inference.d.ts +0 -287
  123. package/dist/types.d.ts +0 -1620
  124. package/dist/utils/index.d.ts +0 -1
  125. package/dist/utils/query-preservation.d.ts +0 -31
  126. package/dist/utils.d.ts +0 -69
  127. package/dist/validation/validator.d.ts +0 -169
  128. package/dist/websocket/clustering.d.ts +0 -114
package/dist/index.js CHANGED
@@ -4,22 +4,27 @@ import {
4
4
  Cors,
5
5
  Csrf,
6
6
  DDoSProtection,
7
+ DatabaseSessionStore,
7
8
  FileSecurity,
9
+ FileSessionStore,
8
10
  FileUpload,
9
11
  Helmet,
10
12
  InMemoryNonceStore,
11
13
  InputValidation,
12
14
  JsonBody,
15
+ MemorySessionStore,
13
16
  PerformanceAlerting,
14
17
  PerformanceDashboard,
15
18
  PerformanceMonitor,
16
19
  RateLimit,
20
+ RedisSessionStore,
17
21
  RequestId,
18
22
  RequestSigning,
19
23
  RequestTracer,
20
24
  Security,
21
25
  SecuritySuite,
22
26
  Session,
27
+ SessionManager,
23
28
  SignatureError,
24
29
  __export,
25
30
  __require,
@@ -30,6 +35,7 @@ import {
30
35
  config,
31
36
  contentSecurityPolicy,
32
37
  cors,
38
+ createSessionStore,
33
39
  csrf,
34
40
  ddosProtection,
35
41
  defaultConfig,
@@ -38,6 +44,7 @@ import {
38
44
  extractBasicAuth,
39
45
  extractBearerToken,
40
46
  fileUpload,
47
+ generateSessionId,
41
48
  getConfig,
42
49
  imageUpload,
43
50
  inputValidation,
@@ -59,7 +66,7 @@ import {
59
66
  signRequest,
60
67
  singleFileUpload,
61
68
  verifySignature
62
- } from "./chunk-r15a48wc.js";
69
+ } from "./chunk-cjdekj87.js";
63
70
 
64
71
  // src/auth.ts
65
72
  function base64UrlEncode(str) {
@@ -3337,7 +3344,7 @@ var MiddlewareFactory = {
3337
3344
  };
3338
3345
  },
3339
3346
  cors: (options = {}) => {
3340
- return async (req, next) => {
3347
+ return async (_req, next) => {
3341
3348
  const response2 = await next();
3342
3349
  if (response2) {
3343
3350
  const headers = new Headers(response2.headers);
@@ -3369,9 +3376,147 @@ var MiddlewareFactory = {
3369
3376
  };
3370
3377
  var globalMiddlewarePipeline = new MiddlewarePipeline;
3371
3378
 
3379
+ // src/router/api-routes.ts
3380
+ import { existsSync, readdirSync, statSync } from "fs";
3381
+ import { basename, extname, join, resolve } from "path";
3382
+ var ROUTE_EXTENSIONS = [".ts", ".js"];
3383
+ var ROUTES_DIRS = ["routes", "src/routes"];
3384
+ var ROOT_ROUTE_FILES = ["web", "index"];
3385
+ function detectRoutesDirectory() {
3386
+ const cwd = process.cwd();
3387
+ for (const dir of ROUTES_DIRS) {
3388
+ const fullPath = resolve(cwd, dir);
3389
+ if (existsSync(fullPath) && statSync(fullPath).isDirectory()) {
3390
+ return fullPath;
3391
+ }
3392
+ }
3393
+ return null;
3394
+ }
3395
+ function discoverRouteFiles(dir, baseDir) {
3396
+ const results = [];
3397
+ if (!existsSync(dir))
3398
+ return results;
3399
+ const entries = readdirSync(dir, { withFileTypes: true });
3400
+ for (const entry of entries) {
3401
+ if (entry.name.startsWith(".") || entry.name.startsWith("_"))
3402
+ continue;
3403
+ const fullPath = join(dir, entry.name);
3404
+ if (entry.isDirectory()) {
3405
+ results.push(...discoverRouteFiles(fullPath, baseDir));
3406
+ } else if (ROUTE_EXTENSIONS.includes(extname(entry.name))) {
3407
+ const relDir = dir === baseDir ? "" : dir.slice(baseDir.length);
3408
+ const name = basename(entry.name, extname(entry.name));
3409
+ const prefix = ROOT_ROUTE_FILES.includes(name) ? relDir || "" : `${relDir}/${name}`;
3410
+ results.push({ filePath: fullPath, prefix });
3411
+ }
3412
+ }
3413
+ return results;
3414
+ }
3415
+ async function loadRouteFile(router, filePath, prefix, verbose) {
3416
+ try {
3417
+ const mod = await import(filePath);
3418
+ let count = 0;
3419
+ const routesBefore = router.routes?.length || 0;
3420
+ if (typeof mod.default === "function") {
3421
+ const prefixedRouter = createPrefixedProxy(router, prefix);
3422
+ await mod.default(prefixedRouter);
3423
+ count = (router.routes?.length || 0) - routesBefore;
3424
+ } else if (Array.isArray(mod.routes)) {
3425
+ for (const route of mod.routes) {
3426
+ const method = (route.method || "GET").toLowerCase();
3427
+ const path = `${prefix}${route.path}`;
3428
+ if (typeof router[method] === "function") {
3429
+ await router[method](path, route.handler);
3430
+ count++;
3431
+ }
3432
+ }
3433
+ }
3434
+ if (verbose && count > 0) {
3435
+ console.log(` ${prefix || "/"} \u2192 ${basename(filePath)} (${count} routes)`);
3436
+ }
3437
+ return count;
3438
+ } catch (error) {
3439
+ console.error(`[bun-router] Failed to load route file ${filePath}:`, error);
3440
+ return 0;
3441
+ }
3442
+ }
3443
+ function createPrefixedProxy(router, prefix) {
3444
+ if (!prefix)
3445
+ return router;
3446
+ const methods = ["get", "post", "put", "patch", "delete", "options", "any"];
3447
+ return new Proxy(router, {
3448
+ get(target, prop) {
3449
+ if (methods.includes(prop)) {
3450
+ return async (path, ...args) => {
3451
+ return target[prop](`${prefix}${path}`, ...args);
3452
+ };
3453
+ }
3454
+ if (prop === "group") {
3455
+ return async (options, callback) => {
3456
+ const nestedPrefix = options.prefix ? `${prefix}${options.prefix}` : prefix;
3457
+ return target.group({ ...options, prefix: nestedPrefix }, callback);
3458
+ };
3459
+ }
3460
+ return target[prop];
3461
+ }
3462
+ });
3463
+ }
3464
+ function registerApiRoutes(RouterClass) {
3465
+ Object.defineProperties(RouterClass.prototype, {
3466
+ _routesDir: {
3467
+ value: null,
3468
+ writable: true,
3469
+ configurable: true
3470
+ },
3471
+ _apiRoutesInitialized: {
3472
+ value: false,
3473
+ writable: true,
3474
+ configurable: true
3475
+ },
3476
+ _initApiRoutes: {
3477
+ async value() {
3478
+ if (this._apiRoutesInitialized)
3479
+ return;
3480
+ const routesDir = this._routesDir || detectRoutesDirectory();
3481
+ if (!routesDir) {
3482
+ this._apiRoutesInitialized = true;
3483
+ return;
3484
+ }
3485
+ const verbose = this.config?.verbose || false;
3486
+ const files = discoverRouteFiles(routesDir, routesDir);
3487
+ if (files.length === 0) {
3488
+ this._apiRoutesInitialized = true;
3489
+ return;
3490
+ }
3491
+ if (verbose) {
3492
+ console.log(`[bun-router] Auto-discovering API routes from ${routesDir}:`);
3493
+ }
3494
+ let totalRoutes = 0;
3495
+ for (const { filePath, prefix } of files) {
3496
+ totalRoutes += await loadRouteFile(this, filePath, prefix, verbose);
3497
+ }
3498
+ if (totalRoutes > 0 && verbose) {
3499
+ console.log(`[bun-router] Registered ${totalRoutes} API routes`);
3500
+ }
3501
+ this._apiRoutesInitialized = true;
3502
+ },
3503
+ writable: true,
3504
+ configurable: true
3505
+ },
3506
+ routesFrom: {
3507
+ value(dir) {
3508
+ this._routesDir = resolve(dir);
3509
+ return this;
3510
+ },
3511
+ writable: true,
3512
+ configurable: true
3513
+ }
3514
+ });
3515
+ }
3516
+
3372
3517
  // src/router/file-based-routing.ts
3373
- import { join, relative, resolve, dirname } from "path";
3374
- import { readdirSync, statSync, existsSync } from "fs";
3518
+ import { join as join2, relative, resolve as resolve2, dirname } from "path";
3519
+ import { readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync2 } from "fs";
3375
3520
 
3376
3521
  // src/utils/query-preservation.ts
3377
3522
  var defaultQueryPreservationConfig = {
@@ -3403,11 +3548,13 @@ function generateQueryPreservationScript(config2) {
3403
3548
  if (pattern.endsWith('*')) {
3404
3549
  return path.startsWith(pattern.slice(0, -1));
3405
3550
  }
3551
+ // eslint-disable-next-line prefer-template
3406
3552
  return path === pattern || path.startsWith(pattern + '/');
3407
3553
  });
3408
3554
  }
3409
3555
  return true;
3410
- } catch (e) { return false; }
3556
+ }
3557
+ catch (e) { return false; }
3411
3558
  }
3412
3559
 
3413
3560
  function getPreservedParams() {
@@ -3518,18 +3665,18 @@ var DEFAULT_EXCLUDES = [
3518
3665
  var DEFAULT_EXTENSIONS = [".stx", ".html"];
3519
3666
  function detectViewsDirectory(cwd = process.cwd()) {
3520
3667
  for (const dir of DEFAULT_VIEW_DIRECTORIES) {
3521
- const fullPath = resolve(cwd, dir);
3522
- if (existsSync(fullPath) && statSync(fullPath).isDirectory()) {
3668
+ const fullPath = resolve2(cwd, dir);
3669
+ if (existsSync2(fullPath) && statSync2(fullPath).isDirectory()) {
3523
3670
  return fullPath;
3524
3671
  }
3525
3672
  }
3526
3673
  return null;
3527
3674
  }
3528
3675
  function hasRoutableFiles(dir, extensions, exclude) {
3529
- if (!existsSync(dir))
3676
+ if (!existsSync2(dir))
3530
3677
  return false;
3531
3678
  try {
3532
- const entries = readdirSync(dir, { withFileTypes: true });
3679
+ const entries = readdirSync2(dir, { withFileTypes: true });
3533
3680
  for (const entry of entries) {
3534
3681
  if (exclude.some((pattern) => entry.name.startsWith(pattern) || entry.name === pattern)) {
3535
3682
  continue;
@@ -3538,7 +3685,7 @@ function hasRoutableFiles(dir, extensions, exclude) {
3538
3685
  return true;
3539
3686
  }
3540
3687
  if (entry.isDirectory()) {
3541
- const subDir = join(dir, entry.name);
3688
+ const subDir = join2(dir, entry.name);
3542
3689
  if (hasRoutableFiles(subDir, extensions, exclude)) {
3543
3690
  return true;
3544
3691
  }
@@ -3569,7 +3716,7 @@ function filePathToRoutePath(filePath, viewsDir, extensions) {
3569
3716
  return `{${param}}`;
3570
3717
  });
3571
3718
  if (!routePath.startsWith("/")) {
3572
- routePath = "/" + routePath;
3719
+ routePath = `/${routePath}`;
3573
3720
  }
3574
3721
  if (routePath === "/") {
3575
3722
  return { routePath: "/", params };
@@ -3578,12 +3725,12 @@ function filePathToRoutePath(filePath, viewsDir, extensions) {
3578
3725
  }
3579
3726
  function discoverRoutes(dir, viewsDir, extensions, exclude) {
3580
3727
  const routes = [];
3581
- if (!existsSync(dir)) {
3728
+ if (!existsSync2(dir)) {
3582
3729
  return routes;
3583
3730
  }
3584
- const entries = readdirSync(dir, { withFileTypes: true });
3731
+ const entries = readdirSync2(dir, { withFileTypes: true });
3585
3732
  for (const entry of entries) {
3586
- const fullPath = join(dir, entry.name);
3733
+ const fullPath = join2(dir, entry.name);
3587
3734
  if (exclude.some((pattern) => entry.name.startsWith(pattern) || entry.name === pattern)) {
3588
3735
  continue;
3589
3736
  }
@@ -3631,18 +3778,18 @@ function discoverRoutes(dir, viewsDir, extensions, exclude) {
3631
3778
  function findPrebuiltView(stxFilePath, viewsDir) {
3632
3779
  const relativePath = relative(viewsDir, stxFilePath);
3633
3780
  const prebuiltLocations = [
3634
- resolve(process.cwd(), "dist/views", relativePath.replace(/\.stx$/, ".html")),
3635
- resolve(process.cwd(), "views", relativePath.replace(/\.stx$/, ".html")),
3636
- resolve("/var/task/views", relativePath.replace(/\.stx$/, ".html"))
3781
+ resolve2(process.cwd(), "dist/views", relativePath.replace(/\.stx$/, ".html")),
3782
+ resolve2(process.cwd(), "views", relativePath.replace(/\.stx$/, ".html")),
3783
+ resolve2("/var/task/views", relativePath.replace(/\.stx$/, ".html"))
3637
3784
  ];
3638
3785
  for (const location of prebuiltLocations) {
3639
- if (existsSync(location)) {
3786
+ if (existsSync2(location)) {
3640
3787
  return location;
3641
3788
  }
3642
3789
  }
3643
3790
  return null;
3644
3791
  }
3645
- async function renderStxFile(filePath, viewsDir, data) {
3792
+ async function renderStxFile(filePath, viewsDir, data, routingConfig) {
3646
3793
  const stxModule = "@stacksjs/stx";
3647
3794
  const stx = await import(stxModule);
3648
3795
  if (!stx.processDirectives || !stx.extractVariables) {
@@ -3662,15 +3809,18 @@ async function renderStxFile(filePath, viewsDir, data) {
3662
3809
  if (scriptContent) {
3663
3810
  await stx.extractVariables(scriptContent, context, filePath);
3664
3811
  }
3812
+ const resolvedComponentsDir = routingConfig?.componentsDir ? resolve2(routingConfig.componentsDir) : join2(viewsDir, "components");
3813
+ const resolvedLayoutsDir = routingConfig?.layoutsDir ? resolve2(routingConfig.layoutsDir) : join2(viewsDir, "layouts");
3814
+ const resolvedPartialsDir = routingConfig?.partialsDir ? resolve2(routingConfig.partialsDir) : join2(viewsDir, "partials");
3665
3815
  const config2 = {
3666
3816
  ...stx.defaultConfig,
3667
- componentsDir: join(viewsDir, "components"),
3668
- layoutsDir: join(viewsDir, "layouts"),
3669
- partialsDir: join(viewsDir, "partials")
3817
+ componentsDir: resolvedComponentsDir,
3818
+ layoutsDir: resolvedLayoutsDir,
3819
+ partialsDir: resolvedPartialsDir
3670
3820
  };
3671
3821
  return stx.processDirectives(templateContent, context, filePath, config2, new Set);
3672
3822
  }
3673
- function createViewHandler(filePath, viewsDir, _config, queryPreservationConfig) {
3823
+ function createViewHandler(filePath, viewsDir, config2, queryPreservationConfig) {
3674
3824
  return async (req) => {
3675
3825
  const url = new URL(req.url);
3676
3826
  const data = {
@@ -3698,7 +3848,7 @@ function createViewHandler(filePath, viewsDir, _config, queryPreservationConfig)
3698
3848
  });
3699
3849
  }
3700
3850
  if (filePath.endsWith(".stx")) {
3701
- let html = await renderStxFile(filePath, viewsDir, data);
3851
+ let html = await renderStxFile(filePath, viewsDir, data, config2);
3702
3852
  html = applyQueryPreservation(html);
3703
3853
  return new Response(html, {
3704
3854
  status: 200,
@@ -3767,7 +3917,7 @@ function registerFileBasedRouting(RouterClass) {
3767
3917
  const handler = createViewHandler(route.filePath, viewsDir, config2, this.config.queryPreservation);
3768
3918
  const existingRoute = this.routes.find((r) => r.path === route.routePath && r.method === "GET");
3769
3919
  if (!existingRoute) {
3770
- await this.get(route.routePath, handler, "web");
3920
+ this.get(route.routePath, handler, "web");
3771
3921
  this._fileBasedRoutes.push(route);
3772
3922
  }
3773
3923
  }
@@ -3779,11 +3929,11 @@ function registerFileBasedRouting(RouterClass) {
3779
3929
  views: {
3780
3930
  value(config2) {
3781
3931
  if (typeof config2 === "string") {
3782
- this._viewsDir = resolve(config2);
3932
+ this._viewsDir = resolve2(config2);
3783
3933
  this._fileRoutingConfig = {};
3784
3934
  } else {
3785
3935
  if (config2.viewsPath) {
3786
- this._viewsDir = resolve(config2.viewsPath);
3936
+ this._viewsDir = resolve2(config2.viewsPath);
3787
3937
  }
3788
3938
  this._fileRoutingConfig = config2;
3789
3939
  }
@@ -3810,7 +3960,7 @@ function registerFileBasedRouting(RouterClass) {
3810
3960
  fileRoutes: {
3811
3961
  async value(viewsPath, options) {
3812
3962
  if (viewsPath) {
3813
- this._viewsDir = resolve(viewsPath);
3963
+ this._viewsDir = resolve2(viewsPath);
3814
3964
  }
3815
3965
  if (options) {
3816
3966
  this._fileRoutingConfig = { ...this._fileRoutingConfig, ...options };
@@ -4136,10 +4286,10 @@ function registerFileStreaming(RouterClass) {
4136
4286
  configurable: true
4137
4287
  },
4138
4288
  health: {
4139
- async value() {
4289
+ value() {
4140
4290
  const path = "/health";
4141
4291
  const fullPath = this.config.apiPrefix ? `${this.config.apiPrefix}${path}` : path;
4142
- await this.get(fullPath, () => {
4292
+ this.get(fullPath, () => {
4143
4293
  return new Response("OK", {
4144
4294
  headers: {
4145
4295
  "Content-Type": "text/plain"
@@ -4395,7 +4545,7 @@ class ModelBindingRegistry {
4395
4545
  }
4396
4546
  }
4397
4547
  var modelRegistry = new ModelBindingRegistry;
4398
- async function resolveModel(paramName, value, modelWrapper, customKey, _context = {}) {
4548
+ async function resolveModel(_paramName, value, modelWrapper, customKey, _context = {}) {
4399
4549
  if (customKey) {
4400
4550
  return await modelWrapper.resolveRouteBinding(value, customKey);
4401
4551
  }
@@ -5917,7 +6067,7 @@ var RouterUtils = {
5917
6067
  var router = new FluentRouter;
5918
6068
 
5919
6069
  // src/utils.ts
5920
- import { join as join2 } from "path";
6070
+ import { join as join3 } from "path";
5921
6071
  function normalizePath(path) {
5922
6072
  let normalizedPath = path.replace(/\/+/g, "/");
5923
6073
  if (!normalizedPath.startsWith("/")) {
@@ -6031,14 +6181,14 @@ async function fileExists(path) {
6031
6181
  }
6032
6182
  async function resolveViewPath(viewName, viewsPath, extensions) {
6033
6183
  if (extensions.some((ext) => viewName.endsWith(ext))) {
6034
- const fullPath = normalizePath(join2(viewsPath, viewName));
6184
+ const fullPath = normalizePath(join3(viewsPath, viewName));
6035
6185
  if (await fileExists(fullPath)) {
6036
6186
  return fullPath;
6037
6187
  }
6038
6188
  return null;
6039
6189
  }
6040
6190
  for (const ext of extensions) {
6041
- const fullPath = normalizePath(join2(viewsPath, `${viewName}${ext}`));
6191
+ const fullPath = normalizePath(join3(viewsPath, `${viewName}${ext}`));
6042
6192
  if (await fileExists(fullPath)) {
6043
6193
  return fullPath;
6044
6194
  }
@@ -6056,19 +6206,19 @@ function processHtmlTemplate(template, data) {
6056
6206
  return result;
6057
6207
  }
6058
6208
  function processConditionals(template, data) {
6059
- return template.replace(/\{\{#if ([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g, (match, condition, content, alternative = "") => {
6209
+ return template.replace(/\{\{#if ([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g, (_match, condition, content, alternative = "") => {
6060
6210
  const conditionTrimmed = condition.trim();
6061
6211
  const value = getNestedValue(data, conditionTrimmed);
6062
6212
  return value ? content : alternative;
6063
6213
  });
6064
6214
  }
6065
6215
  function processLoops(template, data) {
6066
- return template.replace(/\{\{#each ([^}]+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (match, arrayKey, content) => {
6216
+ return template.replace(/\{\{#each ([^}]+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, arrayKey, content) => {
6067
6217
  const array = getNestedValue(data, arrayKey.trim());
6068
6218
  if (!Array.isArray(array))
6069
6219
  return "";
6070
6220
  return array.map((item) => {
6071
- return content.replace(/\{\{@index\}\}/g, String(array.indexOf(item))).replace(/\{\{this\}\}/g, String(item)).replace(/\{\{this\.([^}]+)\}\}/g, (matchStr, prop) => {
6221
+ return content.replace(/\{\{@index\}\}/g, String(array.indexOf(item))).replace(/\{\{this\}\}/g, String(item)).replace(/\{\{this\.([^}]+)\}\}/g, (_matchStr, prop) => {
6072
6222
  const value = item[prop.trim()];
6073
6223
  return value !== undefined ? String(value) : "";
6074
6224
  });
@@ -6085,7 +6235,7 @@ function getNestedValue(obj, path) {
6085
6235
  function registerGroupOrganization(RouterClass) {
6086
6236
  Object.defineProperties(RouterClass.prototype, {
6087
6237
  group: {
6088
- async value(options, callback) {
6238
+ value(options, callback) {
6089
6239
  const previousGroup = this.currentGroup;
6090
6240
  const newGroup = { ...previousGroup };
6091
6241
  if (options.prefix && previousGroup?.prefix) {
@@ -6108,7 +6258,7 @@ function registerGroupOrganization(RouterClass) {
6108
6258
  configurable: true
6109
6259
  },
6110
6260
  name: {
6111
- async value(prefix, callback) {
6261
+ value(prefix, callback) {
6112
6262
  const previousGroup = this.currentGroup || {};
6113
6263
  const newGroup = { ...previousGroup };
6114
6264
  this.currentGroup = newGroup;
@@ -6127,7 +6277,7 @@ function registerGroupOrganization(RouterClass) {
6127
6277
  configurable: true
6128
6278
  },
6129
6279
  controller: {
6130
- async value(controller, callback) {
6280
+ value(controller, callback) {
6131
6281
  const previousGroup = this.currentGroup || {};
6132
6282
  const newGroup = { ...previousGroup, controller };
6133
6283
  this.currentGroup = newGroup;
@@ -6139,7 +6289,7 @@ function registerGroupOrganization(RouterClass) {
6139
6289
  configurable: true
6140
6290
  },
6141
6291
  domain: {
6142
- async value(domain, callback) {
6292
+ value(domain, callback) {
6143
6293
  const previousDomain = this.currentDomain;
6144
6294
  this.currentDomain = domain;
6145
6295
  callback();
@@ -6150,14 +6300,14 @@ function registerGroupOrganization(RouterClass) {
6150
6300
  configurable: true
6151
6301
  },
6152
6302
  prefix: {
6153
- async value(prefix, callback) {
6303
+ value(prefix, callback) {
6154
6304
  return this.group({ prefix }, callback);
6155
6305
  },
6156
6306
  writable: true,
6157
6307
  configurable: true
6158
6308
  },
6159
6309
  resource: {
6160
- async value(name, handler, type = "api") {
6310
+ value(name, handler, type = "api") {
6161
6311
  const pluralName = name.endsWith("s") ? name : `${name}s`;
6162
6312
  const singularName = name.endsWith("s") ? name.slice(0, -1) : name;
6163
6313
  const routes = [
@@ -6169,7 +6319,7 @@ function registerGroupOrganization(RouterClass) {
6169
6319
  { name: "update", method: "PUT", path: `/${pluralName}/{id}`, action: "update" },
6170
6320
  { name: "destroy", method: "DELETE", path: `/${pluralName}/{id}`, action: "destroy" }
6171
6321
  ];
6172
- await this.name(singularName, async () => {
6322
+ this.name(singularName, () => {
6173
6323
  for (const route of routes) {
6174
6324
  let routeHandler;
6175
6325
  if (typeof handler === "string") {
@@ -6183,16 +6333,16 @@ function registerGroupOrganization(RouterClass) {
6183
6333
  }
6184
6334
  switch (route.method) {
6185
6335
  case "GET":
6186
- await this.get(route.path, routeHandler, type, route.name);
6336
+ this.get(route.path, routeHandler, type, route.name);
6187
6337
  break;
6188
6338
  case "POST":
6189
- await this.post(route.path, routeHandler, type, route.name);
6339
+ this.post(route.path, routeHandler, type, route.name);
6190
6340
  break;
6191
6341
  case "PUT":
6192
- await this.put(route.path, routeHandler, type, route.name);
6342
+ this.put(route.path, routeHandler, type, route.name);
6193
6343
  break;
6194
6344
  case "DELETE":
6195
- await this.delete(route.path, routeHandler, type, route.name);
6345
+ this.delete(route.path, routeHandler, type, route.name);
6196
6346
  break;
6197
6347
  }
6198
6348
  }
@@ -6209,7 +6359,7 @@ function registerGroupOrganization(RouterClass) {
6209
6359
  function registerHttpMethods(RouterClass) {
6210
6360
  Object.defineProperties(RouterClass.prototype, {
6211
6361
  addRoute: {
6212
- async value(method, path, handler, type, name, middleware2) {
6362
+ value(method, path, handler, type, name, middleware2) {
6213
6363
  let routePath = path;
6214
6364
  let routeMiddleware = [];
6215
6365
  const routeType = type || "web";
@@ -6223,7 +6373,7 @@ function registerHttpMethods(RouterClass) {
6223
6373
  }
6224
6374
  if (middleware2 && middleware2.length > 0) {
6225
6375
  for (const middlewareItem of middleware2) {
6226
- const resolved = await this.resolveMiddleware(middlewareItem);
6376
+ const resolved = this.resolveMiddleware(middlewareItem);
6227
6377
  if (resolved) {
6228
6378
  routeMiddleware.push(resolved);
6229
6379
  }
@@ -6272,6 +6422,9 @@ function registerHttpMethods(RouterClass) {
6272
6422
  };
6273
6423
  }
6274
6424
  };
6425
+ if (handler instanceof Response) {
6426
+ this.staticResponses.set(routePath, handler);
6427
+ }
6275
6428
  if (domain) {
6276
6429
  if (!this.domains[domain]) {
6277
6430
  this.domains[domain] = [];
@@ -6284,7 +6437,10 @@ function registerHttpMethods(RouterClass) {
6284
6437
  if (!this.staticRoutes.has(method.toUpperCase())) {
6285
6438
  this.staticRoutes.set(method.toUpperCase(), new Map);
6286
6439
  }
6287
- this.staticRoutes.get(method.toUpperCase()).set(routePath, route);
6440
+ const methodMap = this.staticRoutes.get(method.toUpperCase());
6441
+ if (!methodMap.has(routePath)) {
6442
+ methodMap.set(routePath, route);
6443
+ }
6288
6444
  }
6289
6445
  if (name) {
6290
6446
  route.name = name;
@@ -6300,51 +6456,51 @@ function registerHttpMethods(RouterClass) {
6300
6456
  configurable: true
6301
6457
  },
6302
6458
  get: {
6303
- async value(path, handler, type, name, middleware2) {
6459
+ value(path, handler, type, name, middleware2) {
6304
6460
  return this.addRoute("GET", path, handler, type, name, middleware2);
6305
6461
  },
6306
6462
  writable: true,
6307
6463
  configurable: true
6308
6464
  },
6309
6465
  post: {
6310
- async value(path, handler, type, name, middleware2) {
6466
+ value(path, handler, type, name, middleware2) {
6311
6467
  return this.addRoute("POST", path, handler, type, name, middleware2);
6312
6468
  },
6313
6469
  writable: true,
6314
6470
  configurable: true
6315
6471
  },
6316
6472
  put: {
6317
- async value(path, handler, type, name, middleware2) {
6473
+ value(path, handler, type, name, middleware2) {
6318
6474
  return this.addRoute("PUT", path, handler, type, name, middleware2);
6319
6475
  },
6320
6476
  writable: true,
6321
6477
  configurable: true
6322
6478
  },
6323
6479
  patch: {
6324
- async value(path, handler, type, name, middleware2) {
6480
+ value(path, handler, type, name, middleware2) {
6325
6481
  return this.addRoute("PATCH", path, handler, type, name, middleware2);
6326
6482
  },
6327
6483
  writable: true,
6328
6484
  configurable: true
6329
6485
  },
6330
6486
  delete: {
6331
- async value(path, handler, type, name, middleware2) {
6487
+ value(path, handler, type, name, middleware2) {
6332
6488
  return this.addRoute("DELETE", path, handler, type, name, middleware2);
6333
6489
  },
6334
6490
  writable: true,
6335
6491
  configurable: true
6336
6492
  },
6337
6493
  options: {
6338
- async value(path, handler, type, name, middleware2) {
6494
+ value(path, handler, type, name, middleware2) {
6339
6495
  return this.addRoute("OPTIONS", path, handler, type, name, middleware2);
6340
6496
  },
6341
6497
  writable: true,
6342
6498
  configurable: true
6343
6499
  },
6344
6500
  match: {
6345
- async value(methods, path, handler, type, name, middleware2) {
6501
+ value(methods, path, handler, type, name, middleware2) {
6346
6502
  for (const method of methods) {
6347
- await this.addRoute(method, path, handler, type, name, middleware2);
6503
+ this.addRoute(method, path, handler, type, name, middleware2);
6348
6504
  }
6349
6505
  return this;
6350
6506
  },
@@ -6352,7 +6508,7 @@ function registerHttpMethods(RouterClass) {
6352
6508
  configurable: true
6353
6509
  },
6354
6510
  any: {
6355
- async value(path, handler, type, name, middleware2) {
6511
+ value(path, handler, type, name, middleware2) {
6356
6512
  const methods = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
6357
6513
  return this.match(methods, path, handler, type, name, middleware2);
6358
6514
  },
@@ -6415,8 +6571,8 @@ function registerRedirectMethods(RouterClass) {
6415
6571
  configurable: true
6416
6572
  },
6417
6573
  redirectRoute: {
6418
- async value(from, to, status = 302) {
6419
- await this.get(from, (_req) => {
6574
+ value(from, to, status = 302) {
6575
+ this.get(from, (_req) => {
6420
6576
  return this.redirect(to, status);
6421
6577
  });
6422
6578
  return this;
@@ -6425,7 +6581,7 @@ function registerRedirectMethods(RouterClass) {
6425
6581
  configurable: true
6426
6582
  },
6427
6583
  permanentRedirectRoute: {
6428
- async value(from, to) {
6584
+ value(from, to) {
6429
6585
  return this.redirectRoute(from, to, 301);
6430
6586
  },
6431
6587
  writable: true,
@@ -6501,6 +6657,9 @@ function isCallableHandler(handler) {
6501
6657
  return typeof handler === "function" && !handler.prototype?.handle;
6502
6658
  }
6503
6659
  async function resolveHandler(handler, req, config2) {
6660
+ if (handler instanceof Response) {
6661
+ return handler.clone();
6662
+ }
6504
6663
  if (isCallableHandler(handler)) {
6505
6664
  const result = await handler(req);
6506
6665
  return wrapResponse(result);
@@ -6590,9 +6749,9 @@ function createHandlerResolver(config2) {
6590
6749
  function registerMiddlewareHandling(RouterClass) {
6591
6750
  Object.defineProperties(RouterClass.prototype, {
6592
6751
  use: {
6593
- async value(...middleware2) {
6752
+ value(...middleware2) {
6594
6753
  for (const mw of middleware2) {
6595
- const resolvedMiddleware = await this.resolveMiddleware(mw);
6754
+ const resolvedMiddleware = this.resolveMiddleware(mw);
6596
6755
  if (resolvedMiddleware) {
6597
6756
  this.globalMiddleware.push(resolvedMiddleware);
6598
6757
  }
@@ -6603,24 +6762,41 @@ function registerMiddlewareHandling(RouterClass) {
6603
6762
  configurable: true
6604
6763
  },
6605
6764
  resolveMiddleware: {
6606
- async value(middleware2) {
6765
+ value(middleware2) {
6607
6766
  if (typeof middleware2 === "function") {
6608
6767
  return middleware2;
6609
6768
  }
6769
+ if (typeof middleware2 === "object" && middleware2 !== null && "handle" in middleware2 && typeof middleware2.handle === "function") {
6770
+ return (req, next) => {
6771
+ return middleware2.handle(req, next);
6772
+ };
6773
+ }
6610
6774
  if (typeof middleware2 === "string") {
6611
- try {
6612
- const importedMiddleware = await import(`../middleware/${middleware2}.ts`);
6613
- if (importedMiddleware.default && typeof importedMiddleware.default === "function") {
6614
- return importedMiddleware.default;
6775
+ const [name, params] = middleware2.split(":");
6776
+ const factory = this.namedMiddleware?.get(name);
6777
+ if (factory) {
6778
+ return factory(params);
6779
+ }
6780
+ let cached = null;
6781
+ const middlewareName = middleware2;
6782
+ return async (req, next) => {
6783
+ if (!cached) {
6784
+ try {
6785
+ const importedMiddleware = await import(`../middleware/${middlewareName}.ts`);
6786
+ if (importedMiddleware.default && typeof importedMiddleware.default === "function") {
6787
+ cached = importedMiddleware.default;
6788
+ } else if (importedMiddleware.default && typeof importedMiddleware.default.handle === "function") {
6789
+ cached = (r, n) => importedMiddleware.default.handle(r, n);
6790
+ }
6791
+ } catch (error) {
6792
+ console.error(`Failed to load middleware "${middlewareName}":`, error);
6793
+ }
6615
6794
  }
6616
- if (importedMiddleware.default && typeof importedMiddleware.default.handle === "function") {
6617
- return (req, next) => {
6618
- return importedMiddleware.default.handle(req, next);
6619
- };
6795
+ if (cached) {
6796
+ return cached(req, next);
6620
6797
  }
6621
- } catch (error) {
6622
- console.error(`Failed to load middleware "${middleware2}":`, error);
6623
- }
6798
+ return next();
6799
+ };
6624
6800
  }
6625
6801
  return null;
6626
6802
  },
@@ -6694,9 +6870,9 @@ function registerMiddlewareHandling(RouterClass) {
6694
6870
  configurable: true
6695
6871
  },
6696
6872
  applyMiddlewareToRoute: {
6697
- async value(route, middleware2) {
6873
+ value(route, middleware2) {
6698
6874
  for (const mw of middleware2) {
6699
- const resolvedMiddleware = await this.resolveMiddleware(mw);
6875
+ const resolvedMiddleware = this.resolveMiddleware(mw);
6700
6876
  if (resolvedMiddleware) {
6701
6877
  route.middleware.push(resolvedMiddleware);
6702
6878
  }
@@ -6718,7 +6894,7 @@ function registerMiddlewareHandling(RouterClass) {
6718
6894
  configurable: true
6719
6895
  },
6720
6896
  onError: {
6721
- async value(handler) {
6897
+ value(handler) {
6722
6898
  this.errorHandler = handler;
6723
6899
  return this;
6724
6900
  },
@@ -7124,7 +7300,7 @@ class RouteTrie {
7124
7300
  optional: paramPart.endsWith("?")
7125
7301
  });
7126
7302
  } else if (part.includes("{")) {
7127
- const regex = part.replace(/\{([^}:]+)(?::([^}]+))?\}/g, (match, name, pattern) => {
7303
+ const regex = part.replace(/\{([^}:]+)(?::([^}]+))?\}/g, (_match, _name, pattern) => {
7128
7304
  return pattern ? `(${pattern})` : "([^/]+)";
7129
7305
  });
7130
7306
  const paramNames = Array.from(part.matchAll(/\{([^}:]+)(?::([^}]+))?\}/g)).map((match) => match[1].replace("?", ""));
@@ -7401,7 +7577,8 @@ class RouteCompiler {
7401
7577
  }
7402
7578
  }
7403
7579
  convertToURLPattern(path, constraints) {
7404
- let regexPattern = path.replace(/\{([^}:]+)(?::([^}]+))?\}/g, (match, name, pattern) => {
7580
+ let regexPattern = path.replace(/\{([^}:]+)(?::([^}]+))?\}/g, (_match, name, ..._args) => {
7581
+ const pattern = _args[0];
7405
7582
  if (constraints && constraints[name]) {
7406
7583
  return `(?<${name}>${constraints[name]})`;
7407
7584
  } else if (pattern) {
@@ -7947,7 +8124,7 @@ function registerRouteBuilding(RouterClass) {
7947
8124
  const apiRoutes = await import(this.config.apiRoutesPath);
7948
8125
  if (apiRoutes.default && Array.isArray(apiRoutes.default)) {
7949
8126
  for (const route of apiRoutes.default) {
7950
- await this.registerRoute(route, "api");
8127
+ this.registerRoute(route, "api");
7951
8128
  }
7952
8129
  }
7953
8130
  } catch (error) {
@@ -7961,7 +8138,7 @@ function registerRouteBuilding(RouterClass) {
7961
8138
  const webRoutes = await import(this.config.webRoutesPath);
7962
8139
  if (webRoutes.default && Array.isArray(webRoutes.default)) {
7963
8140
  for (const route of webRoutes.default) {
7964
- await this.registerRoute(route, "web");
8141
+ this.registerRoute(route, "web");
7965
8142
  }
7966
8143
  }
7967
8144
  } catch (error) {
@@ -7978,26 +8155,26 @@ function registerRouteBuilding(RouterClass) {
7978
8155
  configurable: true
7979
8156
  },
7980
8157
  registerRoute: {
7981
- async value(route, type) {
8158
+ value(route, type) {
7982
8159
  const { path, method, handler, middleware: middleware2 = [], name } = route;
7983
8160
  switch (method) {
7984
8161
  case "GET":
7985
- await this.get(path, handler, type, name, middleware2);
8162
+ this.get(path, handler, type, name, middleware2);
7986
8163
  break;
7987
8164
  case "POST":
7988
- await this.post(path, handler, type, name, middleware2);
8165
+ this.post(path, handler, type, name, middleware2);
7989
8166
  break;
7990
8167
  case "PUT":
7991
- await this.put(path, handler, type, name, middleware2);
8168
+ this.put(path, handler, type, name, middleware2);
7992
8169
  break;
7993
8170
  case "DELETE":
7994
- await this.delete(path, handler, type, name, middleware2);
8171
+ this.delete(path, handler, type, name, middleware2);
7995
8172
  break;
7996
8173
  case "PATCH":
7997
- await this.patch(path, handler, type, name, middleware2);
8174
+ this.patch(path, handler, type, name, middleware2);
7998
8175
  break;
7999
8176
  case "OPTIONS":
8000
- await this.options(path, handler, type, name, middleware2);
8177
+ this.options(path, handler, type, name, middleware2);
8001
8178
  break;
8002
8179
  default:
8003
8180
  console.warn(`Unsupported HTTP method: ${method}`);
@@ -8260,6 +8437,7 @@ class Router {
8260
8437
  templateCache = new Map;
8261
8438
  routeCache = new Map;
8262
8439
  staticRoutes = new Map;
8440
+ staticResponses = new Map;
8263
8441
  precompiledPatterns = new Map;
8264
8442
  domainPatternCache = new Map;
8265
8443
  routeCompiler = null;
@@ -8351,10 +8529,24 @@ class Router {
8351
8529
  }
8352
8530
  return this;
8353
8531
  }
8532
+ async register(routePath, options) {
8533
+ const callback = async () => {
8534
+ await import(routePath);
8535
+ };
8536
+ if (options?.prefix || options?.middleware && options.middleware.length > 0) {
8537
+ await this.group({
8538
+ prefix: options.prefix,
8539
+ middleware: options.middleware
8540
+ }, callback);
8541
+ } else {
8542
+ await callback();
8543
+ }
8544
+ return this;
8545
+ }
8354
8546
  invalidateCache() {
8355
8547
  this.routeCache.clear();
8356
8548
  }
8357
- async registerRoute(method, path, handler, type, name, middleware2) {
8549
+ registerRoute(method, path, handler, type, name, middleware2) {
8358
8550
  let routePath = path;
8359
8551
  let routeMiddleware = [];
8360
8552
  const routeType = type || "web";
@@ -8368,7 +8560,7 @@ class Router {
8368
8560
  }
8369
8561
  if (middleware2 && middleware2.length > 0) {
8370
8562
  for (const middlewareItem of middleware2) {
8371
- const resolved = await this.resolveMiddleware(middlewareItem);
8563
+ const resolved = this.resolveMiddleware(middlewareItem);
8372
8564
  if (resolved) {
8373
8565
  routeMiddleware.push(resolved);
8374
8566
  }
@@ -8438,7 +8630,7 @@ class Router {
8438
8630
  this.routeCache.clear();
8439
8631
  return this;
8440
8632
  }
8441
- async resolveMiddleware(middleware2) {
8633
+ resolveMiddleware(middleware2) {
8442
8634
  if (typeof middleware2 === "function") {
8443
8635
  return middleware2;
8444
8636
  }
@@ -8449,31 +8641,31 @@ class Router {
8449
8641
  }
8450
8642
  return null;
8451
8643
  }
8452
- async get(path, handler, type, name, middleware2) {
8644
+ get(path, handler, type, name, middleware2) {
8453
8645
  return this.registerRoute("GET", path, handler, type, name, middleware2);
8454
8646
  }
8455
- async post(path, handler, type, name, middleware2) {
8647
+ post(path, handler, type, name, middleware2) {
8456
8648
  return this.registerRoute("POST", path, handler, type, name, middleware2);
8457
8649
  }
8458
- async put(path, handler, type, name, middleware2) {
8650
+ put(path, handler, type, name, middleware2) {
8459
8651
  return this.registerRoute("PUT", path, handler, type, name, middleware2);
8460
8652
  }
8461
- async patch(path, handler, type, name, middleware2) {
8653
+ patch(path, handler, type, name, middleware2) {
8462
8654
  return this.registerRoute("PATCH", path, handler, type, name, middleware2);
8463
8655
  }
8464
- async delete(path, handler, type, name, middleware2) {
8656
+ delete(path, handler, type, name, middleware2) {
8465
8657
  return this.registerRoute("DELETE", path, handler, type, name, middleware2);
8466
8658
  }
8467
- async options(path, handler, type, name, middleware2) {
8659
+ options(path, handler, type, name, middleware2) {
8468
8660
  return this.registerRoute("OPTIONS", path, handler, type, name, middleware2);
8469
8661
  }
8470
- async match(methods, path, handler, type, name, middleware2) {
8662
+ match(methods, path, handler, type, name, middleware2) {
8471
8663
  for (const method of methods) {
8472
- await this.registerRoute(method, path, handler, type, name, middleware2);
8664
+ this.registerRoute(method, path, handler, type, name, middleware2);
8473
8665
  }
8474
8666
  return this;
8475
8667
  }
8476
- async any(path, handler, type, name, middleware2) {
8668
+ any(path, handler, type, name, middleware2) {
8477
8669
  const methods = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
8478
8670
  return this.match(methods, path, handler, type, name, middleware2);
8479
8671
  }
@@ -8508,8 +8700,8 @@ class Router {
8508
8700
  permanentRedirect(url) {
8509
8701
  return this.redirect(url, 301);
8510
8702
  }
8511
- async redirectRoute(from, to, status = 302) {
8512
- await this.get(from, (_req) => {
8703
+ redirectRoute(from, to, status = 302) {
8704
+ this.get(from, (_req) => {
8513
8705
  return this.redirect(to, status);
8514
8706
  });
8515
8707
  return this;
@@ -9082,9 +9274,9 @@ class Router {
9082
9274
  }
9083
9275
  throw new Error(`Invalid action handler: ${typeof handler}`);
9084
9276
  }
9085
- async use(...middleware2) {
9277
+ use(...middleware2) {
9086
9278
  for (const mw of middleware2) {
9087
- const resolvedMiddleware = await this.resolveMiddleware(mw);
9279
+ const resolvedMiddleware = this.resolveMiddleware(mw);
9088
9280
  if (resolvedMiddleware) {
9089
9281
  this.globalMiddleware.push(resolvedMiddleware);
9090
9282
  }
@@ -9238,12 +9430,30 @@ function registerServerHandling(RouterClass) {
9238
9430
  if (this._initFileRoutes) {
9239
9431
  await this._initFileRoutes();
9240
9432
  }
9433
+ if (this._initApiRoutes) {
9434
+ await this._initApiRoutes();
9435
+ }
9241
9436
  this.invalidateCache();
9242
9437
  const serverOptions = {
9243
9438
  idleTimeout: 255,
9244
9439
  ...options,
9245
9440
  fetch: this.handleRequest.bind(this)
9246
9441
  };
9442
+ const staticRouteMap = {};
9443
+ if (this.staticResponses && this.staticResponses.size > 0) {
9444
+ for (const [path, response2] of this.staticResponses) {
9445
+ staticRouteMap[path] = response2;
9446
+ }
9447
+ }
9448
+ if (options.static) {
9449
+ Object.assign(staticRouteMap, options.static);
9450
+ }
9451
+ if (Object.keys(staticRouteMap).length > 0) {
9452
+ serverOptions.static = staticRouteMap;
9453
+ }
9454
+ if (options.development !== undefined) {
9455
+ serverOptions.development = options.development;
9456
+ }
9247
9457
  if (this.wsConfig) {
9248
9458
  serverOptions.websocket = this.wsConfig;
9249
9459
  }
@@ -9483,7 +9693,7 @@ function registerServerHandling(RouterClass) {
9483
9693
  }
9484
9694
 
9485
9695
  // src/router/view-rendering.ts
9486
- import { join as join3 } from "path";
9696
+ import { join as join4 } from "path";
9487
9697
  function registerViewRendering(RouterClass) {
9488
9698
  Object.defineProperties(RouterClass.prototype, {
9489
9699
  renderView: {
@@ -9505,7 +9715,7 @@ function registerViewRendering(RouterClass) {
9505
9715
  let viewContent = await Bun.file(viewPath).text();
9506
9716
  const layoutName = options.layout || viewsConfig.defaultLayout;
9507
9717
  if (layoutName) {
9508
- const layoutPath = await resolveViewPath(join3("layouts", layoutName), viewsConfig.viewsPath, viewsConfig.extensions);
9718
+ const layoutPath = await resolveViewPath(join4("layouts", layoutName), viewsConfig.viewsPath, viewsConfig.extensions);
9509
9719
  if (!layoutPath) {
9510
9720
  throw new Error(`Layout '${layoutName}' not found`);
9511
9721
  }
@@ -9546,7 +9756,7 @@ function registerViewRendering(RouterClass) {
9546
9756
  configurable: true
9547
9757
  },
9548
9758
  view: {
9549
- async value(path, viewOrData, dataOrOptions = {}, optionsOrType = {}, typeOrName = "web", name) {
9759
+ value(path, viewOrData, dataOrOptions = {}, optionsOrType = {}, typeOrName = "web", name) {
9550
9760
  let view;
9551
9761
  let data = {};
9552
9762
  let options = {};
@@ -9614,7 +9824,7 @@ function registerViewRendering(RouterClass) {
9614
9824
  headers
9615
9825
  });
9616
9826
  };
9617
- await this.get(path, handler, type, routeName);
9827
+ this.get(path, handler, type, routeName);
9618
9828
  return this;
9619
9829
  },
9620
9830
  writable: true,
@@ -10790,6 +11000,120 @@ registerServerHandling(Router);
10790
11000
  registerRouteBuilding(Router);
10791
11001
  registerModelBinding(Router);
10792
11002
  registerFileBasedRouting(Router);
11003
+ registerApiRoutes(Router);
11004
+ // src/router/middleware-groups.ts
11005
+ class MiddlewareGroupRegistry {
11006
+ groups = new Map;
11007
+ globalMiddleware = [];
11008
+ middlewarePriority = new Map;
11009
+ define(name, middleware2) {
11010
+ this.groups.set(name, [...middleware2]);
11011
+ return this;
11012
+ }
11013
+ extend(name, middleware2) {
11014
+ const existing = this.groups.get(name) || [];
11015
+ this.groups.set(name, [...existing, ...middleware2]);
11016
+ return this;
11017
+ }
11018
+ prepend(name, middleware2) {
11019
+ const existing = this.groups.get(name) || [];
11020
+ this.groups.set(name, [...middleware2, ...existing]);
11021
+ return this;
11022
+ }
11023
+ get(name) {
11024
+ return this.groups.get(name) || [];
11025
+ }
11026
+ has(name) {
11027
+ return this.groups.has(name);
11028
+ }
11029
+ remove(name) {
11030
+ this.groups.delete(name);
11031
+ return this;
11032
+ }
11033
+ resolve(middleware2) {
11034
+ if (typeof middleware2 === "function") {
11035
+ return [middleware2];
11036
+ }
11037
+ if (this.groups.has(middleware2)) {
11038
+ return this.get(middleware2);
11039
+ }
11040
+ return [middleware2];
11041
+ }
11042
+ resolveAll(middleware2) {
11043
+ const resolved = [];
11044
+ for (const mw of middleware2) {
11045
+ resolved.push(...this.resolve(mw));
11046
+ }
11047
+ return resolved;
11048
+ }
11049
+ pushGlobal(...middleware2) {
11050
+ this.globalMiddleware.push(...middleware2);
11051
+ return this;
11052
+ }
11053
+ prependGlobal(...middleware2) {
11054
+ this.globalMiddleware.unshift(...middleware2);
11055
+ return this;
11056
+ }
11057
+ removeGlobal(middleware2) {
11058
+ this.globalMiddleware = this.globalMiddleware.filter((mw) => typeof mw === "string" ? mw !== middleware2 : true);
11059
+ return this;
11060
+ }
11061
+ getGlobal() {
11062
+ return [...this.globalMiddleware];
11063
+ }
11064
+ setPriority(name, priority) {
11065
+ this.middlewarePriority.set(name, priority);
11066
+ return this;
11067
+ }
11068
+ sortByPriority(middleware2) {
11069
+ return [...middleware2].sort((a, b) => {
11070
+ const nameA = typeof a === "string" ? a.split(":")[0] : "";
11071
+ const nameB = typeof b === "string" ? b.split(":")[0] : "";
11072
+ const priorityA = this.middlewarePriority.get(nameA) ?? 100;
11073
+ const priorityB = this.middlewarePriority.get(nameB) ?? 100;
11074
+ return priorityA - priorityB;
11075
+ });
11076
+ }
11077
+ filter(middleware2, options) {
11078
+ if (options.only && options.only.length > 0) {
11079
+ return middleware2.filter((mw) => {
11080
+ if (typeof mw === "string") {
11081
+ const name = mw.split(":")[0];
11082
+ return options.only.includes(name);
11083
+ }
11084
+ return false;
11085
+ });
11086
+ }
11087
+ if (options.except && options.except.length > 0) {
11088
+ return middleware2.filter((mw) => {
11089
+ if (typeof mw === "string") {
11090
+ const name = mw.split(":")[0];
11091
+ return !options.except.includes(name);
11092
+ }
11093
+ return true;
11094
+ });
11095
+ }
11096
+ return middleware2;
11097
+ }
11098
+ flush() {
11099
+ this.groups.clear();
11100
+ this.globalMiddleware = [];
11101
+ this.middlewarePriority.clear();
11102
+ }
11103
+ }
11104
+ var middlewareGroups = new MiddlewareGroupRegistry;
11105
+ middlewareGroups.define("web", ["session", "csrf", "cors"]);
11106
+ middlewareGroups.define("api", ["throttle:60,1", "cors"]);
11107
+ middlewareGroups.setPriority("session", 10);
11108
+ middlewareGroups.setPriority("cors", 20);
11109
+ middlewareGroups.setPriority("csrf", 30);
11110
+ middlewareGroups.setPriority("auth", 40);
11111
+ middlewareGroups.setPriority("throttle", 50);
11112
+ middlewareGroups.setPriority("role", 60);
11113
+ middlewareGroups.setPriority("permission", 60);
11114
+ middlewareGroups.setPriority("can", 70);
11115
+ middlewareGroups.setPriority("abilities", 70);
11116
+ middlewareGroups.setPriority("verified", 80);
10793
11117
  // src/testing/auth-testing.ts
10794
11118
  import { mock } from "bun:test";
10795
11119
 
@@ -11029,14 +11353,16 @@ class AuthTester {
11029
11353
  return this;
11030
11354
  }
11031
11355
  withApiKey(apiKey, headerName = "X-API-Key") {
11032
- this.request.headers = this.request.headers || new Headers;
11033
- this.request.headers.set(headerName, apiKey);
11356
+ const headers = new Headers(this.request.headers);
11357
+ headers.set(headerName, apiKey);
11358
+ this.request = { ...this.request, headers };
11034
11359
  return this;
11035
11360
  }
11036
11361
  withBasicAuth(username, password) {
11037
11362
  const credentials = btoa(`${username}:${password}`);
11038
- this.request.headers = this.request.headers || new Headers;
11039
- this.request.headers.set("Authorization", `Basic ${credentials}`);
11363
+ const headers = new Headers(this.request.headers);
11364
+ headers.set("Authorization", `Basic ${credentials}`);
11365
+ this.request = { ...this.request, headers };
11040
11366
  return this;
11041
11367
  }
11042
11368
  withAuthCookies(cookies) {
@@ -11667,13 +11993,13 @@ var mockMiddleware = {
11667
11993
  return new Response("Unauthorized", { status: 401 });
11668
11994
  }
11669
11995
  }),
11670
- rateLimit: (shouldLimit = false) => mock3(async (req, next) => {
11996
+ rateLimit: (shouldLimit = false) => mock3(async (_req, next) => {
11671
11997
  if (shouldLimit) {
11672
11998
  return new Response("Too Many Requests", { status: 429 });
11673
11999
  }
11674
12000
  return await next();
11675
12001
  }),
11676
- cors: (origin = "*") => mock3(async (req, next) => {
12002
+ cors: (origin = "*") => mock3(async (_req, next) => {
11677
12003
  const response2 = await next();
11678
12004
  if (response2) {
11679
12005
  response2.headers.set("Access-Control-Allow-Origin", origin);
@@ -11722,7 +12048,7 @@ function spyOnMiddleware(middleware2) {
11722
12048
  return spyOn(middleware2, "call");
11723
12049
  }
11724
12050
  function createMiddlewareSpy() {
11725
- const spy = mock3(async (req, next) => {
12051
+ const spy = mock3(async (_req, next) => {
11726
12052
  return await next();
11727
12053
  });
11728
12054
  return {
@@ -12218,7 +12544,7 @@ class LoadTester {
12218
12544
  requestPromises.push(requestPromise);
12219
12545
  if (this.config.requestsPerSecond) {
12220
12546
  const delay = 1000 / this.config.requestsPerSecond;
12221
- await new Promise((resolve2) => setTimeout(resolve2, delay));
12547
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
12222
12548
  }
12223
12549
  if (requestPromises.length >= this.config.concurrency) {
12224
12550
  await Promise.race(requestPromises);
@@ -13276,6 +13602,7 @@ export {
13276
13602
  multipleFileUpload,
13277
13603
  modelMocks,
13278
13604
  mockMiddleware,
13605
+ middlewareGroups,
13279
13606
  middleware,
13280
13607
  memoryTests,
13281
13608
  matchPath,
@@ -13289,6 +13616,7 @@ export {
13289
13616
  imageUpload,
13290
13617
  globalMiddlewarePipeline,
13291
13618
  getConfig,
13619
+ generateSessionId,
13292
13620
  generateQueryPreservationScript,
13293
13621
  fileUploadScenarios,
13294
13622
  fileUploadMocks,
@@ -13309,6 +13637,7 @@ export {
13309
13637
  createTestClient,
13310
13638
  createSubdomainMiddleware,
13311
13639
  createSessionTester,
13640
+ createSessionStore,
13312
13641
  createRouteCacheMiddleware,
13313
13642
  createRateLimitMiddleware,
13314
13643
  createPerformanceTester,
@@ -13351,6 +13680,7 @@ export {
13351
13680
  SkipConditions,
13352
13681
  SignatureError,
13353
13682
  SessionTester,
13683
+ SessionManager,
13354
13684
  Session,
13355
13685
  SecuritySuite,
13356
13686
  Security,
@@ -13367,6 +13697,7 @@ export {
13367
13697
  RequestTracer,
13368
13698
  RequestSigning,
13369
13699
  RequestId,
13700
+ RedisSessionStore,
13370
13701
  RateLimiter,
13371
13702
  RateLimitUtils,
13372
13703
  RateLimitRegistry,
@@ -13384,8 +13715,10 @@ export {
13384
13715
  MiddlewareTester,
13385
13716
  MiddlewarePipeline,
13386
13717
  MiddlewareHelpers,
13718
+ MiddlewareGroupRegistry,
13387
13719
  MiddlewareFactory,
13388
13720
  MiddlewareChainTester,
13721
+ MemorySessionStore,
13389
13722
  LoadTester,
13390
13723
  JsonBody,
13391
13724
  JWTTester,
@@ -13399,6 +13732,7 @@ export {
13399
13732
  FileValidationTester,
13400
13733
  FileUploadTester,
13401
13734
  FileUpload,
13735
+ FileSessionStore,
13402
13736
  FileSecurity,
13403
13737
  exports_errors as Errors,
13404
13738
  EnhancementPresets,
@@ -13406,6 +13740,7 @@ export {
13406
13740
  DomainGroupBuilder,
13407
13741
  DomainGroup,
13408
13742
  Dependencies,
13743
+ DatabaseSessionStore,
13409
13744
  DDoSProtection,
13410
13745
  Csrf,
13411
13746
  Cors,