@stacksjs/bun-router 0.0.5 → 0.0.7
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.
- package/dist/auth.d.ts +134 -0
- package/dist/cache/lru-cache.d.ts +139 -0
- package/dist/cache/middleware-memoization.d.ts +151 -0
- package/dist/cache/route-cache-warmer.d.ts +161 -0
- package/dist/cache/sqlite-cache.d.ts +209 -0
- package/dist/cache/streaming-cache.d.ts +132 -0
- package/dist/cli/colors.d.ts +15 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/middleware.d.ts +31 -0
- package/dist/cli/openapi.d.ts +17 -0
- package/dist/cli/router.d.ts +15 -0
- package/dist/cli/routes.d.ts +29 -0
- package/dist/cli/utils.d.ts +74 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/container/container.d.ts +273 -0
- package/dist/container/contextual-binding.d.ts +240 -0
- package/dist/container/decorators.d.ts +141 -0
- package/dist/container/service-provider.d.ts +285 -0
- package/dist/development/hot-reload.d.ts +187 -0
- package/dist/development/index.d.ts +167 -0
- package/dist/development/performance-profiler.d.ts +217 -0
- package/dist/development/route-debugger.d.ts +154 -0
- package/dist/development/route-inspector.d.ts +211 -0
- package/dist/development/typescript-utilities.d.ts +209 -0
- package/dist/docs.d.ts +11 -0
- package/dist/errors/circuit-breaker.d.ts +195 -0
- package/dist/errors/error-handler.d.ts +88 -0
- package/dist/errors/error-reporting.d.ts +144 -0
- package/dist/errors/exceptions.d.ts +184 -0
- package/dist/errors/graceful-degradation.d.ts +154 -0
- package/dist/errors/index.d.ts +9 -0
- package/dist/errors/router-errors.d.ts +110 -0
- package/dist/file-serving/static-files.d.ts +143 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +375 -227
- package/dist/middleware/auth.d.ts +63 -0
- package/dist/middleware/content_security_policy.d.ts +53 -0
- package/dist/middleware/cors.d.ts +5 -0
- package/dist/middleware/csrf.d.ts +7 -0
- package/dist/middleware/ddos_protection.d.ts +39 -0
- package/dist/middleware/file_security.d.ts +26 -0
- package/dist/middleware/file_upload.d.ts +38 -0
- package/dist/middleware/helmet.d.ts +54 -0
- package/dist/middleware/index.d.ts +44 -0
- package/dist/middleware/input_validation.d.ts +45 -0
- package/dist/middleware/json_body.d.ts +4 -0
- package/dist/middleware/performance_alerting.d.ts +87 -0
- package/dist/middleware/performance_dashboard.d.ts +87 -0
- package/dist/middleware/performance_monitor.d.ts +209 -0
- package/dist/middleware/pipeline.d.ts +131 -0
- package/dist/middleware/rate_limit.d.ts +36 -0
- package/dist/middleware/request_id.d.ts +4 -0
- package/dist/middleware/request_signing.d.ts +153 -0
- package/dist/middleware/request_tracer.d.ts +72 -0
- package/dist/middleware/response_cache.d.ts +97 -0
- package/dist/middleware/security.d.ts +69 -0
- package/dist/middleware/security_suite.d.ts +46 -0
- package/dist/middleware/session.d.ts +23 -0
- package/dist/model-binding/index.d.ts +2 -0
- package/dist/model-binding/model-middleware.d.ts +118 -0
- package/dist/model-binding/model-registry.d.ts +164 -0
- package/dist/model-binding.d.ts +185 -0
- package/dist/model-resolver-factory.d.ts +31 -0
- package/dist/observability/correlation.d.ts +187 -0
- package/dist/observability/health-checks.d.ts +186 -0
- package/dist/observability/index.d.ts +60 -0
- package/dist/observability/integration.d.ts +147 -0
- package/dist/observability/metrics.d.ts +184 -0
- package/dist/observability/tracing.d.ts +187 -0
- package/dist/optimization/bun-utilities.d.ts +224 -0
- package/dist/query-builder-integration.d.ts +36 -0
- package/dist/request/context.d.ts +34 -0
- package/dist/request/enhanced-request.d.ts +213 -0
- package/dist/request/macros.d.ts +300 -0
- package/dist/response/macros.d.ts +245 -0
- package/dist/response/response-factory.d.ts +133 -0
- package/dist/router/api-routes.d.ts +5 -0
- package/dist/router/file-based-routing.d.ts +118 -0
- package/dist/router/file-streaming.d.ts +5 -0
- package/dist/router/fluent-router.d.ts +315 -0
- package/dist/router/fluent-routing.d.ts +271 -0
- package/dist/router/group-organization.d.ts +5 -0
- package/dist/router/handler-resolver.d.ts +24 -0
- package/dist/router/http-methods.d.ts +10 -0
- package/dist/router/index.d.ts +113 -0
- package/dist/router/middleware-groups.d.ts +94 -0
- package/dist/router/middleware-integration.d.ts +112 -0
- package/dist/router/middleware.d.ts +5 -0
- package/dist/router/model-binding.d.ts +5 -0
- package/dist/router/optimized-route-matching.d.ts +6 -0
- package/dist/router/route-building.d.ts +5 -0
- package/dist/router/route-compiler.d.ts +153 -0
- package/dist/router/route-matching.d.ts +5 -0
- package/dist/router/route-trie.d.ts +114 -0
- package/dist/router/router.d.ts +276 -0
- package/dist/router/server.d.ts +5 -0
- package/dist/router/validation-integration.d.ts +170 -0
- package/dist/router/view-rendering.d.ts +5 -0
- package/dist/router/websocket.d.ts +5 -0
- package/dist/routing/route-caching.d.ts +129 -0
- package/dist/routing/route-throttling.d.ts +150 -0
- package/dist/routing/subdomain-routing.d.ts +206 -0
- package/dist/session/database-store.d.ts +51 -0
- package/dist/session/file-store.d.ts +22 -0
- package/dist/session/index.d.ts +106 -0
- package/dist/session/memory-store.d.ts +21 -0
- package/dist/session/redis-store.d.ts +31 -0
- package/dist/streaming/index.d.ts +3 -0
- package/dist/streaming/sse-handler.d.ts +138 -0
- package/dist/streaming/stream-handler.d.ts +114 -0
- package/dist/testing/auth-testing.d.ts +156 -0
- package/dist/testing/file-upload-testing.d.ts +190 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/middleware-testing.d.ts +138 -0
- package/dist/testing/model-binding-testing.d.ts +186 -0
- package/dist/testing/performance-testing.d.ts +235 -0
- package/dist/testing/test-client.d.ts +117 -0
- package/dist/testing/test-request.d.ts +85 -0
- package/dist/testing/test-response.d.ts +90 -0
- package/dist/testing/types.d.ts +207 -0
- package/dist/testing/websocket-testing.d.ts +227 -0
- package/dist/types/controller-types.d.ts +208 -0
- package/dist/types/core.d.ts +543 -0
- package/dist/types/middleware-types.d.ts +227 -0
- package/dist/types/request-response-augmentation.d.ts +261 -0
- package/dist/types/route-inference.d.ts +168 -0
- package/dist/types.d.ts +1776 -0
- package/dist/url.d.ts +56 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/query-preservation.d.ts +48 -0
- package/dist/utils.d.ts +69 -0
- package/dist/validation/validator.d.ts +140 -0
- package/dist/websocket/clustering.d.ts +185 -0
- package/package.json +3 -2
- package/src/auth.ts +469 -0
- package/src/cache/lru-cache.ts +457 -0
- package/src/cache/middleware-memoization.ts +531 -0
- package/src/cache/route-cache-warmer.ts +486 -0
- package/src/cache/sqlite-cache.ts +783 -0
- package/src/cache/streaming-cache.ts +572 -0
- package/src/cli/colors.ts +29 -0
- package/src/cli/index.ts +287 -0
- package/src/cli/middleware.ts +291 -0
- package/src/cli/openapi.ts +407 -0
- package/src/cli/router.ts +188 -0
- package/src/cli/routes.ts +265 -0
- package/src/cli/utils.ts +531 -0
- package/src/cli.ts +5 -0
- package/src/config.ts +322 -0
- package/src/container/container.ts +740 -0
- package/src/container/contextual-binding.ts +603 -0
- package/src/container/decorators.ts +359 -0
- package/src/container/service-provider.ts +596 -0
- package/src/development/hot-reload.ts +673 -0
- package/src/development/index.ts +499 -0
- package/src/development/performance-profiler.ts +717 -0
- package/src/development/route-debugger.ts +527 -0
- package/src/development/route-inspector.ts +749 -0
- package/src/development/typescript-utilities.ts +678 -0
- package/src/docs.ts +397 -0
- package/src/errors/circuit-breaker.ts +732 -0
- package/src/errors/error-handler.ts +569 -0
- package/src/errors/error-reporting.ts +672 -0
- package/src/errors/exceptions.ts +536 -0
- package/src/errors/graceful-degradation.ts +621 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/router-errors.ts +632 -0
- package/src/file-serving/static-files.ts +581 -0
- package/src/index.ts +14 -0
- package/src/middleware/auth.ts +219 -0
- package/src/middleware/content_security_policy.ts +215 -0
- package/src/middleware/cors.ts +74 -0
- package/src/middleware/csrf.ts +108 -0
- package/src/middleware/ddos_protection.ts +255 -0
- package/src/middleware/file_security.ts +191 -0
- package/src/middleware/file_upload.ts +264 -0
- package/src/middleware/helmet.ts +268 -0
- package/src/middleware/index.ts +117 -0
- package/src/middleware/input_validation.ts +449 -0
- package/src/middleware/json_body.ts +37 -0
- package/src/middleware/performance_alerting.ts +538 -0
- package/src/middleware/performance_dashboard.ts +661 -0
- package/src/middleware/performance_monitor.ts +943 -0
- package/src/middleware/pipeline.ts +489 -0
- package/src/middleware/rate_limit.ts +245 -0
- package/src/middleware/request_id.ts +36 -0
- package/src/middleware/request_signing.ts +636 -0
- package/src/middleware/request_tracer.ts +636 -0
- package/src/middleware/response_cache.ts +743 -0
- package/src/middleware/security.ts +482 -0
- package/src/middleware/security_suite.ts +257 -0
- package/src/middleware/session.ts +91 -0
- package/src/model-binding/index.ts +18 -0
- package/src/model-binding/model-middleware.ts +425 -0
- package/src/model-binding/model-registry.ts +550 -0
- package/src/model-binding.ts +370 -0
- package/src/model-resolver-factory.ts +106 -0
- package/src/observability/correlation.ts +691 -0
- package/src/observability/health-checks.ts +729 -0
- package/src/observability/index.ts +184 -0
- package/src/observability/integration.ts +548 -0
- package/src/observability/metrics.ts +753 -0
- package/src/observability/tracing.ts +638 -0
- package/src/optimization/bun-utilities.ts +778 -0
- package/src/query-builder-integration.ts +137 -0
- package/src/request/context.ts +62 -0
- package/src/request/enhanced-request.ts +857 -0
- package/src/request/macros.ts +688 -0
- package/src/response/macros.ts +612 -0
- package/src/response/response-factory.ts +588 -0
- package/src/router/api-routes.ts +243 -0
- package/src/router/file-based-routing.ts +670 -0
- package/src/router/file-streaming.ts +372 -0
- package/src/router/fluent-router.ts +927 -0
- package/src/router/fluent-routing.ts +797 -0
- package/src/router/group-organization.ts +213 -0
- package/src/router/handler-resolver.ts +291 -0
- package/src/router/http-methods.ts +377 -0
- package/src/router/index.ts +185 -0
- package/src/router/middleware-groups.ts +222 -0
- package/src/router/middleware-integration.ts +399 -0
- package/src/router/middleware.ts +231 -0
- package/src/router/model-binding.ts +215 -0
- package/src/router/optimized-route-matching.ts +253 -0
- package/src/router/route-building.ts +212 -0
- package/src/router/route-compiler.ts +702 -0
- package/src/router/route-matching.ts +349 -0
- package/src/router/route-trie.ts +464 -0
- package/src/router/router.ts +1524 -0
- package/src/router/server.ts +429 -0
- package/src/router/validation-integration.ts +443 -0
- package/src/router/view-rendering.ts +233 -0
- package/src/router/websocket.ts +100 -0
- package/src/routing/route-caching.ts +402 -0
- package/src/routing/route-throttling.ts +469 -0
- package/src/routing/subdomain-routing.ts +492 -0
- package/src/session/database-store.ts +109 -0
- package/src/session/file-store.ts +148 -0
- package/src/session/index.ts +244 -0
- package/src/session/memory-store.ts +88 -0
- package/src/session/redis-store.ts +93 -0
- package/src/streaming/index.ts +17 -0
- package/src/streaming/sse-handler.ts +482 -0
- package/src/streaming/stream-handler.ts +552 -0
- package/src/testing/auth-testing.ts +446 -0
- package/src/testing/file-upload-testing.ts +543 -0
- package/src/testing/index.ts +10 -0
- package/src/testing/middleware-testing.ts +322 -0
- package/src/testing/model-binding-testing.ts +645 -0
- package/src/testing/performance-testing.ts +738 -0
- package/src/testing/test-client.ts +310 -0
- package/src/testing/test-request.ts +315 -0
- package/src/testing/test-response.ts +332 -0
- package/src/testing/types.ts +224 -0
- package/src/testing/websocket-testing.ts +590 -0
- package/src/types/controller-types.ts +385 -0
- package/src/types/core.ts +683 -0
- package/src/types/middleware-types.ts +419 -0
- package/src/types/request-response-augmentation.ts +489 -0
- package/src/types/route-inference.ts +357 -0
- package/src/types.ts +2049 -0
- package/src/url.ts +126 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/query-preservation.ts +201 -0
- package/src/utils.ts +327 -0
- package/src/validation/validator.ts +685 -0
- package/src/websocket/clustering.ts +762 -0
package/dist/index.js
CHANGED
|
@@ -2763,6 +2763,27 @@ var RouterErrorFactory = {
|
|
|
2763
2763
|
handlerResolution: (ref, reason, context) => new HandlerResolutionException(ref, reason, context),
|
|
2764
2764
|
modelBinding: (model, param, value, reason, context) => new ModelBindingException(model, param, value, reason, context)
|
|
2765
2765
|
};
|
|
2766
|
+
// src/request/context.ts
|
|
2767
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
2768
|
+
var storage = new AsyncLocalStorage;
|
|
2769
|
+
function runWithRequest(initial, fn) {
|
|
2770
|
+
return storage.run({ current: initial }, fn);
|
|
2771
|
+
}
|
|
2772
|
+
function setCurrentRequest(req) {
|
|
2773
|
+
const store = storage.getStore();
|
|
2774
|
+
if (store)
|
|
2775
|
+
store.current = req;
|
|
2776
|
+
}
|
|
2777
|
+
function getCurrentRequest() {
|
|
2778
|
+
return storage.getStore()?.current ?? undefined;
|
|
2779
|
+
}
|
|
2780
|
+
function request() {
|
|
2781
|
+
const req = getCurrentRequest();
|
|
2782
|
+
if (!req) {
|
|
2783
|
+
throw new Error("request() called outside a request scope. It can only be invoked from within a route handler or middleware.");
|
|
2784
|
+
}
|
|
2785
|
+
return req;
|
|
2786
|
+
}
|
|
2766
2787
|
// src/response/response-factory.ts
|
|
2767
2788
|
var response = {
|
|
2768
2789
|
json: (data, options = {}) => {
|
|
@@ -2858,8 +2879,8 @@ var response = {
|
|
|
2858
2879
|
redirectTemporary: (url) => {
|
|
2859
2880
|
return response.redirect(url, 302);
|
|
2860
2881
|
},
|
|
2861
|
-
back: (
|
|
2862
|
-
const referer =
|
|
2882
|
+
back: (request2, fallback = "/") => {
|
|
2883
|
+
const referer = request2.headers.get("referer") || fallback;
|
|
2863
2884
|
return response.redirect(referer);
|
|
2864
2885
|
},
|
|
2865
2886
|
view: (html, status = 200, headers = {}) => {
|
|
@@ -3104,7 +3125,7 @@ class MiddlewarePipeline {
|
|
|
3104
3125
|
}
|
|
3105
3126
|
this.compiledPipelines.set(routeKey, compiled);
|
|
3106
3127
|
}
|
|
3107
|
-
async execute(routeKey,
|
|
3128
|
+
async execute(routeKey, request2, finalHandler) {
|
|
3108
3129
|
const startTime = performance.now();
|
|
3109
3130
|
this.stats.totalExecutions++;
|
|
3110
3131
|
const pipeline = this.compiledPipelines.get(routeKey);
|
|
@@ -3114,7 +3135,7 @@ class MiddlewarePipeline {
|
|
|
3114
3135
|
}
|
|
3115
3136
|
this.stats.cacheHits++;
|
|
3116
3137
|
const context = {
|
|
3117
|
-
request,
|
|
3138
|
+
request: request2,
|
|
3118
3139
|
dependencies: new Map,
|
|
3119
3140
|
metadata: {}
|
|
3120
3141
|
};
|
|
@@ -3129,7 +3150,7 @@ class MiddlewarePipeline {
|
|
|
3129
3150
|
this.stats.skippedMiddleware++;
|
|
3130
3151
|
return await next();
|
|
3131
3152
|
}
|
|
3132
|
-
const result2 = await middleware2.handler(
|
|
3153
|
+
const result2 = await middleware2.handler(request2, next);
|
|
3133
3154
|
if (result2 instanceof Response && middleware2.canShortCircuit) {
|
|
3134
3155
|
this.stats.shortCircuits++;
|
|
3135
3156
|
return result2;
|
|
@@ -4193,12 +4214,12 @@ class StreamHandler {
|
|
|
4193
4214
|
}
|
|
4194
4215
|
}
|
|
4195
4216
|
class FileStreamHandler {
|
|
4196
|
-
static async streamFile(filePath,
|
|
4217
|
+
static async streamFile(filePath, request2, options = {}) {
|
|
4197
4218
|
const { contentType, enableRanges = true, chunkSize: _chunkSize = 64 * 1024 } = options;
|
|
4198
4219
|
try {
|
|
4199
4220
|
const file = Bun.file(filePath);
|
|
4200
4221
|
const fileSize = file.size;
|
|
4201
|
-
const range = enableRanges ?
|
|
4222
|
+
const range = enableRanges ? request2.headers.get("range") : null;
|
|
4202
4223
|
if (range && enableRanges) {
|
|
4203
4224
|
return FileStreamHandler.handleRangeRequest(file, range, contentType);
|
|
4204
4225
|
}
|
|
@@ -4272,8 +4293,8 @@ class FileStreamHandler {
|
|
|
4272
4293
|
function registerFileStreaming(RouterClass) {
|
|
4273
4294
|
Object.defineProperties(RouterClass.prototype, {
|
|
4274
4295
|
streamFile: {
|
|
4275
|
-
value(filePath,
|
|
4276
|
-
return FileStreamHandler.streamFile(filePath,
|
|
4296
|
+
value(filePath, request2, options) {
|
|
4297
|
+
return FileStreamHandler.streamFile(filePath, request2, options);
|
|
4277
4298
|
},
|
|
4278
4299
|
writable: true,
|
|
4279
4300
|
configurable: true
|
|
@@ -5627,6 +5648,60 @@ var SubdomainPatterns = {
|
|
|
5627
5648
|
environment: (domain) => `{env}.${domain}`
|
|
5628
5649
|
};
|
|
5629
5650
|
|
|
5651
|
+
// src/url.ts
|
|
5652
|
+
import process3 from "process";
|
|
5653
|
+
var namedRouteRegistry = new Map;
|
|
5654
|
+
function registerNamedRoute(name, path) {
|
|
5655
|
+
namedRouteRegistry.set(name, path);
|
|
5656
|
+
}
|
|
5657
|
+
function getNamedRoutePath(name) {
|
|
5658
|
+
return namedRouteRegistry.get(name);
|
|
5659
|
+
}
|
|
5660
|
+
function getNamedRoutes() {
|
|
5661
|
+
return new Map(namedRouteRegistry);
|
|
5662
|
+
}
|
|
5663
|
+
function clearNamedRoutes() {
|
|
5664
|
+
namedRouteRegistry.clear();
|
|
5665
|
+
}
|
|
5666
|
+
function url(name, params = {}, options = {}) {
|
|
5667
|
+
const path = namedRouteRegistry.get(name);
|
|
5668
|
+
if (!path) {
|
|
5669
|
+
const known = [...namedRouteRegistry.keys()].sort().join(", ") || "(none registered)";
|
|
5670
|
+
throw new Error(`Named route '${name}' is not defined. Known routes: ${known}`);
|
|
5671
|
+
}
|
|
5672
|
+
const consumed = new Set;
|
|
5673
|
+
let resolved = path;
|
|
5674
|
+
for (const [key, value] of Object.entries(params)) {
|
|
5675
|
+
const required = `{${key}}`;
|
|
5676
|
+
const optional = `{${key}?}`;
|
|
5677
|
+
const encoded = encodeURIComponent(String(value));
|
|
5678
|
+
if (resolved.includes(required)) {
|
|
5679
|
+
resolved = resolved.replaceAll(required, encoded);
|
|
5680
|
+
consumed.add(key);
|
|
5681
|
+
} else if (resolved.includes(optional)) {
|
|
5682
|
+
resolved = resolved.replaceAll(optional, encoded);
|
|
5683
|
+
consumed.add(key);
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
resolved = resolved.replace(/\/\{[^}]+\?\}/g, "");
|
|
5687
|
+
const missing = resolved.match(/\{([^}?]+)\}/g);
|
|
5688
|
+
if (missing && missing.length > 0)
|
|
5689
|
+
throw new Error(`Missing required params for route '${name}': ${missing.join(", ")}`);
|
|
5690
|
+
const leftover = Object.entries(params).filter(([k]) => !consumed.has(k));
|
|
5691
|
+
if (leftover.length > 0) {
|
|
5692
|
+
const qs = new URLSearchParams;
|
|
5693
|
+
for (const [k, v] of leftover)
|
|
5694
|
+
qs.set(k, String(v));
|
|
5695
|
+
resolved += `?${qs.toString()}`;
|
|
5696
|
+
}
|
|
5697
|
+
if (options.absolute) {
|
|
5698
|
+
const base = (options.base ?? process3.env.APP_URL ?? "http://localhost").replace(/\/$/, "");
|
|
5699
|
+
const prefixed = base.startsWith("http") ? base : `https://${base}`;
|
|
5700
|
+
return `${prefixed}${resolved.startsWith("/") ? resolved : `/${resolved}`}`;
|
|
5701
|
+
}
|
|
5702
|
+
return resolved;
|
|
5703
|
+
}
|
|
5704
|
+
|
|
5630
5705
|
// src/router/fluent-routing.ts
|
|
5631
5706
|
class FluentRouteBuilder {
|
|
5632
5707
|
method;
|
|
@@ -5880,6 +5955,8 @@ class FluentRouter {
|
|
|
5880
5955
|
register(builder) {
|
|
5881
5956
|
const route = builder.build();
|
|
5882
5957
|
this.routes.push(route);
|
|
5958
|
+
if (route.name)
|
|
5959
|
+
registerNamedRoute(route.name, route.path);
|
|
5883
5960
|
return this;
|
|
5884
5961
|
}
|
|
5885
5962
|
cached(tags = [], config2) {
|
|
@@ -5920,6 +5997,8 @@ class FluentRouter {
|
|
|
5920
5997
|
this.subdomainRouter.addDomainGroup(domainGroup);
|
|
5921
5998
|
} else {
|
|
5922
5999
|
this.routes.push(groupedRoute);
|
|
6000
|
+
if (groupedRoute.name)
|
|
6001
|
+
registerNamedRoute(groupedRoute.name, groupedRoute.path);
|
|
5923
6002
|
}
|
|
5924
6003
|
}
|
|
5925
6004
|
return this;
|
|
@@ -5965,45 +6044,45 @@ class FluentRouter {
|
|
|
5965
6044
|
getRoutes() {
|
|
5966
6045
|
return [...this.routes, ...this.subdomainRouter.getAllRoutes()];
|
|
5967
6046
|
}
|
|
5968
|
-
async handle(
|
|
5969
|
-
const _url = new URL(
|
|
5970
|
-
const
|
|
5971
|
-
const domain =
|
|
6047
|
+
async handle(request2) {
|
|
6048
|
+
const _url = new URL(request2.url);
|
|
6049
|
+
const url2 = new URL(request2.url);
|
|
6050
|
+
const domain = url2.hostname;
|
|
5972
6051
|
const match = this.subdomainRouter.findDomainGroup(domain);
|
|
5973
6052
|
if (match) {
|
|
5974
|
-
const enhancedReq =
|
|
6053
|
+
const enhancedReq = request2;
|
|
5975
6054
|
enhancedReq.domainParams = match.parameters;
|
|
5976
6055
|
for (const route of match.group.getRoutes()) {
|
|
5977
|
-
if (this.matchesRoute(route,
|
|
6056
|
+
if (this.matchesRoute(route, request2)) {
|
|
5978
6057
|
return await this.executeRoute(route, enhancedReq);
|
|
5979
6058
|
}
|
|
5980
6059
|
}
|
|
5981
6060
|
}
|
|
5982
6061
|
for (const route of this.routes) {
|
|
5983
|
-
if (this.matchesRoute(route,
|
|
5984
|
-
return await this.executeRoute(route,
|
|
6062
|
+
if (this.matchesRoute(route, request2)) {
|
|
6063
|
+
return await this.executeRoute(route, request2);
|
|
5985
6064
|
}
|
|
5986
6065
|
}
|
|
5987
6066
|
return null;
|
|
5988
6067
|
}
|
|
5989
|
-
matchesRoute(route,
|
|
5990
|
-
if (route.method !==
|
|
6068
|
+
matchesRoute(route, request2) {
|
|
6069
|
+
if (route.method !== request2.method) {
|
|
5991
6070
|
return false;
|
|
5992
6071
|
}
|
|
5993
|
-
const
|
|
6072
|
+
const url2 = new URL(request2.url);
|
|
5994
6073
|
const routePattern = route.path.replace(/\{([^:}]+):?([^}]*)\}/g, "([^/]+)");
|
|
5995
6074
|
const regex = new RegExp(`^${routePattern}$`);
|
|
5996
|
-
return regex.test(
|
|
6075
|
+
return regex.test(url2.pathname);
|
|
5997
6076
|
}
|
|
5998
|
-
async executeRoute(route,
|
|
6077
|
+
async executeRoute(route, request2) {
|
|
5999
6078
|
const allMiddleware = [...this.globalMiddleware, ...route.middleware];
|
|
6000
6079
|
let index = 0;
|
|
6001
6080
|
const next = async () => {
|
|
6002
6081
|
if (index < allMiddleware.length) {
|
|
6003
6082
|
const middleware2 = allMiddleware[index++];
|
|
6004
|
-
return await middleware2(
|
|
6083
|
+
return await middleware2(request2, next);
|
|
6005
6084
|
}
|
|
6006
|
-
return await route.handler(
|
|
6085
|
+
return await route.handler(request2);
|
|
6007
6086
|
};
|
|
6008
6087
|
return await next();
|
|
6009
6088
|
}
|
|
@@ -6041,20 +6120,20 @@ var RouteFactory = {
|
|
|
6041
6120
|
};
|
|
6042
6121
|
var RouterUtils = {
|
|
6043
6122
|
route: (name, params = {}, query = {}) => {
|
|
6044
|
-
let
|
|
6123
|
+
let url2 = `/${name}`;
|
|
6045
6124
|
for (const [key, value] of Object.entries(params)) {
|
|
6046
|
-
|
|
6125
|
+
url2 = url2.replace(`{${key}}`, value);
|
|
6047
6126
|
}
|
|
6048
6127
|
const queryString = new URLSearchParams(query).toString();
|
|
6049
6128
|
if (queryString) {
|
|
6050
|
-
|
|
6129
|
+
url2 += `?${queryString}`;
|
|
6051
6130
|
}
|
|
6052
|
-
return
|
|
6131
|
+
return url2;
|
|
6053
6132
|
},
|
|
6054
|
-
redirect: (
|
|
6133
|
+
redirect: (url2, status = 302) => {
|
|
6055
6134
|
return new Response(null, {
|
|
6056
6135
|
status,
|
|
6057
|
-
headers: { Location:
|
|
6136
|
+
headers: { Location: url2 }
|
|
6058
6137
|
});
|
|
6059
6138
|
},
|
|
6060
6139
|
json: (data, status = 200) => {
|
|
@@ -6408,10 +6487,10 @@ function registerHttpMethods(RouterClass) {
|
|
|
6408
6487
|
route.constraints = constraints;
|
|
6409
6488
|
}
|
|
6410
6489
|
route.pattern = {
|
|
6411
|
-
exec: (
|
|
6490
|
+
exec: (url2) => {
|
|
6412
6491
|
const params = {};
|
|
6413
6492
|
const constraintsRecord = route.constraints && !Array.isArray(route.constraints) ? route.constraints : undefined;
|
|
6414
|
-
const isMatch = matchPath(routePath,
|
|
6493
|
+
const isMatch = matchPath(routePath, url2.pathname, params, constraintsRecord);
|
|
6415
6494
|
if (!isMatch) {
|
|
6416
6495
|
return null;
|
|
6417
6496
|
}
|
|
@@ -6445,6 +6524,7 @@ function registerHttpMethods(RouterClass) {
|
|
|
6445
6524
|
if (name) {
|
|
6446
6525
|
route.name = name;
|
|
6447
6526
|
this.namedRoutes.set(name, route);
|
|
6527
|
+
registerNamedRoute(name, route.path);
|
|
6448
6528
|
}
|
|
6449
6529
|
if (this.addRouteToCompiler) {
|
|
6450
6530
|
this.addRouteToCompiler(route);
|
|
@@ -6529,12 +6609,12 @@ function registerHttpMethods(RouterClass) {
|
|
|
6529
6609
|
if (!route) {
|
|
6530
6610
|
throw new Error(`Route with name "${name}" not found`);
|
|
6531
6611
|
}
|
|
6532
|
-
let
|
|
6612
|
+
let url2 = route.path;
|
|
6533
6613
|
for (const [param, value] of Object.entries(params)) {
|
|
6534
|
-
|
|
6535
|
-
|
|
6614
|
+
url2 = url2.replace(`{${param}}`, encodeURIComponent(value));
|
|
6615
|
+
url2 = url2.replace(`{${param}?}`, encodeURIComponent(value));
|
|
6536
6616
|
}
|
|
6537
|
-
return
|
|
6617
|
+
return url2;
|
|
6538
6618
|
},
|
|
6539
6619
|
writable: true,
|
|
6540
6620
|
configurable: true
|
|
@@ -6552,9 +6632,9 @@ function registerHttpMethods(RouterClass) {
|
|
|
6552
6632
|
function registerRedirectMethods(RouterClass) {
|
|
6553
6633
|
Object.defineProperties(RouterClass.prototype, {
|
|
6554
6634
|
redirect: {
|
|
6555
|
-
value(
|
|
6635
|
+
value(url2, status = 302) {
|
|
6556
6636
|
const headers = new Headers;
|
|
6557
|
-
headers.set("Location",
|
|
6637
|
+
headers.set("Location", url2);
|
|
6558
6638
|
return new Response(null, {
|
|
6559
6639
|
status,
|
|
6560
6640
|
headers
|
|
@@ -6564,8 +6644,8 @@ function registerRedirectMethods(RouterClass) {
|
|
|
6564
6644
|
configurable: true
|
|
6565
6645
|
},
|
|
6566
6646
|
permanentRedirect: {
|
|
6567
|
-
value(
|
|
6568
|
-
return this.redirect(
|
|
6647
|
+
value(url2) {
|
|
6648
|
+
return this.redirect(url2, 301);
|
|
6569
6649
|
},
|
|
6570
6650
|
writable: true,
|
|
6571
6651
|
configurable: true
|
|
@@ -7560,8 +7640,8 @@ class RouteCompiler {
|
|
|
7560
7640
|
}
|
|
7561
7641
|
const pattern = this.convertToURLPattern(route.path, route.constraints && !Array.isArray(route.constraints) ? route.constraints : undefined);
|
|
7562
7642
|
const urlPatternAdapter = {
|
|
7563
|
-
exec: (
|
|
7564
|
-
const pathname =
|
|
7643
|
+
exec: (url2) => {
|
|
7644
|
+
const pathname = url2.pathname;
|
|
7565
7645
|
const result = pattern.exec(pathname);
|
|
7566
7646
|
if (!result)
|
|
7567
7647
|
return null;
|
|
@@ -7920,13 +8000,13 @@ function registerOptimizedRouteMatching(RouterClass) {
|
|
|
7920
8000
|
},
|
|
7921
8001
|
fallbackMatchRoute: {
|
|
7922
8002
|
value(path, method, domain) {
|
|
7923
|
-
const
|
|
7924
|
-
const cacheKey = `${domain || ""}:${method}:${
|
|
8003
|
+
const url2 = new URL(path, "http://localhost");
|
|
8004
|
+
const cacheKey = `${domain || ""}:${method}:${url2.pathname}`;
|
|
7925
8005
|
if (this.routeCache.has(cacheKey)) {
|
|
7926
8006
|
return this.routeCache.get(cacheKey);
|
|
7927
8007
|
}
|
|
7928
8008
|
if (this.staticRoutes.has(method)) {
|
|
7929
|
-
const staticRoute = this.staticRoutes.get(method).get(
|
|
8009
|
+
const staticRoute = this.staticRoutes.get(method).get(url2.pathname);
|
|
7930
8010
|
if (staticRoute && (!domain || !staticRoute.domain || staticRoute.domain === domain)) {
|
|
7931
8011
|
const result = {
|
|
7932
8012
|
route: staticRoute,
|
|
@@ -7939,7 +8019,7 @@ function registerOptimizedRouteMatching(RouterClass) {
|
|
|
7939
8019
|
const potentialRoutes = domain && this.domains[domain] ? this.domains[domain] : this.routes;
|
|
7940
8020
|
const methodRoutes = potentialRoutes.filter((route) => route.method === method);
|
|
7941
8021
|
for (const route of methodRoutes) {
|
|
7942
|
-
if (route.path ===
|
|
8022
|
+
if (route.path === url2.pathname) {
|
|
7943
8023
|
const result = {
|
|
7944
8024
|
route,
|
|
7945
8025
|
params: {}
|
|
@@ -7950,7 +8030,7 @@ function registerOptimizedRouteMatching(RouterClass) {
|
|
|
7950
8030
|
}
|
|
7951
8031
|
for (const route of methodRoutes) {
|
|
7952
8032
|
if (route.pattern) {
|
|
7953
|
-
const match = route.pattern.exec(
|
|
8033
|
+
const match = route.pattern.exec(url2);
|
|
7954
8034
|
if (match) {
|
|
7955
8035
|
const result = {
|
|
7956
8036
|
route,
|
|
@@ -8075,10 +8155,10 @@ function registerRouteBuilding(RouterClass) {
|
|
|
8075
8155
|
} catch {}
|
|
8076
8156
|
}
|
|
8077
8157
|
bunRoutes[path] = async (req) => {
|
|
8078
|
-
const
|
|
8158
|
+
const url2 = new URL(req.url);
|
|
8079
8159
|
const params = {};
|
|
8080
8160
|
const constraintsRecord = route.constraints && !Array.isArray(route.constraints) ? route.constraints : undefined;
|
|
8081
|
-
matchPath(path,
|
|
8161
|
+
matchPath(path, url2.pathname, params, constraintsRecord);
|
|
8082
8162
|
const enhancedReq = this.enhanceRequest(req, params);
|
|
8083
8163
|
const middlewareResult = await this.runMiddleware(enhancedReq, [...this.globalMiddleware, ...route.middleware]);
|
|
8084
8164
|
if (middlewareResult) {
|
|
@@ -8092,10 +8172,10 @@ function registerRouteBuilding(RouterClass) {
|
|
|
8092
8172
|
for (const route of routes) {
|
|
8093
8173
|
const method = route.method;
|
|
8094
8174
|
methodHandlers[method] = async (req) => {
|
|
8095
|
-
const
|
|
8175
|
+
const url2 = new URL(req.url);
|
|
8096
8176
|
const params = {};
|
|
8097
8177
|
const constraintsRecord = route.constraints && !Array.isArray(route.constraints) ? route.constraints : undefined;
|
|
8098
|
-
matchPath(path,
|
|
8178
|
+
matchPath(path, url2.pathname, params, constraintsRecord);
|
|
8099
8179
|
const enhancedReq = this.enhanceRequest(req, params);
|
|
8100
8180
|
const middlewareResult = await this.runMiddleware(enhancedReq, [...this.globalMiddleware, ...route.middleware]);
|
|
8101
8181
|
if (middlewareResult) {
|
|
@@ -8191,13 +8271,13 @@ function registerRouteMatching(RouterClass) {
|
|
|
8191
8271
|
Object.defineProperties(RouterClass.prototype, {
|
|
8192
8272
|
matchRoute: {
|
|
8193
8273
|
value(path, method, domain) {
|
|
8194
|
-
const
|
|
8195
|
-
const cacheKey = `${domain || ""}:${method}:${
|
|
8274
|
+
const url2 = new URL(path, "http://localhost");
|
|
8275
|
+
const cacheKey = `${domain || ""}:${method}:${url2.pathname}`;
|
|
8196
8276
|
if (this.routeCache.has(cacheKey)) {
|
|
8197
8277
|
return this.routeCache.get(cacheKey);
|
|
8198
8278
|
}
|
|
8199
8279
|
if (this.staticRoutes.has(method)) {
|
|
8200
|
-
const staticRoute = this.staticRoutes.get(method).get(
|
|
8280
|
+
const staticRoute = this.staticRoutes.get(method).get(url2.pathname);
|
|
8201
8281
|
if (staticRoute && (!domain || !staticRoute.domain || staticRoute.domain === domain)) {
|
|
8202
8282
|
const result = {
|
|
8203
8283
|
route: staticRoute,
|
|
@@ -8210,7 +8290,7 @@ function registerRouteMatching(RouterClass) {
|
|
|
8210
8290
|
const potentialRoutes = domain && this.domains[domain] ? this.domains[domain] : this.routes;
|
|
8211
8291
|
const methodRoutes = potentialRoutes.filter((route) => route.method === method);
|
|
8212
8292
|
for (const route of methodRoutes) {
|
|
8213
|
-
if (route.path ===
|
|
8293
|
+
if (route.path === url2.pathname) {
|
|
8214
8294
|
const result = {
|
|
8215
8295
|
route,
|
|
8216
8296
|
params: {}
|
|
@@ -8221,7 +8301,7 @@ function registerRouteMatching(RouterClass) {
|
|
|
8221
8301
|
}
|
|
8222
8302
|
for (const route of methodRoutes) {
|
|
8223
8303
|
if (route.pattern) {
|
|
8224
|
-
const match = route.pattern.exec(
|
|
8304
|
+
const match = route.pattern.exec(url2);
|
|
8225
8305
|
if (match) {
|
|
8226
8306
|
const result = {
|
|
8227
8307
|
route,
|
|
@@ -8236,11 +8316,11 @@ function registerRouteMatching(RouterClass) {
|
|
|
8236
8316
|
const wildcardRoutes = this.domains[domain].filter((route) => route.method === method && route.path.endsWith("*"));
|
|
8237
8317
|
for (const route of wildcardRoutes) {
|
|
8238
8318
|
const basePath = route.path.slice(0, -1);
|
|
8239
|
-
if (
|
|
8319
|
+
if (url2.pathname.startsWith(basePath)) {
|
|
8240
8320
|
const result = {
|
|
8241
8321
|
route,
|
|
8242
8322
|
params: {
|
|
8243
|
-
wildcard:
|
|
8323
|
+
wildcard: url2.pathname.slice(basePath.length)
|
|
8244
8324
|
}
|
|
8245
8325
|
};
|
|
8246
8326
|
this.routeCache.set(cacheKey, result);
|
|
@@ -8251,11 +8331,11 @@ function registerRouteMatching(RouterClass) {
|
|
|
8251
8331
|
const globalWildcardRoutes = this.routes.filter((route) => route.method === method && route.path.endsWith("*") && (!domain || !route.domain));
|
|
8252
8332
|
for (const route of globalWildcardRoutes) {
|
|
8253
8333
|
const basePath = route.path.slice(0, -1);
|
|
8254
|
-
if (
|
|
8334
|
+
if (url2.pathname.startsWith(basePath)) {
|
|
8255
8335
|
const result = {
|
|
8256
8336
|
route,
|
|
8257
8337
|
params: {
|
|
8258
|
-
wildcard:
|
|
8338
|
+
wildcard: url2.pathname.slice(basePath.length)
|
|
8259
8339
|
}
|
|
8260
8340
|
};
|
|
8261
8341
|
this.routeCache.set(cacheKey, result);
|
|
@@ -8356,9 +8436,9 @@ function registerRouteMatching(RouterClass) {
|
|
|
8356
8436
|
const routePath = lastRoute.path;
|
|
8357
8437
|
const constraintsRecord = lastRoute.constraints && !Array.isArray(lastRoute.constraints) ? lastRoute.constraints : undefined;
|
|
8358
8438
|
lastRoute.pattern = {
|
|
8359
|
-
exec: (
|
|
8439
|
+
exec: (url2) => {
|
|
8360
8440
|
const params2 = {};
|
|
8361
|
-
const isMatch = matchPath(routePath,
|
|
8441
|
+
const isMatch = matchPath(routePath, url2.pathname, params2, constraintsRecord);
|
|
8362
8442
|
if (!isMatch) {
|
|
8363
8443
|
return null;
|
|
8364
8444
|
}
|
|
@@ -8595,10 +8675,10 @@ class Router {
|
|
|
8595
8675
|
route.constraints = constraints;
|
|
8596
8676
|
}
|
|
8597
8677
|
route.pattern = {
|
|
8598
|
-
exec: (
|
|
8678
|
+
exec: (url2) => {
|
|
8599
8679
|
const params = {};
|
|
8600
8680
|
const constraintsRecord = route.constraints && !Array.isArray(route.constraints) ? route.constraints : undefined;
|
|
8601
|
-
const isMatch = matchPath(routePath,
|
|
8681
|
+
const isMatch = matchPath(routePath, url2.pathname, params, constraintsRecord);
|
|
8602
8682
|
if (!isMatch) {
|
|
8603
8683
|
return null;
|
|
8604
8684
|
}
|
|
@@ -8626,6 +8706,7 @@ class Router {
|
|
|
8626
8706
|
if (name) {
|
|
8627
8707
|
route.name = name;
|
|
8628
8708
|
this.namedRoutes.set(name, route);
|
|
8709
|
+
registerNamedRoute(name, route.path);
|
|
8629
8710
|
}
|
|
8630
8711
|
this.routeCache.clear();
|
|
8631
8712
|
return this;
|
|
@@ -8678,27 +8759,27 @@ class Router {
|
|
|
8678
8759
|
if (!route) {
|
|
8679
8760
|
throw new Error(`Route with name "${name}" not found`);
|
|
8680
8761
|
}
|
|
8681
|
-
let
|
|
8762
|
+
let url2 = route.path;
|
|
8682
8763
|
for (const [param, value] of Object.entries(params)) {
|
|
8683
|
-
|
|
8684
|
-
|
|
8764
|
+
url2 = url2.replace(`{${param}}`, encodeURIComponent(value));
|
|
8765
|
+
url2 = url2.replace(`{${param}?}`, encodeURIComponent(value));
|
|
8685
8766
|
}
|
|
8686
|
-
return
|
|
8767
|
+
return url2;
|
|
8687
8768
|
}
|
|
8688
8769
|
onError(handler) {
|
|
8689
8770
|
this.errorHandler = handler;
|
|
8690
8771
|
return this;
|
|
8691
8772
|
}
|
|
8692
|
-
redirect(
|
|
8773
|
+
redirect(url2, status = 302) {
|
|
8693
8774
|
const headers = new Headers;
|
|
8694
|
-
headers.set("Location",
|
|
8775
|
+
headers.set("Location", url2);
|
|
8695
8776
|
return new Response(null, {
|
|
8696
8777
|
status,
|
|
8697
8778
|
headers
|
|
8698
8779
|
});
|
|
8699
8780
|
}
|
|
8700
|
-
permanentRedirect(
|
|
8701
|
-
return this.redirect(
|
|
8781
|
+
permanentRedirect(url2) {
|
|
8782
|
+
return this.redirect(url2, 301);
|
|
8702
8783
|
}
|
|
8703
8784
|
redirectRoute(from, to, status = 302) {
|
|
8704
8785
|
this.get(from, (_req) => {
|
|
@@ -8725,13 +8806,13 @@ class Router {
|
|
|
8725
8806
|
}
|
|
8726
8807
|
async handleRequest(req) {
|
|
8727
8808
|
try {
|
|
8728
|
-
const
|
|
8809
|
+
const url2 = new URL(req.url);
|
|
8729
8810
|
if (this.config.verbose) {
|
|
8730
|
-
console.log(`${req.method} ${
|
|
8811
|
+
console.log(`${req.method} ${url2.pathname}`);
|
|
8731
8812
|
}
|
|
8732
8813
|
if (req.method === "OPTIONS") {
|
|
8733
|
-
const hostname2 =
|
|
8734
|
-
const optionsMatch = this.matchRoute(
|
|
8814
|
+
const hostname2 = url2.hostname || req.headers.get("host")?.split(":")[0] || "localhost";
|
|
8815
|
+
const optionsMatch = this.matchRoute(url2.pathname, "OPTIONS", hostname2);
|
|
8735
8816
|
if (!optionsMatch) {
|
|
8736
8817
|
return new Response(null, {
|
|
8737
8818
|
status: 204,
|
|
@@ -8744,8 +8825,8 @@ class Router {
|
|
|
8744
8825
|
});
|
|
8745
8826
|
}
|
|
8746
8827
|
}
|
|
8747
|
-
const hostname =
|
|
8748
|
-
const match = this.matchRoute(
|
|
8828
|
+
const hostname = url2.hostname || req.headers.get("host")?.split(":")[0] || "localhost";
|
|
8829
|
+
const match = this.matchRoute(url2.pathname, req.method, hostname);
|
|
8749
8830
|
const enhancedReq = this.enhanceRequest(req, match?.params || {});
|
|
8750
8831
|
if (match) {
|
|
8751
8832
|
enhancedReq.route = match.route;
|
|
@@ -8763,10 +8844,15 @@ class Router {
|
|
|
8763
8844
|
}
|
|
8764
8845
|
return new Response("No response from middleware chain", { status: 500 });
|
|
8765
8846
|
}
|
|
8766
|
-
const allowedMethods = this.getAllowedMethods(
|
|
8847
|
+
const allowedMethods = this.getAllowedMethods(url2.pathname, hostname);
|
|
8767
8848
|
if (allowedMethods.length > 0) {
|
|
8768
8849
|
const methodNotAllowedHandler = async (_req, _next) => {
|
|
8769
|
-
return new Response(JSON.stringify({
|
|
8850
|
+
return new Response(JSON.stringify({
|
|
8851
|
+
error: "Method Not Allowed",
|
|
8852
|
+
path: url2.pathname,
|
|
8853
|
+
method: req.method,
|
|
8854
|
+
allowed: allowedMethods
|
|
8855
|
+
}), {
|
|
8770
8856
|
status: 405,
|
|
8771
8857
|
headers: {
|
|
8772
8858
|
"Content-Type": "application/json",
|
|
@@ -8788,7 +8874,11 @@ class Router {
|
|
|
8788
8874
|
if (this.fallbackHandler) {
|
|
8789
8875
|
return await this.resolveHandler(this.fallbackHandler, enhancedReq);
|
|
8790
8876
|
}
|
|
8791
|
-
return new Response(JSON.stringify({
|
|
8877
|
+
return new Response(JSON.stringify({
|
|
8878
|
+
error: "Not Found",
|
|
8879
|
+
path: url2.pathname,
|
|
8880
|
+
method: req.method
|
|
8881
|
+
}), {
|
|
8792
8882
|
status: 404,
|
|
8793
8883
|
headers: { "Content-Type": "application/json" }
|
|
8794
8884
|
});
|
|
@@ -8803,7 +8893,11 @@ class Router {
|
|
|
8803
8893
|
const response2 = await this.resolveHandler(this.fallbackHandler, enhancedReq);
|
|
8804
8894
|
return this.applyModifiedCookies(response2, enhancedReq);
|
|
8805
8895
|
}
|
|
8806
|
-
return new Response(JSON.stringify({
|
|
8896
|
+
return new Response(JSON.stringify({
|
|
8897
|
+
error: "Not Found",
|
|
8898
|
+
path: url2.pathname,
|
|
8899
|
+
method: req.method
|
|
8900
|
+
}), {
|
|
8807
8901
|
status: 404,
|
|
8808
8902
|
headers: { "Content-Type": "application/json" }
|
|
8809
8903
|
});
|
|
@@ -8844,12 +8938,12 @@ class Router {
|
|
|
8844
8938
|
}
|
|
8845
8939
|
}
|
|
8846
8940
|
getAllowedMethods(path, domain) {
|
|
8847
|
-
const
|
|
8941
|
+
const url2 = new URL(path, "http://localhost");
|
|
8848
8942
|
const methods = new Set;
|
|
8849
8943
|
const allMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
|
|
8850
8944
|
for (const method of allMethods) {
|
|
8851
8945
|
if (this.staticRoutes.has(method)) {
|
|
8852
|
-
const staticRoute = this.staticRoutes.get(method).get(
|
|
8946
|
+
const staticRoute = this.staticRoutes.get(method).get(url2.pathname);
|
|
8853
8947
|
if (staticRoute && (!domain || !staticRoute.domain || staticRoute.domain === domain)) {
|
|
8854
8948
|
methods.add(method);
|
|
8855
8949
|
continue;
|
|
@@ -8858,7 +8952,7 @@ class Router {
|
|
|
8858
8952
|
const potentialRoutes = domain && this.domains[domain] ? this.domains[domain] : this.routes;
|
|
8859
8953
|
const methodRoutes = potentialRoutes.filter((route) => route.method === method);
|
|
8860
8954
|
for (const route of methodRoutes) {
|
|
8861
|
-
if (route.path ===
|
|
8955
|
+
if (route.path === url2.pathname) {
|
|
8862
8956
|
methods.add(method);
|
|
8863
8957
|
break;
|
|
8864
8958
|
}
|
|
@@ -8866,7 +8960,7 @@ class Router {
|
|
|
8866
8960
|
if (!methods.has(method)) {
|
|
8867
8961
|
for (const route of methodRoutes) {
|
|
8868
8962
|
if (route.pattern) {
|
|
8869
|
-
const match = route.pattern.exec(
|
|
8963
|
+
const match = route.pattern.exec(url2);
|
|
8870
8964
|
if (match) {
|
|
8871
8965
|
methods.add(method);
|
|
8872
8966
|
break;
|
|
@@ -8878,7 +8972,7 @@ class Router {
|
|
|
8878
8972
|
const wildcardRoutes = potentialRoutes.filter((route) => route.method === method && route.path.endsWith("*"));
|
|
8879
8973
|
for (const route of wildcardRoutes) {
|
|
8880
8974
|
const basePath = route.path.slice(0, -1);
|
|
8881
|
-
if (
|
|
8975
|
+
if (url2.pathname.startsWith(basePath)) {
|
|
8882
8976
|
methods.add(method);
|
|
8883
8977
|
break;
|
|
8884
8978
|
}
|
|
@@ -8891,13 +8985,13 @@ class Router {
|
|
|
8891
8985
|
return Array.from(methods);
|
|
8892
8986
|
}
|
|
8893
8987
|
matchRoute(path, method, domain) {
|
|
8894
|
-
const
|
|
8895
|
-
const cacheKey = `${domain || ""}:${method}:${
|
|
8988
|
+
const url2 = new URL(path, "http://localhost");
|
|
8989
|
+
const cacheKey = `${domain || ""}:${method}:${url2.pathname}`;
|
|
8896
8990
|
if (this.routeCache.has(cacheKey)) {
|
|
8897
8991
|
return this.routeCache.get(cacheKey);
|
|
8898
8992
|
}
|
|
8899
8993
|
if (this.staticRoutes.has(method)) {
|
|
8900
|
-
const staticRoute = this.staticRoutes.get(method).get(
|
|
8994
|
+
const staticRoute = this.staticRoutes.get(method).get(url2.pathname);
|
|
8901
8995
|
if (staticRoute && (!domain || !staticRoute.domain || staticRoute.domain === domain)) {
|
|
8902
8996
|
const result = {
|
|
8903
8997
|
route: staticRoute,
|
|
@@ -8910,7 +9004,7 @@ class Router {
|
|
|
8910
9004
|
const potentialRoutes = domain && this.domains[domain] ? this.domains[domain] : this.routes;
|
|
8911
9005
|
const methodRoutes = potentialRoutes.filter((route) => route.method === method);
|
|
8912
9006
|
for (const route of methodRoutes) {
|
|
8913
|
-
if (route.path ===
|
|
9007
|
+
if (route.path === url2.pathname) {
|
|
8914
9008
|
const result = {
|
|
8915
9009
|
route,
|
|
8916
9010
|
params: {}
|
|
@@ -8921,7 +9015,7 @@ class Router {
|
|
|
8921
9015
|
}
|
|
8922
9016
|
for (const route of methodRoutes) {
|
|
8923
9017
|
if (route.pattern) {
|
|
8924
|
-
const match = route.pattern.exec(
|
|
9018
|
+
const match = route.pattern.exec(url2);
|
|
8925
9019
|
if (match) {
|
|
8926
9020
|
const result = {
|
|
8927
9021
|
route,
|
|
@@ -8936,11 +9030,11 @@ class Router {
|
|
|
8936
9030
|
const wildcardRoutes = this.domains[domain].filter((route) => route.method === method && route.path.endsWith("*"));
|
|
8937
9031
|
for (const route of wildcardRoutes) {
|
|
8938
9032
|
const basePath = route.path.slice(0, -1);
|
|
8939
|
-
if (
|
|
9033
|
+
if (url2.pathname.startsWith(basePath)) {
|
|
8940
9034
|
const result = {
|
|
8941
9035
|
route,
|
|
8942
9036
|
params: {
|
|
8943
|
-
wildcard:
|
|
9037
|
+
wildcard: url2.pathname.slice(basePath.length)
|
|
8944
9038
|
}
|
|
8945
9039
|
};
|
|
8946
9040
|
this.routeCache.set(cacheKey, result);
|
|
@@ -8951,11 +9045,11 @@ class Router {
|
|
|
8951
9045
|
const globalWildcardRoutes = this.routes.filter((route) => route.method === method && route.path.endsWith("*") && (!domain || !route.domain));
|
|
8952
9046
|
for (const route of globalWildcardRoutes) {
|
|
8953
9047
|
const basePath = route.path.slice(0, -1);
|
|
8954
|
-
if (
|
|
9048
|
+
if (url2.pathname.startsWith(basePath)) {
|
|
8955
9049
|
const result = {
|
|
8956
9050
|
route,
|
|
8957
9051
|
params: {
|
|
8958
|
-
wildcard:
|
|
9052
|
+
wildcard: url2.pathname.slice(basePath.length)
|
|
8959
9053
|
}
|
|
8960
9054
|
};
|
|
8961
9055
|
this.routeCache.set(cacheKey, result);
|
|
@@ -8984,9 +9078,9 @@ class Router {
|
|
|
8984
9078
|
}
|
|
8985
9079
|
return parsedCookies;
|
|
8986
9080
|
};
|
|
8987
|
-
const
|
|
9081
|
+
const url2 = new URL(req.url);
|
|
8988
9082
|
const query = {};
|
|
8989
|
-
|
|
9083
|
+
url2.searchParams.forEach((value, key) => {
|
|
8990
9084
|
query[key] = value;
|
|
8991
9085
|
});
|
|
8992
9086
|
const enhancedReq = {
|
|
@@ -9173,6 +9267,20 @@ class Router {
|
|
|
9173
9267
|
return value;
|
|
9174
9268
|
return value !== undefined && value !== null ? [value] : [];
|
|
9175
9269
|
};
|
|
9270
|
+
enhancedReq.bearerToken = () => {
|
|
9271
|
+
const authHeader = req.headers.get("authorization") || req.headers.get("Authorization") || "";
|
|
9272
|
+
if (authHeader.startsWith("Bearer "))
|
|
9273
|
+
return authHeader.substring(7);
|
|
9274
|
+
return null;
|
|
9275
|
+
};
|
|
9276
|
+
enhancedReq.header = (name) => {
|
|
9277
|
+
return req.headers.get(name) || req.headers.get(name.toLowerCase()) || null;
|
|
9278
|
+
};
|
|
9279
|
+
enhancedReq.getParam = (name, defaultValue) => {
|
|
9280
|
+
const value = params?.[name];
|
|
9281
|
+
return value !== undefined ? value : defaultValue;
|
|
9282
|
+
};
|
|
9283
|
+
enhancedReq.params = params || {};
|
|
9176
9284
|
return enhancedReq;
|
|
9177
9285
|
}
|
|
9178
9286
|
applyModifiedCookies(response2, req) {
|
|
@@ -9310,6 +9418,7 @@ class Router {
|
|
|
9310
9418
|
this.routes.push(route);
|
|
9311
9419
|
if (route.name) {
|
|
9312
9420
|
this.namedRoutes.set(route.name, route);
|
|
9421
|
+
registerNamedRoute(route.name, route.path);
|
|
9313
9422
|
}
|
|
9314
9423
|
return this;
|
|
9315
9424
|
}
|
|
@@ -9341,7 +9450,7 @@ class Router {
|
|
|
9341
9450
|
}
|
|
9342
9451
|
return this;
|
|
9343
9452
|
}
|
|
9344
|
-
async executeMiddleware(middleware2,
|
|
9453
|
+
async executeMiddleware(middleware2, request2, handler) {
|
|
9345
9454
|
if (middleware2.length === 0) {
|
|
9346
9455
|
return handler();
|
|
9347
9456
|
}
|
|
@@ -9351,7 +9460,7 @@ class Router {
|
|
|
9351
9460
|
return handler();
|
|
9352
9461
|
}
|
|
9353
9462
|
const mw = middleware2[currentIndex++];
|
|
9354
|
-
const result = await mw(
|
|
9463
|
+
const result = await mw(request2, next);
|
|
9355
9464
|
return result || new Response("No response from middleware", { status: 500 });
|
|
9356
9465
|
};
|
|
9357
9466
|
return next();
|
|
@@ -9493,12 +9602,20 @@ function registerServerHandling(RouterClass) {
|
|
|
9493
9602
|
configurable: true
|
|
9494
9603
|
},
|
|
9495
9604
|
handleRequest: {
|
|
9605
|
+
async value(req) {
|
|
9606
|
+
const self = this;
|
|
9607
|
+
return runWithRequest(req, () => self.handleRequestImpl(req));
|
|
9608
|
+
},
|
|
9609
|
+
writable: true,
|
|
9610
|
+
configurable: true
|
|
9611
|
+
},
|
|
9612
|
+
handleRequestImpl: {
|
|
9496
9613
|
async value(req) {
|
|
9497
9614
|
try {
|
|
9498
|
-
const
|
|
9615
|
+
const url2 = new URL(req.url);
|
|
9499
9616
|
if (req.method === "OPTIONS") {
|
|
9500
|
-
const hostname2 =
|
|
9501
|
-
const optionsMatch = this.matchRoute(
|
|
9617
|
+
const hostname2 = url2.hostname || req.headers.get("host")?.split(":")[0] || "localhost";
|
|
9618
|
+
const optionsMatch = this.matchRoute(url2.pathname, "OPTIONS", hostname2);
|
|
9502
9619
|
if (!optionsMatch) {
|
|
9503
9620
|
return new Response(null, {
|
|
9504
9621
|
status: 204,
|
|
@@ -9512,9 +9629,10 @@ function registerServerHandling(RouterClass) {
|
|
|
9512
9629
|
});
|
|
9513
9630
|
}
|
|
9514
9631
|
}
|
|
9515
|
-
const hostname =
|
|
9516
|
-
const match = this.matchRoute(
|
|
9632
|
+
const hostname = url2.hostname || req.headers.get("host")?.split(":")[0] || "localhost";
|
|
9633
|
+
const match = this.matchRoute(url2.pathname, req.method, hostname);
|
|
9517
9634
|
const enhancedReq = this.enhanceRequest(req, match?.params || {});
|
|
9635
|
+
setCurrentRequest(enhancedReq);
|
|
9518
9636
|
if (match) {
|
|
9519
9637
|
enhancedReq.route = match.route;
|
|
9520
9638
|
const middlewareStack = [...this.globalMiddleware];
|
|
@@ -9531,32 +9649,53 @@ function registerServerHandling(RouterClass) {
|
|
|
9531
9649
|
}
|
|
9532
9650
|
return new Response("No response from middleware chain", { status: 500 });
|
|
9533
9651
|
}
|
|
9534
|
-
const allowedMethods = this.getAllowedMethods(
|
|
9652
|
+
const allowedMethods = this.getAllowedMethods(url2.pathname, hostname);
|
|
9653
|
+
const corsHeaders = {
|
|
9654
|
+
"Content-Type": "application/json",
|
|
9655
|
+
"Access-Control-Allow-Origin": "*",
|
|
9656
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
9657
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, Accept, Origin"
|
|
9658
|
+
};
|
|
9535
9659
|
if (allowedMethods.length > 0) {
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9660
|
+
const methodNotAllowedHandler = async (_req, _next) => {
|
|
9661
|
+
return new Response(JSON.stringify({
|
|
9662
|
+
success: false,
|
|
9663
|
+
message: "Method Not Allowed",
|
|
9664
|
+
path: url2.pathname,
|
|
9665
|
+
method: req.method,
|
|
9666
|
+
allowed: allowedMethods
|
|
9667
|
+
}), {
|
|
9668
|
+
status: 405,
|
|
9669
|
+
headers: { ...corsHeaders, Allow: allowedMethods.join(", ") }
|
|
9670
|
+
});
|
|
9671
|
+
};
|
|
9672
|
+
if (this.globalMiddleware.length > 0) {
|
|
9673
|
+
const stack = [...this.globalMiddleware, methodNotAllowedHandler];
|
|
9674
|
+
const response2 = await this.runMiddleware(enhancedReq, stack);
|
|
9675
|
+
if (response2)
|
|
9676
|
+
return this.applyModifiedCookies(response2, enhancedReq);
|
|
9677
|
+
}
|
|
9678
|
+
return await methodNotAllowedHandler(enhancedReq, async () => null);
|
|
9546
9679
|
}
|
|
9547
9680
|
if (this.fallbackHandler) {
|
|
9548
9681
|
const response2 = await this.resolveHandler(this.fallbackHandler, enhancedReq);
|
|
9549
9682
|
return this.applyModifiedCookies(response2, enhancedReq);
|
|
9550
9683
|
}
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9684
|
+
const notFoundHandler = async (_req, _next) => {
|
|
9685
|
+
return new Response(JSON.stringify({
|
|
9686
|
+
success: false,
|
|
9687
|
+
message: "Not Found",
|
|
9688
|
+
path: url2.pathname,
|
|
9689
|
+
method: req.method
|
|
9690
|
+
}), { status: 404, headers: corsHeaders });
|
|
9691
|
+
};
|
|
9692
|
+
if (this.globalMiddleware.length > 0) {
|
|
9693
|
+
const stack = [...this.globalMiddleware, notFoundHandler];
|
|
9694
|
+
const response2 = await this.runMiddleware(enhancedReq, stack);
|
|
9695
|
+
if (response2)
|
|
9696
|
+
return this.applyModifiedCookies(response2, enhancedReq);
|
|
9697
|
+
}
|
|
9698
|
+
return await notFoundHandler(enhancedReq, async () => null);
|
|
9560
9699
|
} catch (error) {
|
|
9561
9700
|
console.error("Error handling request:", error);
|
|
9562
9701
|
if (this.errorHandler) {
|
|
@@ -9865,34 +10004,34 @@ function registerWebSocketHandling(RouterClass) {
|
|
|
9865
10004
|
configurable: true
|
|
9866
10005
|
},
|
|
9867
10006
|
upgrade: {
|
|
9868
|
-
value(
|
|
10007
|
+
value(request2, options) {
|
|
9869
10008
|
if (!this.serverInstance) {
|
|
9870
10009
|
throw new Error("Server not started, cannot upgrade to WebSocket");
|
|
9871
10010
|
}
|
|
9872
10011
|
if (!this.wsConfig) {
|
|
9873
10012
|
throw new Error("WebSocket configuration not set, use router.websocket() to configure");
|
|
9874
10013
|
}
|
|
9875
|
-
return this.serverInstance.upgrade(
|
|
10014
|
+
return this.serverInstance.upgrade(request2, options);
|
|
9876
10015
|
},
|
|
9877
10016
|
writable: true,
|
|
9878
10017
|
configurable: true
|
|
9879
10018
|
},
|
|
9880
10019
|
timeout: {
|
|
9881
|
-
value(
|
|
10020
|
+
value(request2, seconds) {
|
|
9882
10021
|
if (!this.serverInstance) {
|
|
9883
10022
|
throw new Error("Server not started, cannot set timeout");
|
|
9884
10023
|
}
|
|
9885
|
-
this.serverInstance.timeout(
|
|
10024
|
+
this.serverInstance.timeout(request2, seconds);
|
|
9886
10025
|
},
|
|
9887
10026
|
writable: true,
|
|
9888
10027
|
configurable: true
|
|
9889
10028
|
},
|
|
9890
10029
|
requestIP: {
|
|
9891
|
-
value(
|
|
10030
|
+
value(request2) {
|
|
9892
10031
|
if (!this.serverInstance) {
|
|
9893
10032
|
throw new Error("Server not started, cannot get request IP");
|
|
9894
10033
|
}
|
|
9895
|
-
return this.serverInstance.requestIP(
|
|
10034
|
+
return this.serverInstance.requestIP(request2);
|
|
9896
10035
|
},
|
|
9897
10036
|
writable: true,
|
|
9898
10037
|
configurable: true
|
|
@@ -9927,12 +10066,12 @@ class RequestWithMacros {
|
|
|
9927
10066
|
static macro(name, handler) {
|
|
9928
10067
|
requestMacroRegistry.register(name, handler);
|
|
9929
10068
|
}
|
|
9930
|
-
static applyMacros(
|
|
10069
|
+
static applyMacros(request2) {
|
|
9931
10070
|
const macros = requestMacroRegistry.all();
|
|
9932
10071
|
macros.forEach((macro) => {
|
|
9933
|
-
|
|
10072
|
+
request2[macro.name] = macro.handler.bind(request2);
|
|
9934
10073
|
});
|
|
9935
|
-
return
|
|
10074
|
+
return request2;
|
|
9936
10075
|
}
|
|
9937
10076
|
static hasMacro(name) {
|
|
9938
10077
|
return requestMacroRegistry.has(name);
|
|
@@ -10138,8 +10277,8 @@ var BuiltInRequestMacros = {
|
|
|
10138
10277
|
return this.url;
|
|
10139
10278
|
},
|
|
10140
10279
|
root() {
|
|
10141
|
-
const
|
|
10142
|
-
return `${
|
|
10280
|
+
const url2 = new URL(this.url);
|
|
10281
|
+
return `${url2.protocol}//${url2.host}`;
|
|
10143
10282
|
},
|
|
10144
10283
|
is(pattern) {
|
|
10145
10284
|
const path = this.path();
|
|
@@ -10151,11 +10290,11 @@ var BuiltInRequestMacros = {
|
|
|
10151
10290
|
return this.routeName || null;
|
|
10152
10291
|
},
|
|
10153
10292
|
fingerprint() {
|
|
10154
|
-
const
|
|
10293
|
+
const url2 = new URL(this.url);
|
|
10155
10294
|
const data = {
|
|
10156
10295
|
method: this.method,
|
|
10157
|
-
path:
|
|
10158
|
-
query:
|
|
10296
|
+
path: url2.pathname,
|
|
10297
|
+
query: url2.search,
|
|
10159
10298
|
ip: BuiltInRequestMacros.ip.call(this)
|
|
10160
10299
|
};
|
|
10161
10300
|
return btoa(JSON.stringify(data));
|
|
@@ -10207,7 +10346,7 @@ function registerBuiltInRequestMacros() {
|
|
|
10207
10346
|
registerBuiltInRequestMacros();
|
|
10208
10347
|
|
|
10209
10348
|
// src/response/macros.ts
|
|
10210
|
-
import
|
|
10349
|
+
import process4 from "process";
|
|
10211
10350
|
|
|
10212
10351
|
class ResponseMacroRegistry {
|
|
10213
10352
|
macros = new Map;
|
|
@@ -10361,16 +10500,16 @@ var BuiltInResponseMacros = {
|
|
|
10361
10500
|
}
|
|
10362
10501
|
});
|
|
10363
10502
|
},
|
|
10364
|
-
redirect: (
|
|
10503
|
+
redirect: (url2, status = 302) => {
|
|
10365
10504
|
return new Response(null, {
|
|
10366
10505
|
status,
|
|
10367
10506
|
headers: {
|
|
10368
|
-
Location:
|
|
10507
|
+
Location: url2
|
|
10369
10508
|
}
|
|
10370
10509
|
});
|
|
10371
10510
|
},
|
|
10372
|
-
permanentRedirect: (
|
|
10373
|
-
return BuiltInResponseMacros.redirect(
|
|
10511
|
+
permanentRedirect: (url2) => {
|
|
10512
|
+
return BuiltInResponseMacros.redirect(url2, 301);
|
|
10374
10513
|
},
|
|
10375
10514
|
download: (data, filename, contentType = "application/octet-stream") => {
|
|
10376
10515
|
return new Response(data, {
|
|
@@ -10441,7 +10580,7 @@ var BuiltInResponseMacros = {
|
|
|
10441
10580
|
status,
|
|
10442
10581
|
timestamp: new Date().toISOString(),
|
|
10443
10582
|
checks,
|
|
10444
|
-
uptime:
|
|
10583
|
+
uptime: process4.uptime?.() || 0
|
|
10445
10584
|
};
|
|
10446
10585
|
return new Response(JSON.stringify(response2), {
|
|
10447
10586
|
status: statusCode,
|
|
@@ -10507,8 +10646,8 @@ var BuiltInRules = {
|
|
|
10507
10646
|
name: "url",
|
|
10508
10647
|
validate: (value) => {
|
|
10509
10648
|
try {
|
|
10510
|
-
const
|
|
10511
|
-
return Boolean(
|
|
10649
|
+
const url2 = new URL(value);
|
|
10650
|
+
return Boolean(url2);
|
|
10512
10651
|
} catch {
|
|
10513
10652
|
return false;
|
|
10514
10653
|
}
|
|
@@ -11332,8 +11471,8 @@ function createCookieAccessor2(cookies) {
|
|
|
11332
11471
|
|
|
11333
11472
|
class AuthTester {
|
|
11334
11473
|
request;
|
|
11335
|
-
constructor(
|
|
11336
|
-
this.request =
|
|
11474
|
+
constructor(request2) {
|
|
11475
|
+
this.request = request2 || createMockRequest();
|
|
11337
11476
|
}
|
|
11338
11477
|
as(user) {
|
|
11339
11478
|
this.request.user = user;
|
|
@@ -11561,16 +11700,16 @@ var authMocks = {
|
|
|
11561
11700
|
})
|
|
11562
11701
|
};
|
|
11563
11702
|
var authHelpers = {
|
|
11564
|
-
authenticatedRequest: (user,
|
|
11565
|
-
return new AuthTester(
|
|
11703
|
+
authenticatedRequest: (user, request2) => {
|
|
11704
|
+
return new AuthTester(request2).as(user).getRequest();
|
|
11566
11705
|
},
|
|
11567
|
-
jwtRequest: (payload = {},
|
|
11706
|
+
jwtRequest: (payload = {}, request2) => {
|
|
11568
11707
|
const jwt = new JWTTester;
|
|
11569
11708
|
const token = jwt.generateToken(payload);
|
|
11570
|
-
return new AuthTester(
|
|
11709
|
+
return new AuthTester(request2).withJWT(token).getRequest();
|
|
11571
11710
|
},
|
|
11572
|
-
sessionRequest: (sessionData = {},
|
|
11573
|
-
return new AuthTester(
|
|
11711
|
+
sessionRequest: (sessionData = {}, request2) => {
|
|
11712
|
+
return new AuthTester(request2).withSession(sessionData).getRequest();
|
|
11574
11713
|
},
|
|
11575
11714
|
verifyJWTStructure: (token) => {
|
|
11576
11715
|
const parts = token.split(".");
|
|
@@ -11585,8 +11724,8 @@ var authHelpers = {
|
|
|
11585
11724
|
}
|
|
11586
11725
|
}
|
|
11587
11726
|
};
|
|
11588
|
-
function createAuthTester(
|
|
11589
|
-
return new AuthTester(
|
|
11727
|
+
function createAuthTester(request2) {
|
|
11728
|
+
return new AuthTester(request2);
|
|
11590
11729
|
}
|
|
11591
11730
|
function createJWTTester(options) {
|
|
11592
11731
|
return new JWTTester(options);
|
|
@@ -11599,8 +11738,8 @@ import { mock as mock2 } from "bun:test";
|
|
|
11599
11738
|
class FileUploadTester {
|
|
11600
11739
|
request;
|
|
11601
11740
|
files;
|
|
11602
|
-
constructor(
|
|
11603
|
-
this.request =
|
|
11741
|
+
constructor(request2) {
|
|
11742
|
+
this.request = request2 || createMockRequest();
|
|
11604
11743
|
this.files = [];
|
|
11605
11744
|
}
|
|
11606
11745
|
addFile(testFile) {
|
|
@@ -11832,8 +11971,8 @@ var fileUploadScenarios = {
|
|
|
11832
11971
|
}
|
|
11833
11972
|
};
|
|
11834
11973
|
var fileUploadAssertions = {
|
|
11835
|
-
hasFiles: (
|
|
11836
|
-
const files =
|
|
11974
|
+
hasFiles: (request2, count) => {
|
|
11975
|
+
const files = request2.files || [];
|
|
11837
11976
|
if (count !== undefined && files.length !== count) {
|
|
11838
11977
|
throw new Error(`Expected ${count} files, but got ${files.length}`);
|
|
11839
11978
|
}
|
|
@@ -11841,8 +11980,8 @@ var fileUploadAssertions = {
|
|
|
11841
11980
|
throw new Error("Expected request to have files");
|
|
11842
11981
|
}
|
|
11843
11982
|
},
|
|
11844
|
-
hasFileWithField: (
|
|
11845
|
-
const files =
|
|
11983
|
+
hasFileWithField: (request2, fieldName) => {
|
|
11984
|
+
const files = request2.files || [];
|
|
11846
11985
|
const hasField = files.some((file) => file.fieldName === fieldName);
|
|
11847
11986
|
if (!hasField) {
|
|
11848
11987
|
throw new Error(`Expected file with field name '${fieldName}'`);
|
|
@@ -11866,8 +12005,8 @@ var fileUploadAssertions = {
|
|
|
11866
12005
|
}
|
|
11867
12006
|
}
|
|
11868
12007
|
};
|
|
11869
|
-
function createFileUploadTester(
|
|
11870
|
-
return new FileUploadTester(
|
|
12008
|
+
function createFileUploadTester(request2) {
|
|
12009
|
+
return new FileUploadTester(request2);
|
|
11871
12010
|
}
|
|
11872
12011
|
var testFiles = {
|
|
11873
12012
|
image: (fieldName = "image", filename = "test.jpg") => ({
|
|
@@ -11911,15 +12050,15 @@ class MiddlewareTester {
|
|
|
11911
12050
|
this.context = this.createContext();
|
|
11912
12051
|
}
|
|
11913
12052
|
createContext() {
|
|
11914
|
-
const
|
|
12053
|
+
const request2 = createMockRequest();
|
|
11915
12054
|
const next = mock3(() => Promise.resolve(new Response("Next called", { status: 200 })));
|
|
11916
12055
|
return {
|
|
11917
|
-
request,
|
|
12056
|
+
request: request2,
|
|
11918
12057
|
next
|
|
11919
12058
|
};
|
|
11920
12059
|
}
|
|
11921
|
-
withRequest(
|
|
11922
|
-
this.context.request =
|
|
12060
|
+
withRequest(request2) {
|
|
12061
|
+
this.context.request = request2;
|
|
11923
12062
|
return this;
|
|
11924
12063
|
}
|
|
11925
12064
|
withNext(nextFn) {
|
|
@@ -12017,8 +12156,8 @@ class MiddlewareChainTester {
|
|
|
12017
12156
|
this.request = createMockRequest();
|
|
12018
12157
|
this.finalHandler = mock3(async () => new Response("Final handler", { status: 200 }));
|
|
12019
12158
|
}
|
|
12020
|
-
withRequest(
|
|
12021
|
-
this.request =
|
|
12159
|
+
withRequest(request2) {
|
|
12160
|
+
this.request = request2;
|
|
12022
12161
|
return this;
|
|
12023
12162
|
}
|
|
12024
12163
|
withFinalHandler(handler) {
|
|
@@ -12058,11 +12197,11 @@ function createMiddlewareSpy() {
|
|
|
12058
12197
|
}
|
|
12059
12198
|
async function benchmarkMiddleware(middleware2, iterations = 1000) {
|
|
12060
12199
|
const times = [];
|
|
12061
|
-
const
|
|
12200
|
+
const request2 = createMockRequest();
|
|
12062
12201
|
const next = mock3(async () => new Response("OK"));
|
|
12063
12202
|
for (let i = 0;i < iterations; i++) {
|
|
12064
12203
|
const start = performance.now();
|
|
12065
|
-
await middleware2(
|
|
12204
|
+
await middleware2(request2, next);
|
|
12066
12205
|
const end = performance.now();
|
|
12067
12206
|
times.push(end - start);
|
|
12068
12207
|
}
|
|
@@ -12160,8 +12299,8 @@ class ModelBindingTester {
|
|
|
12160
12299
|
this.options = options;
|
|
12161
12300
|
this.request = createMockRequest();
|
|
12162
12301
|
}
|
|
12163
|
-
withRequest(
|
|
12164
|
-
this.request =
|
|
12302
|
+
withRequest(request2) {
|
|
12303
|
+
this.request = request2;
|
|
12165
12304
|
return this;
|
|
12166
12305
|
}
|
|
12167
12306
|
withParams(params) {
|
|
@@ -12299,18 +12438,18 @@ var modelMocks = {
|
|
|
12299
12438
|
};
|
|
12300
12439
|
var constraintHelpers = {
|
|
12301
12440
|
belongsTo: (userIdField = "userId") => {
|
|
12302
|
-
const fn = async (model,
|
|
12303
|
-
if (!
|
|
12441
|
+
const fn = async (model, request2) => {
|
|
12442
|
+
if (!request2.user)
|
|
12304
12443
|
return false;
|
|
12305
|
-
return model[userIdField] ===
|
|
12444
|
+
return model[userIdField] === request2.user.id;
|
|
12306
12445
|
};
|
|
12307
12446
|
return mock4(fn);
|
|
12308
12447
|
},
|
|
12309
12448
|
belongsToUser: () => {
|
|
12310
|
-
const fn = async (model,
|
|
12311
|
-
if (!
|
|
12449
|
+
const fn = async (model, request2) => {
|
|
12450
|
+
if (!request2.user)
|
|
12312
12451
|
return false;
|
|
12313
|
-
return model.userId ===
|
|
12452
|
+
return model.userId === request2.user.id;
|
|
12314
12453
|
};
|
|
12315
12454
|
return mock4(fn);
|
|
12316
12455
|
},
|
|
@@ -12330,9 +12469,9 @@ var constraintHelpers = {
|
|
|
12330
12469
|
return mock4(constraintFn);
|
|
12331
12470
|
},
|
|
12332
12471
|
combine: (...constraints) => {
|
|
12333
|
-
const fn = async (model,
|
|
12472
|
+
const fn = async (model, request2) => {
|
|
12334
12473
|
for (const constraint of constraints) {
|
|
12335
|
-
if (!await constraint(model,
|
|
12474
|
+
if (!await constraint(model, request2)) {
|
|
12336
12475
|
return false;
|
|
12337
12476
|
}
|
|
12338
12477
|
}
|
|
@@ -12389,24 +12528,24 @@ class ModelResolverTester {
|
|
|
12389
12528
|
}
|
|
12390
12529
|
var routeModelHelpers = {
|
|
12391
12530
|
testRoute: async (path, params, modelBindings) => {
|
|
12392
|
-
const
|
|
12393
|
-
|
|
12531
|
+
const request2 = createMockRequest("GET", path);
|
|
12532
|
+
request2.params = params;
|
|
12394
12533
|
for (const [key, model] of Object.entries(modelBindings)) {
|
|
12395
|
-
|
|
12396
|
-
|
|
12534
|
+
request2.context = request2.context || {};
|
|
12535
|
+
request2.context[key] = model;
|
|
12397
12536
|
}
|
|
12398
|
-
return
|
|
12537
|
+
return request2;
|
|
12399
12538
|
},
|
|
12400
12539
|
createHandler: (expectedModels) => {
|
|
12401
|
-
const fn = async (
|
|
12402
|
-
const context =
|
|
12540
|
+
const fn = async (request2) => {
|
|
12541
|
+
const context = request2.context || {};
|
|
12403
12542
|
for (const modelKey of expectedModels) {
|
|
12404
12543
|
if (!context[modelKey]) {
|
|
12405
12544
|
return new Response(`Model ${modelKey} not found`, { status: 404 });
|
|
12406
12545
|
}
|
|
12407
12546
|
}
|
|
12408
12547
|
return new Response(JSON.stringify({
|
|
12409
|
-
params:
|
|
12548
|
+
params: request2.params,
|
|
12410
12549
|
models: Object.fromEntries(expectedModels.map((key) => [key, context[key]]))
|
|
12411
12550
|
}), {
|
|
12412
12551
|
headers: { "Content-Type": "application/json" }
|
|
@@ -12415,16 +12554,16 @@ var routeModelHelpers = {
|
|
|
12415
12554
|
return mock4(fn);
|
|
12416
12555
|
},
|
|
12417
12556
|
testBindingMiddleware: (bindings) => {
|
|
12418
|
-
const fn = async (
|
|
12419
|
-
|
|
12557
|
+
const fn = async (request2, next) => {
|
|
12558
|
+
request2.context = request2.context || {};
|
|
12420
12559
|
for (const [key, resolver] of Object.entries(bindings)) {
|
|
12421
|
-
const paramValue =
|
|
12560
|
+
const paramValue = request2.params[key];
|
|
12422
12561
|
if (paramValue) {
|
|
12423
12562
|
try {
|
|
12424
12563
|
if (typeof resolver === "function") {
|
|
12425
|
-
|
|
12564
|
+
request2.context[key] = await resolver(paramValue);
|
|
12426
12565
|
} else {
|
|
12427
|
-
|
|
12566
|
+
request2.context[key] = resolver;
|
|
12428
12567
|
}
|
|
12429
12568
|
} catch (error) {
|
|
12430
12569
|
console.error(`Error resolving model ${key}:`, error);
|
|
@@ -12461,7 +12600,7 @@ var scopedBindingHelpers = {
|
|
|
12461
12600
|
};
|
|
12462
12601
|
// src/testing/performance-testing.ts
|
|
12463
12602
|
import { mock as mock5 } from "bun:test";
|
|
12464
|
-
import
|
|
12603
|
+
import process5 from "process";
|
|
12465
12604
|
class PerformanceTester {
|
|
12466
12605
|
metrics = [];
|
|
12467
12606
|
startTime = 0;
|
|
@@ -12580,10 +12719,10 @@ class LoadTester {
|
|
|
12580
12719
|
var benchmarkTests = {
|
|
12581
12720
|
routeHandler: async (handler, iterations = 1000) => {
|
|
12582
12721
|
const times = [];
|
|
12583
|
-
const
|
|
12722
|
+
const request2 = createMockRequest();
|
|
12584
12723
|
for (let i = 0;i < iterations; i++) {
|
|
12585
12724
|
const start = performance.now();
|
|
12586
|
-
await handler(
|
|
12725
|
+
await handler(request2);
|
|
12587
12726
|
const end = performance.now();
|
|
12588
12727
|
times.push(end - start);
|
|
12589
12728
|
}
|
|
@@ -12602,11 +12741,11 @@ var benchmarkTests = {
|
|
|
12602
12741
|
},
|
|
12603
12742
|
middleware: async (middleware2, iterations = 1000) => {
|
|
12604
12743
|
const times = [];
|
|
12605
|
-
const
|
|
12744
|
+
const request2 = createMockRequest();
|
|
12606
12745
|
const next = mock5(async () => new Response("OK"));
|
|
12607
12746
|
for (let i = 0;i < iterations; i++) {
|
|
12608
12747
|
const start = performance.now();
|
|
12609
|
-
await middleware2(
|
|
12748
|
+
await middleware2(request2, next);
|
|
12610
12749
|
const end = performance.now();
|
|
12611
12750
|
times.push(end - start);
|
|
12612
12751
|
}
|
|
@@ -12679,11 +12818,11 @@ var memoryTests = {
|
|
|
12679
12818
|
if (globalThis.gc) {
|
|
12680
12819
|
globalThis.gc();
|
|
12681
12820
|
}
|
|
12682
|
-
const initialHeap =
|
|
12821
|
+
const initialHeap = process5.memoryUsage().heapUsed;
|
|
12683
12822
|
for (let i = 0;i < iterations; i++) {
|
|
12684
12823
|
const result = await fn();
|
|
12685
12824
|
results.push(result);
|
|
12686
|
-
const memUsage =
|
|
12825
|
+
const memUsage = process5.memoryUsage();
|
|
12687
12826
|
heapUsages.push(memUsage.heapUsed);
|
|
12688
12827
|
if (i % 10 === 0 && globalThis.gc) {
|
|
12689
12828
|
globalThis.gc();
|
|
@@ -12692,7 +12831,7 @@ var memoryTests = {
|
|
|
12692
12831
|
if (globalThis.gc) {
|
|
12693
12832
|
globalThis.gc();
|
|
12694
12833
|
}
|
|
12695
|
-
const finalHeap =
|
|
12834
|
+
const finalHeap = process5.memoryUsage().heapUsed;
|
|
12696
12835
|
const averageHeapUsed = heapUsages.reduce((sum, usage) => sum + usage, 0) / heapUsages.length;
|
|
12697
12836
|
const maxHeapUsed = Math.max(...heapUsages);
|
|
12698
12837
|
const memoryLeakDetected = finalHeap - initialHeap > 1024 * 1024;
|
|
@@ -12706,17 +12845,17 @@ var memoryTests = {
|
|
|
12706
12845
|
testRouteHandlerMemoryLeaks: async (handler, iterations = 1000) => {
|
|
12707
12846
|
if (globalThis.gc)
|
|
12708
12847
|
globalThis.gc();
|
|
12709
|
-
const initialMemory =
|
|
12848
|
+
const initialMemory = process5.memoryUsage().heapUsed;
|
|
12710
12849
|
for (let i = 0;i < iterations; i++) {
|
|
12711
|
-
const
|
|
12712
|
-
await handler(
|
|
12850
|
+
const request2 = createMockRequest();
|
|
12851
|
+
await handler(request2);
|
|
12713
12852
|
if (i % 100 === 0 && globalThis.gc) {
|
|
12714
12853
|
globalThis.gc();
|
|
12715
12854
|
}
|
|
12716
12855
|
}
|
|
12717
12856
|
if (globalThis.gc)
|
|
12718
12857
|
globalThis.gc();
|
|
12719
|
-
const finalMemory =
|
|
12858
|
+
const finalMemory = process5.memoryUsage().heapUsed;
|
|
12720
12859
|
const memoryGrowth = finalMemory - initialMemory;
|
|
12721
12860
|
const memoryLeakDetected = memoryGrowth > 5 * 1024 * 1024;
|
|
12722
12861
|
return {
|
|
@@ -12808,7 +12947,7 @@ function createLoadTester(client, config2) {
|
|
|
12808
12947
|
}
|
|
12809
12948
|
var performanceUtils = {
|
|
12810
12949
|
getCurrentMemoryUsage: () => {
|
|
12811
|
-
const usage =
|
|
12950
|
+
const usage = process5.memoryUsage();
|
|
12812
12951
|
return {
|
|
12813
12952
|
heapUsed: usage.heapUsed,
|
|
12814
12953
|
heapTotal: usage.heapTotal,
|
|
@@ -12817,7 +12956,7 @@ var performanceUtils = {
|
|
|
12817
12956
|
};
|
|
12818
12957
|
},
|
|
12819
12958
|
getCPUUsage: () => {
|
|
12820
|
-
const usage =
|
|
12959
|
+
const usage = process5.cpuUsage();
|
|
12821
12960
|
return {
|
|
12822
12961
|
user: usage.user,
|
|
12823
12962
|
system: usage.system
|
|
@@ -12952,14 +13091,14 @@ class TestResponseWrapper {
|
|
|
12952
13091
|
}
|
|
12953
13092
|
return this;
|
|
12954
13093
|
}
|
|
12955
|
-
expectRedirect(
|
|
13094
|
+
expectRedirect(url2) {
|
|
12956
13095
|
if (this.status < 300 || this.status >= 400) {
|
|
12957
13096
|
throw new Error(`Expected redirect status (3xx), got ${this.status}`);
|
|
12958
13097
|
}
|
|
12959
|
-
if (
|
|
13098
|
+
if (url2) {
|
|
12960
13099
|
const location = this.headers.location;
|
|
12961
|
-
if (location !==
|
|
12962
|
-
throw new Error(`Expected redirect to '${
|
|
13100
|
+
if (location !== url2) {
|
|
13101
|
+
throw new Error(`Expected redirect to '${url2}', got '${location}'`);
|
|
12963
13102
|
}
|
|
12964
13103
|
}
|
|
12965
13104
|
return this;
|
|
@@ -13102,24 +13241,24 @@ class TestClient {
|
|
|
13102
13241
|
async request(method, path, options = {}) {
|
|
13103
13242
|
const headers = { ...this.defaultHeaders, ...options.headers };
|
|
13104
13243
|
const requestOptions = { ...options, headers };
|
|
13105
|
-
const
|
|
13244
|
+
const request2 = new TestRequestBuilder(method, path, requestOptions).build();
|
|
13106
13245
|
try {
|
|
13107
|
-
const response2 = await this.handleRequest(
|
|
13246
|
+
const response2 = await this.handleRequest(request2);
|
|
13108
13247
|
return await createTestResponse(response2);
|
|
13109
13248
|
} catch (error) {
|
|
13110
13249
|
throw new Error(`Test request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
13111
13250
|
}
|
|
13112
13251
|
}
|
|
13113
|
-
async handleRequest(
|
|
13114
|
-
const
|
|
13115
|
-
const matchResult = this.findMatchingRoute(
|
|
13252
|
+
async handleRequest(request2) {
|
|
13253
|
+
const url2 = new URL(request2.url);
|
|
13254
|
+
const matchResult = this.findMatchingRoute(request2.method, url2.pathname);
|
|
13116
13255
|
if (!matchResult) {
|
|
13117
13256
|
return new Response("Not Found", { status: 404 });
|
|
13118
13257
|
}
|
|
13119
13258
|
const { route, params } = matchResult;
|
|
13120
|
-
|
|
13259
|
+
request2.params = { ...request2.params, ...params };
|
|
13121
13260
|
try {
|
|
13122
|
-
const response2 = await this.executeMiddlewareChain(
|
|
13261
|
+
const response2 = await this.executeMiddlewareChain(request2, route);
|
|
13123
13262
|
return response2 || new Response("No response", { status: 500 });
|
|
13124
13263
|
} catch (error) {
|
|
13125
13264
|
return new Response(JSON.stringify({ error: error instanceof Error ? error.message : "Internal Server Error" }), {
|
|
@@ -13159,28 +13298,28 @@ class TestClient {
|
|
|
13159
13298
|
}
|
|
13160
13299
|
return params;
|
|
13161
13300
|
}
|
|
13162
|
-
async executeMiddlewareChain(
|
|
13301
|
+
async executeMiddlewareChain(request2, route) {
|
|
13163
13302
|
const middlewares = [...this.router.globalMiddleware, ...route.middleware];
|
|
13164
13303
|
let index = 0;
|
|
13165
13304
|
const next = async () => {
|
|
13166
13305
|
if (index < middlewares.length) {
|
|
13167
13306
|
const middleware2 = middlewares[index++];
|
|
13168
|
-
return await middleware2(
|
|
13307
|
+
return await middleware2(request2, next);
|
|
13169
13308
|
} else {
|
|
13170
|
-
return await this.executeHandler(route.handler,
|
|
13309
|
+
return await this.executeHandler(route.handler, request2);
|
|
13171
13310
|
}
|
|
13172
13311
|
};
|
|
13173
13312
|
const result = await next();
|
|
13174
13313
|
return result || new Response("No response", { status: 500 });
|
|
13175
13314
|
}
|
|
13176
|
-
async executeHandler(handler,
|
|
13315
|
+
async executeHandler(handler, request2) {
|
|
13177
13316
|
if (typeof handler === "function") {
|
|
13178
|
-
return await handler(
|
|
13317
|
+
return await handler(request2);
|
|
13179
13318
|
} else if (typeof handler === "string") {
|
|
13180
13319
|
throw new TypeError(`String handlers not supported in test environment: ${handler}`);
|
|
13181
13320
|
} else if (typeof handler === "object" && handler.handle) {
|
|
13182
13321
|
const instance = new handler;
|
|
13183
|
-
return await instance.handle(
|
|
13322
|
+
return await instance.handle(request2);
|
|
13184
13323
|
}
|
|
13185
13324
|
throw new Error("Invalid handler type");
|
|
13186
13325
|
}
|
|
@@ -13564,6 +13703,7 @@ export {
|
|
|
13564
13703
|
verifySignature,
|
|
13565
13704
|
validatePath,
|
|
13566
13705
|
validate,
|
|
13706
|
+
url,
|
|
13567
13707
|
toActionPath,
|
|
13568
13708
|
testRequest,
|
|
13569
13709
|
testMiddlewareChain,
|
|
@@ -13574,10 +13714,12 @@ export {
|
|
|
13574
13714
|
spyOnMiddleware,
|
|
13575
13715
|
singleFileUpload,
|
|
13576
13716
|
signRequest,
|
|
13717
|
+
setCurrentRequest,
|
|
13577
13718
|
session,
|
|
13578
13719
|
securitySuite,
|
|
13579
13720
|
security,
|
|
13580
13721
|
scopedBindingHelpers,
|
|
13722
|
+
runWithRequest,
|
|
13581
13723
|
router,
|
|
13582
13724
|
routeModelHelpers,
|
|
13583
13725
|
routeCacheManager,
|
|
@@ -13588,6 +13730,8 @@ export {
|
|
|
13588
13730
|
requestTracer,
|
|
13589
13731
|
requestSigning,
|
|
13590
13732
|
requestId,
|
|
13733
|
+
request,
|
|
13734
|
+
registerNamedRoute,
|
|
13591
13735
|
rateLimitRegistry,
|
|
13592
13736
|
rateLimit,
|
|
13593
13737
|
processHtmlTemplate,
|
|
@@ -13615,6 +13759,9 @@ export {
|
|
|
13615
13759
|
injectQueryPreservationScript,
|
|
13616
13760
|
imageUpload,
|
|
13617
13761
|
globalMiddlewarePipeline,
|
|
13762
|
+
getNamedRoutes,
|
|
13763
|
+
getNamedRoutePath,
|
|
13764
|
+
getCurrentRequest,
|
|
13618
13765
|
getConfig,
|
|
13619
13766
|
generateSessionId,
|
|
13620
13767
|
generateQueryPreservationScript,
|
|
@@ -13659,6 +13806,7 @@ export {
|
|
|
13659
13806
|
contentSecurityPolicy,
|
|
13660
13807
|
constraintHelpers,
|
|
13661
13808
|
config,
|
|
13809
|
+
clearNamedRoutes,
|
|
13662
13810
|
buildUrlWithPreservedParams,
|
|
13663
13811
|
benchmarkTests,
|
|
13664
13812
|
benchmarkMiddleware,
|