@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.
Files changed (146) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/container/service-provider.d.ts +3 -3
  3. package/dist/development/performance-profiler.d.ts +3 -3
  4. package/dist/development/route-debugger.d.ts +1 -1
  5. package/dist/development/route-inspector.d.ts +2 -2
  6. package/dist/observability/integration.d.ts +1 -1
  7. package/dist/response/macros.d.ts +1 -1
  8. package/dist/router/index.d.ts +7 -7
  9. package/dist/router/router.d.ts +0 -32
  10. package/dist/testing/performance-testing.d.ts +2 -2
  11. package/dist/testing/test-client.d.ts +1 -1
  12. package/dist/testing/websocket-testing.d.ts +1 -1
  13. package/package.json +2 -3
  14. package/src/auth.ts +0 -489
  15. package/src/cache/lru-cache.ts +0 -457
  16. package/src/cache/middleware-memoization.ts +0 -531
  17. package/src/cache/route-cache-warmer.ts +0 -486
  18. package/src/cache/sqlite-cache.ts +0 -783
  19. package/src/cache/streaming-cache.ts +0 -572
  20. package/src/cli/colors.ts +0 -29
  21. package/src/cli/index.ts +0 -287
  22. package/src/cli/middleware.ts +0 -291
  23. package/src/cli/openapi.ts +0 -407
  24. package/src/cli/router.ts +0 -188
  25. package/src/cli/routes.ts +0 -265
  26. package/src/cli/utils.ts +0 -531
  27. package/src/cli.ts +0 -5
  28. package/src/config.ts +0 -322
  29. package/src/container/container.ts +0 -786
  30. package/src/container/contextual-binding.ts +0 -606
  31. package/src/container/decorators.ts +0 -368
  32. package/src/container/index.ts +0 -49
  33. package/src/container/service-provider.ts +0 -596
  34. package/src/development/hot-reload.ts +0 -673
  35. package/src/development/index.ts +0 -499
  36. package/src/development/performance-profiler.ts +0 -717
  37. package/src/development/route-debugger.ts +0 -527
  38. package/src/development/route-inspector.ts +0 -749
  39. package/src/development/typescript-utilities.ts +0 -682
  40. package/src/docs.ts +0 -397
  41. package/src/errors/circuit-breaker.ts +0 -733
  42. package/src/errors/error-handler.ts +0 -569
  43. package/src/errors/error-reporting.ts +0 -672
  44. package/src/errors/exceptions.ts +0 -536
  45. package/src/errors/graceful-degradation.ts +0 -623
  46. package/src/errors/index.ts +0 -21
  47. package/src/errors/router-errors.ts +0 -632
  48. package/src/file-serving/static-files.ts +0 -718
  49. package/src/index.ts +0 -66
  50. package/src/middleware/auth.ts +0 -220
  51. package/src/middleware/content_security_policy.ts +0 -215
  52. package/src/middleware/cors.ts +0 -142
  53. package/src/middleware/csrf.ts +0 -166
  54. package/src/middleware/ddos_protection.ts +0 -279
  55. package/src/middleware/file_security.ts +0 -191
  56. package/src/middleware/file_upload.ts +0 -275
  57. package/src/middleware/helmet.ts +0 -268
  58. package/src/middleware/index.ts +0 -117
  59. package/src/middleware/input_validation.ts +0 -453
  60. package/src/middleware/json_body.ts +0 -37
  61. package/src/middleware/performance_alerting.ts +0 -540
  62. package/src/middleware/performance_dashboard.ts +0 -661
  63. package/src/middleware/performance_monitor.ts +0 -945
  64. package/src/middleware/pipeline.ts +0 -489
  65. package/src/middleware/rate_limit.ts +0 -251
  66. package/src/middleware/request_id.ts +0 -36
  67. package/src/middleware/request_signing.ts +0 -638
  68. package/src/middleware/request_tracer.ts +0 -653
  69. package/src/middleware/response_cache.ts +0 -778
  70. package/src/middleware/security.ts +0 -482
  71. package/src/middleware/security_suite.ts +0 -257
  72. package/src/middleware/session.ts +0 -91
  73. package/src/model-binding/index.ts +0 -18
  74. package/src/model-binding/model-middleware.ts +0 -425
  75. package/src/model-binding/model-registry.ts +0 -550
  76. package/src/model-binding.ts +0 -370
  77. package/src/model-resolver-factory.ts +0 -106
  78. package/src/observability/correlation.ts +0 -691
  79. package/src/observability/health-checks.ts +0 -729
  80. package/src/observability/index.ts +0 -184
  81. package/src/observability/integration.ts +0 -548
  82. package/src/observability/metrics.ts +0 -753
  83. package/src/observability/tracing.ts +0 -638
  84. package/src/optimization/bun-utilities.ts +0 -778
  85. package/src/query-builder-integration.ts +0 -137
  86. package/src/request/context.ts +0 -109
  87. package/src/request/enhanced-request.ts +0 -876
  88. package/src/request/macros.ts +0 -822
  89. package/src/response/macros.ts +0 -665
  90. package/src/response/response-factory.ts +0 -596
  91. package/src/router/api-routes.ts +0 -243
  92. package/src/router/file-based-routing.ts +0 -697
  93. package/src/router/file-streaming.ts +0 -383
  94. package/src/router/fluent-routing.ts +0 -866
  95. package/src/router/group-organization.ts +0 -229
  96. package/src/router/handler-resolver.ts +0 -327
  97. package/src/router/http-methods.ts +0 -407
  98. package/src/router/index.ts +0 -193
  99. package/src/router/middleware-groups.ts +0 -222
  100. package/src/router/middleware-integration.ts +0 -399
  101. package/src/router/middleware.ts +0 -234
  102. package/src/router/model-binding.ts +0 -215
  103. package/src/router/optimized-route-matching.ts +0 -302
  104. package/src/router/route-building.ts +0 -221
  105. package/src/router/route-compiler.ts +0 -691
  106. package/src/router/route-matching.ts +0 -368
  107. package/src/router/route-trie.ts +0 -450
  108. package/src/router/router.ts +0 -1616
  109. package/src/router/server.ts +0 -684
  110. package/src/router/validation-integration.ts +0 -449
  111. package/src/router/view-rendering.ts +0 -233
  112. package/src/router/websocket.ts +0 -100
  113. package/src/routing/route-caching.ts +0 -402
  114. package/src/routing/route-throttling.ts +0 -469
  115. package/src/routing/subdomain-routing.ts +0 -492
  116. package/src/session/database-store.ts +0 -109
  117. package/src/session/file-store.ts +0 -148
  118. package/src/session/index.ts +0 -244
  119. package/src/session/memory-store.ts +0 -88
  120. package/src/session/redis-store.ts +0 -93
  121. package/src/streaming/index.ts +0 -17
  122. package/src/streaming/sse-handler.ts +0 -482
  123. package/src/streaming/stream-handler.ts +0 -552
  124. package/src/testing/auth-testing.ts +0 -448
  125. package/src/testing/file-upload-testing.ts +0 -543
  126. package/src/testing/index.ts +0 -10
  127. package/src/testing/middleware-testing.ts +0 -322
  128. package/src/testing/model-binding-testing.ts +0 -645
  129. package/src/testing/performance-testing.ts +0 -738
  130. package/src/testing/test-client.ts +0 -310
  131. package/src/testing/test-request.ts +0 -315
  132. package/src/testing/test-response.ts +0 -332
  133. package/src/testing/types.ts +0 -224
  134. package/src/testing/websocket-testing.ts +0 -590
  135. package/src/types/controller-types.ts +0 -385
  136. package/src/types/core.ts +0 -683
  137. package/src/types/middleware-types.ts +0 -422
  138. package/src/types/request-response-augmentation.ts +0 -489
  139. package/src/types/route-inference.ts +0 -372
  140. package/src/types.ts +0 -2123
  141. package/src/url.ts +0 -131
  142. package/src/utils/index.ts +0 -1
  143. package/src/utils/query-preservation.ts +0 -201
  144. package/src/utils.ts +0 -395
  145. package/src/validation/validator.ts +0 -688
  146. package/src/websocket/clustering.ts +0 -769
