@stacksjs/bun-router 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/container/service-provider.d.ts +3 -3
- package/dist/development/performance-profiler.d.ts +3 -3
- package/dist/development/route-debugger.d.ts +1 -1
- package/dist/development/route-inspector.d.ts +2 -2
- package/dist/observability/integration.d.ts +1 -1
- package/dist/response/macros.d.ts +1 -1
- package/dist/router/index.d.ts +7 -7
- package/dist/router/router.d.ts +0 -32
- package/dist/testing/performance-testing.d.ts +2 -2
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/websocket-testing.d.ts +1 -1
- package/package.json +2 -3
- package/src/auth.ts +0 -489
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -786
- package/src/container/contextual-binding.ts +0 -606
- package/src/container/decorators.ts +0 -368
- package/src/container/index.ts +0 -49
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -733
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -623
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -718
- package/src/index.ts +0 -66
- package/src/middleware/auth.ts +0 -220
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -142
- package/src/middleware/csrf.ts +0 -166
- package/src/middleware/ddos_protection.ts +0 -279
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -275
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -453
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -540
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -945
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -251
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -638
- package/src/middleware/request_tracer.ts +0 -653
- package/src/middleware/response_cache.ts +0 -778
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -109
- package/src/request/enhanced-request.ts +0 -876
- package/src/request/macros.ts +0 -822
- package/src/response/macros.ts +0 -665
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -697
- package/src/router/file-streaming.ts +0 -383
- package/src/router/fluent-routing.ts +0 -866
- package/src/router/group-organization.ts +0 -229
- package/src/router/handler-resolver.ts +0 -327
- package/src/router/http-methods.ts +0 -407
- package/src/router/index.ts +0 -193
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -234
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -302
- package/src/router/route-building.ts +0 -221
- package/src/router/route-compiler.ts +0 -691
- package/src/router/route-matching.ts +0 -368
- package/src/router/route-trie.ts +0 -450
- package/src/router/router.ts +0 -1616
- package/src/router/server.ts +0 -684
- package/src/router/validation-integration.ts +0 -449
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -448
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -422
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -372
- package/src/types.ts +0 -2123
- package/src/url.ts +0 -131
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -395
- package/src/validation/validator.ts +0 -688
- package/src/websocket/clustering.ts +0 -769
package/src/url.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Named-route URL generation
|
|
3
|
-
*
|
|
4
|
-
* A module-level registry of `name → path` populated by both `Router` and
|
|
5
|
-
* `FluentRouter` whenever a route is given a name. `url(name, params)`
|
|
6
|
-
* resolves a registered name into a URL with path parameters substituted
|
|
7
|
-
* and unmatched params appended as a query string.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import process from 'node:process'
|
|
11
|
-
|
|
12
|
-
const namedRouteRegistry: Map<string, string> = new Map()
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Register a named-route path. Called by Router/FluentRouter when a route
|
|
16
|
-
* gets a `.name()`.
|
|
17
|
-
*/
|
|
18
|
-
export function registerNamedRoute(name: string, path: string): void {
|
|
19
|
-
namedRouteRegistry.set(name, path)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Look up a registered named-route path without parameter substitution.
|
|
24
|
-
* Mostly useful for tests and tooling.
|
|
25
|
-
*/
|
|
26
|
-
export function getNamedRoutePath(name: string): string | undefined {
|
|
27
|
-
return namedRouteRegistry.get(name)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Returns a snapshot of every registered named-route. The map itself is not
|
|
32
|
-
* exposed so callers can't mutate the registry.
|
|
33
|
-
*/
|
|
34
|
-
export function getNamedRoutes(): ReadonlyMap<string, string> {
|
|
35
|
-
return new Map(namedRouteRegistry)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Clear the registry. Provided for tests; production code should not need it.
|
|
40
|
-
*/
|
|
41
|
-
export function clearNamedRoutes(): void {
|
|
42
|
-
namedRouteRegistry.clear()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface UrlOptions {
|
|
46
|
-
/**
|
|
47
|
-
* Return a fully-qualified URL using `process.env.APP_URL` (falling back to
|
|
48
|
-
* `http://localhost`) instead of a path. Defaults to `false`.
|
|
49
|
-
*/
|
|
50
|
-
absolute?: boolean
|
|
51
|
-
/**
|
|
52
|
-
* Override the base used for `absolute: true`. Wins over `APP_URL`.
|
|
53
|
-
*/
|
|
54
|
-
base?: string
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Generate a URL for a named route.
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```ts
|
|
62
|
-
* router.get('/users/{id}', handler).name('users.show')
|
|
63
|
-
*
|
|
64
|
-
* url('users.show', { id: 42 })
|
|
65
|
-
* // → '/users/42'
|
|
66
|
-
*
|
|
67
|
-
* url('users.show', { id: 42, tab: 'profile' })
|
|
68
|
-
* // → '/users/42?tab=profile'
|
|
69
|
-
*
|
|
70
|
-
* url('users.show', { id: 42 }, { absolute: true })
|
|
71
|
-
* // → 'https://app.example/users/42' (when APP_URL=https://app.example)
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
export function url(
|
|
75
|
-
name: string,
|
|
76
|
-
params: Record<string, string | number | boolean> = {},
|
|
77
|
-
options: UrlOptions = {},
|
|
78
|
-
): string {
|
|
79
|
-
const path = namedRouteRegistry.get(name)
|
|
80
|
-
if (!path) {
|
|
81
|
-
const known = [...namedRouteRegistry.keys()].sort().join(', ') || '(none registered)'
|
|
82
|
-
throw new Error(`Named route '${name}' is not defined. Known routes: ${known}`)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const consumed = new Set<string>()
|
|
86
|
-
let resolved = path
|
|
87
|
-
|
|
88
|
-
for (const [key, value] of Object.entries(params)) {
|
|
89
|
-
const required = `{${key}}`
|
|
90
|
-
const optional = `{${key}?}`
|
|
91
|
-
const encoded = encodeURIComponent(String(value))
|
|
92
|
-
|
|
93
|
-
if (resolved.includes(required)) {
|
|
94
|
-
resolved = resolved.replaceAll(required, encoded)
|
|
95
|
-
consumed.add(key)
|
|
96
|
-
}
|
|
97
|
-
else if (resolved.includes(optional)) {
|
|
98
|
-
resolved = resolved.replaceAll(optional, encoded)
|
|
99
|
-
consumed.add(key)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Strip any unfilled optional placeholders and tidy the slashes they
|
|
104
|
-
// leave behind (`/posts/{slug?}` → `/posts`, `/a/{v?}/b` → `/a/b`)
|
|
105
|
-
if (resolved.includes('?}')) {
|
|
106
|
-
resolved = resolved.replace(/\{[^}]+\?\}/g, '').replace(/\/{2,}/g, '/')
|
|
107
|
-
if (resolved.length > 1 && resolved.endsWith('/'))
|
|
108
|
-
resolved = resolved.slice(0, -1)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Throw on unfilled required placeholders so the caller sees the bug.
|
|
112
|
-
const missing = resolved.match(/\{([^}?]+)\}/g)
|
|
113
|
-
if (missing && missing.length > 0)
|
|
114
|
-
throw new Error(`Missing required params for route '${name}': ${missing.join(', ')}`)
|
|
115
|
-
|
|
116
|
-
// Append leftover params as query string.
|
|
117
|
-
const leftover = Object.entries(params).filter(([k]) => !consumed.has(k))
|
|
118
|
-
if (leftover.length > 0) {
|
|
119
|
-
const qs = new URLSearchParams()
|
|
120
|
-
for (const [k, v] of leftover) qs.set(k, String(v))
|
|
121
|
-
resolved += `?${qs.toString()}`
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (options.absolute) {
|
|
125
|
-
const base = (options.base ?? process.env.APP_URL ?? 'http://localhost').replace(/\/$/, '')
|
|
126
|
-
const prefixed = base.startsWith('http') ? base : `https://${base}`
|
|
127
|
-
return `${prefixed}${resolved.startsWith('/') ? resolved : `/${resolved}`}`
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return resolved
|
|
131
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './query-preservation'
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Query Parameter Preservation
|
|
3
|
-
*
|
|
4
|
-
* Automatically preserves specified query parameters across navigation.
|
|
5
|
-
* This is useful for maintaining state like siteId, theme, locale, etc.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface QueryPreservationConfig {
|
|
9
|
-
/**
|
|
10
|
-
* Whether query preservation is enabled
|
|
11
|
-
* Default: true when preserve array is non-empty
|
|
12
|
-
*/
|
|
13
|
-
enabled?: boolean
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Query parameters to preserve across navigation
|
|
17
|
-
* Example: ['siteId', 'theme', 'locale']
|
|
18
|
-
*/
|
|
19
|
-
preserve?: string[]
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Query parameters to never preserve (takes precedence over preserve)
|
|
23
|
-
* Example: ['_t', 'utm_source']
|
|
24
|
-
*/
|
|
25
|
-
exclude?: string[]
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* URL patterns where preservation should apply
|
|
29
|
-
* Default: all internal links (same origin)
|
|
30
|
-
* Example: ['/dashboard/*', '/admin/*']
|
|
31
|
-
*/
|
|
32
|
-
routes?: string[]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Default configuration
|
|
37
|
-
*/
|
|
38
|
-
export const defaultQueryPreservationConfig: QueryPreservationConfig = {
|
|
39
|
-
enabled: true,
|
|
40
|
-
preserve: [],
|
|
41
|
-
exclude: ['_t', '_cache', 'callback'],
|
|
42
|
-
routes: [],
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* eslint-disable prefer-const */
|
|
46
|
-
/**
|
|
47
|
-
* Generate the client-side script for query preservation
|
|
48
|
-
* This script intercepts link clicks and preserves specified query params
|
|
49
|
-
*/
|
|
50
|
-
export function generateQueryPreservationScript(config: QueryPreservationConfig): string {
|
|
51
|
-
const { preserve = [], exclude = [], routes = [] } = config
|
|
52
|
-
|
|
53
|
-
if (!preserve.length) {
|
|
54
|
-
return ''
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Minified but readable client-side script
|
|
58
|
-
return `<script data-query-preservation>
|
|
59
|
-
(function(){
|
|
60
|
-
var preserve = ${JSON.stringify(preserve)};
|
|
61
|
-
var exclude = ${JSON.stringify(exclude)};
|
|
62
|
-
var routes = ${JSON.stringify(routes)};
|
|
63
|
-
|
|
64
|
-
function shouldPreserve(href) {
|
|
65
|
-
// Only preserve for same-origin links
|
|
66
|
-
try {
|
|
67
|
-
var url = new URL(href, window.location.origin);
|
|
68
|
-
if (url.origin !== window.location.origin) return false;
|
|
69
|
-
// Check route patterns if specified
|
|
70
|
-
if (routes.length) {
|
|
71
|
-
var path = url.pathname;
|
|
72
|
-
return routes.some(function(pattern) {
|
|
73
|
-
if (pattern.endsWith('*')) {
|
|
74
|
-
return path.startsWith(pattern.slice(0, -1));
|
|
75
|
-
}
|
|
76
|
-
// eslint-disable-next-line prefer-template
|
|
77
|
-
return path === pattern || path.startsWith(pattern + '/');
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
catch (e) { return false; }
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function getPreservedParams() {
|
|
86
|
-
var current = new URLSearchParams(window.location.search);
|
|
87
|
-
var preserved = {};
|
|
88
|
-
preserve.forEach(function(key) {
|
|
89
|
-
if (current.has(key) && exclude.indexOf(key) === -1) {
|
|
90
|
-
preserved[key] = current.get(key);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
return preserved;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function enhanceUrl(href) {
|
|
97
|
-
var url = new URL(href, window.location.origin);
|
|
98
|
-
var preserved = getPreservedParams();
|
|
99
|
-
Object.keys(preserved).forEach(function(key) {
|
|
100
|
-
if (!url.searchParams.has(key)) {
|
|
101
|
-
url.searchParams.set(key, preserved[key]);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
return url.toString();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Intercept all link clicks
|
|
108
|
-
document.addEventListener('click', function(e) {
|
|
109
|
-
var link = e.target.closest('a[href]');
|
|
110
|
-
if (!link) return;
|
|
111
|
-
|
|
112
|
-
var href = link.getAttribute('href');
|
|
113
|
-
if (!href || href.startsWith('#') || href.startsWith('javascript:') ||
|
|
114
|
-
href.startsWith('mailto:') || href.startsWith('tel:')) return;
|
|
115
|
-
|
|
116
|
-
if (!shouldPreserve(href)) return;
|
|
117
|
-
|
|
118
|
-
// Check if link already has all preserved params
|
|
119
|
-
var enhanced = enhanceUrl(href);
|
|
120
|
-
if (enhanced !== new URL(href, window.location.origin).toString()) {
|
|
121
|
-
e.preventDefault();
|
|
122
|
-
window.location.href = enhanced;
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Expose API for programmatic navigation
|
|
127
|
-
window.__preserveQuery = {
|
|
128
|
-
enhance: enhanceUrl,
|
|
129
|
-
getPreserved: getPreservedParams,
|
|
130
|
-
navigate: function(href) {
|
|
131
|
-
window.location.href = enhanceUrl(href);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
})();
|
|
135
|
-
</script>`
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Inject the query preservation script into HTML content
|
|
140
|
-
* Inserts before </head> or </body> if </head> not found
|
|
141
|
-
*/
|
|
142
|
-
export function injectQueryPreservationScript(
|
|
143
|
-
html: string,
|
|
144
|
-
config: QueryPreservationConfig
|
|
145
|
-
): string {
|
|
146
|
-
if (!config.enabled || !config.preserve?.length) {
|
|
147
|
-
return html
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const script = generateQueryPreservationScript(config)
|
|
151
|
-
if (!script) {
|
|
152
|
-
return html
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Try to inject before </head> for early execution
|
|
156
|
-
if (html.includes('</head>')) {
|
|
157
|
-
return html.replace('</head>', `${script}\n</head>`)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Fallback: inject before </body>
|
|
161
|
-
if (html.includes('</body>')) {
|
|
162
|
-
return html.replace('</body>', `${script}\n</body>`)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Last resort: append to end
|
|
166
|
-
return html + script
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Build a URL with preserved query parameters
|
|
171
|
-
* Server-side utility for generating links
|
|
172
|
-
*/
|
|
173
|
-
export function buildUrlWithPreservedParams(
|
|
174
|
-
path: string,
|
|
175
|
-
currentUrl: string | URL,
|
|
176
|
-
config: QueryPreservationConfig,
|
|
177
|
-
additionalParams?: Record<string, string>
|
|
178
|
-
): string {
|
|
179
|
-
const current = typeof currentUrl === 'string' ? new URL(currentUrl) : currentUrl
|
|
180
|
-
const target = new URL(path, current.origin)
|
|
181
|
-
|
|
182
|
-
// Preserve specified params from current URL
|
|
183
|
-
if (config.preserve) {
|
|
184
|
-
for (const key of config.preserve) {
|
|
185
|
-
if (current.searchParams.has(key) && !config.exclude?.includes(key)) {
|
|
186
|
-
if (!target.searchParams.has(key)) {
|
|
187
|
-
target.searchParams.set(key, current.searchParams.get(key)!)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Add any additional params
|
|
194
|
-
if (additionalParams) {
|
|
195
|
-
for (const [key, value] of Object.entries(additionalParams)) {
|
|
196
|
-
target.searchParams.set(key, value)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return target.pathname + target.search
|
|
201
|
-
}
|