@stacksjs/bun-router 0.0.17 → 0.0.19

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 (153) hide show
  1. package/dist/chunk-2mx7fq49.js +4 -0
  2. package/dist/chunk-a8p83068.js +103 -0
  3. package/dist/{chunk-cgptvjdf.js → chunk-y3xq6wq6.js} +1 -1
  4. package/dist/cli.js +4 -3
  5. package/dist/container/index.js +1149 -211
  6. package/dist/container/service-provider.d.ts +3 -3
  7. package/dist/development/performance-profiler.d.ts +3 -3
  8. package/dist/development/route-debugger.d.ts +1 -1
  9. package/dist/development/route-inspector.d.ts +2 -2
  10. package/dist/index.js +369 -2209
  11. package/dist/observability/integration.d.ts +1 -1
  12. package/dist/response/macros.d.ts +1 -1
  13. package/dist/router/index.d.ts +7 -7
  14. package/dist/router/router.d.ts +0 -32
  15. package/dist/testing/performance-testing.d.ts +2 -2
  16. package/dist/testing/test-client.d.ts +1 -1
  17. package/dist/testing/websocket-testing.d.ts +1 -1
  18. package/package.json +7 -7
  19. package/dist/chunk-1ahs68ys.js +0 -18
  20. package/dist/chunk-g3ybefhg.js +0 -1923
  21. package/src/auth.ts +0 -489
  22. package/src/cache/lru-cache.ts +0 -457
  23. package/src/cache/middleware-memoization.ts +0 -531
  24. package/src/cache/route-cache-warmer.ts +0 -486
  25. package/src/cache/sqlite-cache.ts +0 -783
  26. package/src/cache/streaming-cache.ts +0 -572
  27. package/src/cli/colors.ts +0 -29
  28. package/src/cli/index.ts +0 -287
  29. package/src/cli/middleware.ts +0 -291
  30. package/src/cli/openapi.ts +0 -407
  31. package/src/cli/router.ts +0 -188
  32. package/src/cli/routes.ts +0 -265
  33. package/src/cli/utils.ts +0 -531
  34. package/src/cli.ts +0 -5
  35. package/src/config.ts +0 -322
  36. package/src/container/container.ts +0 -786
  37. package/src/container/contextual-binding.ts +0 -606
  38. package/src/container/decorators.ts +0 -368
  39. package/src/container/index.ts +0 -49
  40. package/src/container/service-provider.ts +0 -596
  41. package/src/development/hot-reload.ts +0 -673
  42. package/src/development/index.ts +0 -499
  43. package/src/development/performance-profiler.ts +0 -717
  44. package/src/development/route-debugger.ts +0 -527
  45. package/src/development/route-inspector.ts +0 -749
  46. package/src/development/typescript-utilities.ts +0 -682
  47. package/src/docs.ts +0 -397
  48. package/src/errors/circuit-breaker.ts +0 -733
  49. package/src/errors/error-handler.ts +0 -569
  50. package/src/errors/error-reporting.ts +0 -672
  51. package/src/errors/exceptions.ts +0 -536
  52. package/src/errors/graceful-degradation.ts +0 -623
  53. package/src/errors/index.ts +0 -21
  54. package/src/errors/router-errors.ts +0 -632
  55. package/src/file-serving/static-files.ts +0 -718
  56. package/src/index.ts +0 -66
  57. package/src/middleware/auth.ts +0 -220
  58. package/src/middleware/content_security_policy.ts +0 -215
  59. package/src/middleware/cors.ts +0 -142
  60. package/src/middleware/csrf.ts +0 -166
  61. package/src/middleware/ddos_protection.ts +0 -279
  62. package/src/middleware/file_security.ts +0 -191
  63. package/src/middleware/file_upload.ts +0 -275
  64. package/src/middleware/helmet.ts +0 -268
  65. package/src/middleware/index.ts +0 -117
  66. package/src/middleware/input_validation.ts +0 -453
  67. package/src/middleware/json_body.ts +0 -37
  68. package/src/middleware/performance_alerting.ts +0 -540
  69. package/src/middleware/performance_dashboard.ts +0 -661
  70. package/src/middleware/performance_monitor.ts +0 -945
  71. package/src/middleware/pipeline.ts +0 -489
  72. package/src/middleware/rate_limit.ts +0 -251
  73. package/src/middleware/request_id.ts +0 -36
  74. package/src/middleware/request_signing.ts +0 -638
  75. package/src/middleware/request_tracer.ts +0 -653
  76. package/src/middleware/response_cache.ts +0 -778
  77. package/src/middleware/security.ts +0 -482
  78. package/src/middleware/security_suite.ts +0 -257
  79. package/src/middleware/session.ts +0 -91
  80. package/src/model-binding/index.ts +0 -18
  81. package/src/model-binding/model-middleware.ts +0 -425
  82. package/src/model-binding/model-registry.ts +0 -550
  83. package/src/model-binding.ts +0 -370
  84. package/src/model-resolver-factory.ts +0 -106
  85. package/src/observability/correlation.ts +0 -691
  86. package/src/observability/health-checks.ts +0 -729
  87. package/src/observability/index.ts +0 -184
  88. package/src/observability/integration.ts +0 -548
  89. package/src/observability/metrics.ts +0 -753
  90. package/src/observability/tracing.ts +0 -638
  91. package/src/optimization/bun-utilities.ts +0 -778
  92. package/src/query-builder-integration.ts +0 -137
  93. package/src/request/context.ts +0 -109
  94. package/src/request/enhanced-request.ts +0 -876
  95. package/src/request/macros.ts +0 -822
  96. package/src/response/macros.ts +0 -665
  97. package/src/response/response-factory.ts +0 -596
  98. package/src/router/api-routes.ts +0 -243
  99. package/src/router/file-based-routing.ts +0 -697
  100. package/src/router/file-streaming.ts +0 -383
  101. package/src/router/fluent-routing.ts +0 -866
  102. package/src/router/group-organization.ts +0 -229
  103. package/src/router/handler-resolver.ts +0 -327
  104. package/src/router/http-methods.ts +0 -407
  105. package/src/router/index.ts +0 -193
  106. package/src/router/middleware-groups.ts +0 -222
  107. package/src/router/middleware-integration.ts +0 -399
  108. package/src/router/middleware.ts +0 -234
  109. package/src/router/model-binding.ts +0 -215
  110. package/src/router/optimized-route-matching.ts +0 -302
  111. package/src/router/route-building.ts +0 -221
  112. package/src/router/route-compiler.ts +0 -691
  113. package/src/router/route-matching.ts +0 -368
  114. package/src/router/route-trie.ts +0 -450
  115. package/src/router/router.ts +0 -1616
  116. package/src/router/server.ts +0 -684
  117. package/src/router/validation-integration.ts +0 -449
  118. package/src/router/view-rendering.ts +0 -233
  119. package/src/router/websocket.ts +0 -100
  120. package/src/routing/route-caching.ts +0 -402
  121. package/src/routing/route-throttling.ts +0 -469
  122. package/src/routing/subdomain-routing.ts +0 -492
  123. package/src/session/database-store.ts +0 -109
  124. package/src/session/file-store.ts +0 -148
  125. package/src/session/index.ts +0 -244
  126. package/src/session/memory-store.ts +0 -88
  127. package/src/session/redis-store.ts +0 -93
  128. package/src/streaming/index.ts +0 -17
  129. package/src/streaming/sse-handler.ts +0 -482
  130. package/src/streaming/stream-handler.ts +0 -552
  131. package/src/testing/auth-testing.ts +0 -448
  132. package/src/testing/file-upload-testing.ts +0 -543
  133. package/src/testing/index.ts +0 -10
  134. package/src/testing/middleware-testing.ts +0 -322
  135. package/src/testing/model-binding-testing.ts +0 -645
  136. package/src/testing/performance-testing.ts +0 -738
  137. package/src/testing/test-client.ts +0 -310
  138. package/src/testing/test-request.ts +0 -315
  139. package/src/testing/test-response.ts +0 -332
  140. package/src/testing/types.ts +0 -224
  141. package/src/testing/websocket-testing.ts +0 -590
  142. package/src/types/controller-types.ts +0 -385
  143. package/src/types/core.ts +0 -683
  144. package/src/types/middleware-types.ts +0 -422
  145. package/src/types/request-response-augmentation.ts +0 -489
  146. package/src/types/route-inference.ts +0 -372
  147. package/src/types.ts +0 -2123
  148. package/src/url.ts +0 -131
  149. package/src/utils/index.ts +0 -1
  150. package/src/utils/query-preservation.ts +0 -201
  151. package/src/utils.ts +0 -395
  152. package/src/validation/validator.ts +0 -688
  153. 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