package/src/auth.ts DELETED
@@ -1,489 +0,0 @@
1
- import type { EnhancedRequest, JwtHeader, JwtPayload } from './types'
2
- import { timingSafeEqual } from 'node:crypto'
3
-
4
- // Types
5
- export interface JwtVerifyOptions {
6
- issuer?: string
7
- audience?: string
8
- subject?: string
9
- algorithms?: string[]
10
- expiresIn?: string | number
11
- notBefore?: string | number
12
- ignoreExpiration?: boolean
13
- allowInvalidAsymmetricKeyTypes?: boolean
14
- }
15
-
16
- export interface JwtSignOptions {
17
- algorithm?: 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512' | 'PS256' | 'PS384' | 'PS512' | 'none'
18
- expiresIn?: string | number
19
- notBefore?: string | number
20
- audience?: string | string[]
21
- issuer?: string
22
- subject?: string
23
- keyid?: string
24
- jwtid?: string
25
- noTimestamp?: boolean
26
- header?: Partial<JwtHeader>
27
- encoding?: string
28
- }
29
-
30
- /**
31
- * Token endpoint response for the OAuth2 authorization-code flow
32
- * (RFC 6749 §5.1). Providers may include extra fields — they're preserved
33
- * under the index signature.
34
- */
35
- export interface OAuth2TokenResponse {
36
- access_token: string
37
- token_type: string
38
- expires_in?: number
39
- refresh_token?: string
40
- scope?: string
41
- id_token?: string
42
- [key: string]: string | number | undefined
43
- }
44
-
45
- export interface ApiKeyOptions {
46
- source?: 'header' | 'query' | 'cookie'
47
- keyName?: string
48
- keyPrefix?: string
49
- }
50
-
51
- export interface OAuth2Config {
52
- clientId: string
53
- clientSecret: string
54
- authorizeUrl: string
55
- tokenUrl: string
56
- redirectUri: string
57
- scope?: string
58
- state?: string
59
- }
60
-
61
- // Re-export JwtPayload from types for backwards compatibility
62
- export type { JwtPayload }
63
-
64
- // Base64URL encoding/decoding functions
65
- function base64UrlEncode(str: string): string {
66
- return btoa(str)
67
- .replace(/\+/g, '-')
68
- .replace(/\//g, '_')
69
- .replace(/=+$/, '')
70
- }
71
-
72
- function base64UrlDecode(str: string): string {
73
- str = str.replace(/-/g, '+').replace(/_/g, '/')
74
- while (str.length % 4) {
75
- str += '='
76
- }
77
- return atob(str)
78
- }
79
-
80
- /**
81
- * Simple JWT implementation for signing and verifying tokens
82
- */
83
- export class JWT {
84
- private secret: string
85
-
86
- constructor(secret: string) {
87
- this.secret = secret
88
- }
89
-
90
- /**
91
- * Sign payload into a JWT token
92
- */
93
- sign(payload: JwtPayload, options: JwtSignOptions = {}): string {
94
- // Default header
95
- const header = {
96
- alg: options.algorithm || 'HS256',
97
- typ: 'JWT',
98
- ...options.header,
99
- }
100
-
101
- // Prepare payload with registered claims
102
- const now = Math.floor(Date.now() / 1000)
103
-
104
- const jwtPayload: JwtPayload = {
105
- ...payload,
106
- iat: now,
107
- }
108
-
109
- // Add registered claims from options
110
- if (options.expiresIn) {
111
- const expiresIn = typeof options.expiresIn === 'string'
112
- ? this.parseTimespan(options.expiresIn)
113
- : options.expiresIn
114
-
115
- jwtPayload.exp = now + expiresIn
116
- }
117
-
118
- if (options.notBefore) {
119
- const notBefore = typeof options.notBefore === 'string'
120
- ? this.parseTimespan(options.notBefore)
121
- : options.notBefore
122
-
123
- jwtPayload.nbf = now + notBefore
124
- }
125
-
126
- if (options.issuer)
127
- jwtPayload.iss = options.issuer
128
- if (options.subject)
129
- jwtPayload.sub = options.subject
130
- if (options.audience)
131
- jwtPayload.aud = options.audience
132
- if (options.jwtid)
133
- jwtPayload.jti = options.jwtid
134
-
135
- // Encode header and payload
136
- const encodedHeader = base64UrlEncode(JSON.stringify(header))
137
- const encodedPayload = base64UrlEncode(JSON.stringify(jwtPayload))
138
-
139
- // Create signature - Note: In a production environment, you'd use Bun's crypto APIs
140
- // or a proper JWT library. This is a simplified implementation.
141
- const data = `${encodedHeader}.${encodedPayload}`
142
- const signature = this.createSignature(data, this.secret, header.alg)
143
-
144
- // Return the JWT
145
- return `${data}.${signature}`
146
- }
147
-
148
- /**
149
- * Verify a JWT token and return the decoded payload
150
- */
151
- verify(token: string, options: JwtVerifyOptions = {}): JwtPayload | null {
152
- try {
153
- const parts = token.split('.')
154
-
155
- if (parts.length !== 3) {
156
- throw new Error('Token structure invalid')
157
- }
158
-
159
- const [encodedHeader, encodedPayload, signature] = parts
160
-
161
- // Decode header and payload
162
- const header = JSON.parse(base64UrlDecode(encodedHeader)) as JwtHeader
163
- const payload = JSON.parse(base64UrlDecode(encodedPayload)) as JwtPayload
164
-
165
- // Verify algorithm if specified
166
- if (options.algorithms && !options.algorithms.includes(header.alg)) {
167
- throw new Error(`Algorithm ${header.alg} not allowed`)
168
- }
169
-
170
- // Verify signature - Note: In a production environment, you'd use Bun's crypto APIs
171
- // or a proper JWT library. This is a simplified implementation.
172
- const data = `${encodedHeader}.${encodedPayload}`
173
- const expectedSignature = this.createSignature(data, this.secret, header.alg)
174
-
175
- // Constant-time comparison — `!==` leaks how much of the signature
176
- // matched through response timing
177
- const sigBuf = Buffer.from(signature)
178
- const expectedBuf = Buffer.from(expectedSignature)
179
- if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {
180
- throw new Error('Invalid signature')
181
- }
182
-
183
- // Verify time-based claims
184
- const now = Math.floor(Date.now() / 1000)
185
-
186
- if (payload.exp && !options.ignoreExpiration && now >= payload.exp) {
187
- throw new Error('Token expired')
188
- }
189
-
190
- if (payload.nbf && now < payload.nbf) {
191
- throw new Error('Token not active yet')
192
- }
193
-
194
- if (payload.iat && payload.iat > now) {
195
- throw new Error('Token used before issued')
196
- }
197
-
198
- // Verify issuer
199
- if (options.issuer && payload.iss !== options.issuer) {
200
- throw new Error('Invalid issuer')
201
- }
202
-
203
- // Verify audience
204
- if (options.audience && payload.aud !== options.audience) {
205
- throw new Error('Invalid audience')
206
- }
207
-
208
- // Verify subject
209
- if (options.subject && payload.sub !== options.subject) {
210
- throw new Error('Invalid subject')
211
- }
212
-
213
- return payload
214
- }
215
- catch {
216
- return null
217
- }
218
- }
219
-
220
- /**
221
- * Decode a JWT token without verifying the signature
222
- */
223
- decode(token: string): { header: JwtHeader, payload: JwtPayload } | null {
224
- try {
225
- const parts = token.split('.')
226
-
227
- if (parts.length !== 3) {
228
- return null
229
- }
230
-
231
- const [encodedHeader, encodedPayload] = parts
232
-
233
- return {
234
- header: JSON.parse(base64UrlDecode(encodedHeader)),
235
- payload: JSON.parse(base64UrlDecode(encodedPayload)),
236
- }
237
- }
238
- catch {
239
- return null
240
- }
241
- }
242
-
243
- /**
244
- * Simple signature creation - Note: This is NOT secure for production
245
- * In a real app, use Bun's crypto functionality or a dedicated JWT library
246
- */
247
- private createSignature(data: string, secret: string, algorithm: string): string {
248
- // This is a placeholder. In a real implementation, you'd use
249
- // proper HMAC or RSA signing based on the algorithm.
250
- // For demonstration purposes only!
251
- return base64UrlEncode(JSON.stringify({ data, secret: secret.slice(0, 5), alg: algorithm }))
252
- }
253
-
254
- /**
255
- * Parse timespan string to seconds
256
- */
257
- private parseTimespan(timespan: string): number {
258
- const match = timespan.match(/^(\d+)\s*([smhd])$/i)
259
-
260
- if (!match) {
261
- return Number.parseInt(timespan, 10) || 0
262
- }
263
-
264
- const value = Number.parseInt(match[1], 10)
265
- const unit = match[2].toLowerCase()
266
-
267
- switch (unit) {
268
- case 's': return value
269
- case 'm': return value * 60
270
- case 'h': return value * 60 * 60
271
- case 'd': return value * 24 * 60 * 60
272
- default: return value
273
- }
274
- }
275
- }
276
-
277
- /**
278
- * API Key manager to generate, validate and handle API keys
279
- */
280
- export class ApiKeyManager {
281
- private keys: Map<string, { owner: string, scopes: string[], expiresAt?: Date }>
282
- private options: ApiKeyOptions
283
-
284
- constructor(options: ApiKeyOptions = {}) {
285
- this.keys = new Map()
286
- this.options = {
287
- source: 'header',
288
- keyName: 'X-API-Key',
289
- keyPrefix: 'bun_',
290
- ...options,
291
- }
292
- }
293
-
294
- /**
295
- * Generate a new API key
296
- */
297
- generateKey(owner: string, scopes: string[] = [], expiresIn?: number): string {
298
- // In a real implementation, use a secure random generator
299
- const key = `${this.options.keyPrefix}${this.randomString(32)}`
300
-
301
- // Store key information
302
- this.keys.set(key, {
303
- owner,
304
- scopes,
305
- expiresAt: expiresIn ? new Date(Date.now() + expiresIn * 1000) : undefined,
306
- })
307
-
308
- return key
309
- }
310
-
311
- /**
312
- * Validate an API key
313
- */
314
- validateKey(key: string, requiredScopes: string[] = []): boolean {
315
- const keyInfo = this.keys.get(key)
316
-
317
- if (!keyInfo) {
318
- return false
319
- }
320
-
321
- // Check expiration
322
- if (keyInfo.expiresAt && keyInfo.expiresAt < new Date()) {
323
- return false
324
- }
325
-
326
- // Check scopes
327
- if (requiredScopes.length > 0) {
328
- return requiredScopes.every(scope => keyInfo.scopes.includes(scope))
329
- }
330
-
331
- return true
332
- }
333
-
334
- /**
335
- * Get key information
336
- */
337
- getKeyInfo(key: string): { owner: string, scopes: string[], expiresAt?: Date } | null {
338
- return this.keys.get(key) || null
339
- }
340
-
341
- /**
342
- * Revoke an API key
343
- */
344
- revokeKey(key: string): boolean {
345
- return this.keys.delete(key)
346
- }
347
-
348
- /**
349
- * Extract API key from request based on configured source
350
- */
351
- extractFromRequest(req: EnhancedRequest): string | null {
352
- const { source, keyName } = this.options
353
-
354
- switch (source) {
355
- case 'header':
356
- return req.headers.get(keyName || 'X-API-Key') || null
357
- case 'query':
358
- return new URL(req.url).searchParams.get(keyName || 'api_key') || null
359
- case 'cookie':
360
- // Handle both Map-like cookies (with .get()) and plain object cookies
361
- if (req.cookies) {
362
- const key = keyName || 'api_key'
363
- if (typeof req.cookies.get === 'function') {
364
- return req.cookies.get(key) || null
365
- }
366
- return (req.cookies as unknown as Record<string, string>)[key] || null
367
- }
368
- return null
369
- default:
370
- return null
371
- }
372
- }
373
-
374
- /**
375
- * Generate a random string for keys
376
- */
377
- private randomString(length: number): string {
378
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
379
- let result = ''
380
-
381
- // This is a simple implementation - for production, use crypto.getRandomValues()
382
- for (let i = 0; i < length; i++) {
383
- result += chars.charAt(Math.floor(Math.random() * chars.length))
384
- }
385
-
386
- return result
387
- }
388
- }
389
-
390
- /**
391
- * OAuth2 helper for authorization code flow
392
- */
393
- export class OAuth2Helper {
394
- private config: OAuth2Config
395
-
396
- constructor(config: OAuth2Config) {
397
- this.config = config
398
- }
399
-
400
- /**
401
- * Generate authorization URL for redirect
402
- */
403
- getAuthorizationUrl(additionalParams: Record<string, string> = {}): string {
404
- const params = new URLSearchParams({
405
- client_id: this.config.clientId,
406
- redirect_uri: this.config.redirectUri,
407
- response_type: 'code',
408
- ...additionalParams,
409
- })
410
-
411
- if (this.config.scope) {
412
- params.set('scope', this.config.scope)
413
- }
414
-
415
- if (this.config.state) {
416
- params.set('state', this.config.state)
417
- }
418
-
419
- return `${this.config.authorizeUrl}?${params.toString()}`
420
- }
421
-
422
- /**
423
- * Exchange authorization code for access token
424
- */
425
- async exchangeCodeForToken(code: string): Promise<OAuth2TokenResponse> {
426
- const params = new URLSearchParams({
427
- grant_type: 'authorization_code',
428
- code,
429
- redirect_uri: this.config.redirectUri,
430
- client_id: this.config.clientId,
431
- client_secret: this.config.clientSecret,
432
- })
433
-
434
- const response = await fetch(this.config.tokenUrl, {
435
- method: 'POST',
436
- headers: {
437
- 'Content-Type': 'application/x-www-form-urlencoded',
438
- },
439
- body: params.toString(),
440
- })
441
-
442
- if (!response.ok) {
443
- throw new Error(`OAuth token exchange failed: ${response.status} ${response.statusText}`)
444
- }
445
-
446
- return await response.json() as OAuth2TokenResponse
447
- }
448
-
449
- /**
450
- * Refresh an access token using a refresh token
451
- */
452
- async refreshToken(refreshToken: string): Promise<OAuth2TokenResponse> {
453
- const params = new URLSearchParams({
454
- grant_type: 'refresh_token',
455
- refresh_token: refreshToken,
456
- client_id: this.config.clientId,
457
- client_secret: this.config.clientSecret,
458
- })
459
-
460
- const response = await fetch(this.config.tokenUrl, {
461
- method: 'POST',
462
- headers: {
463
- 'Content-Type': 'application/x-www-form-urlencoded',
464
- },
465
- body: params.toString(),
466
- })
467
-
468
- if (!response.ok) {
469
- throw new Error(`OAuth token refresh failed: ${response.status} ${response.statusText}`)
470
- }
471
-
472
- return await response.json() as OAuth2TokenResponse
473
- }
474
- }
475
-
476
- /**
477
- * Authentication helpers namespace
478
- */
479
- const Auth: {
480
- JWT: typeof JWT
481
- ApiKeyManager: typeof ApiKeyManager
482
- OAuth2Helper: typeof OAuth2Helper
483
- } = {
484
- JWT,
485
- ApiKeyManager,
486
- OAuth2Helper,
487
- }
488
-
489
- export default Auth