@stacksjs/bun-router 0.0.16 → 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 (176) hide show
  1. package/dist/auth.d.ts +22 -8
  2. package/dist/chunk-1ahs68ys.js +18 -0
  3. package/dist/{chunk-0145g1me.js → chunk-cgptvjdf.js} +147 -75
  4. package/dist/chunk-g3ybefhg.js +1923 -0
  5. package/dist/cli.js +3 -2
  6. package/dist/container/container.d.ts +1 -0
  7. package/dist/container/contextual-binding.d.ts +0 -1
  8. package/dist/container/decorators.d.ts +2 -5
  9. package/dist/container/index.d.ts +16 -0
  10. package/dist/container/index.js +322 -0
  11. package/dist/container/service-provider.d.ts +3 -3
  12. package/dist/development/performance-profiler.d.ts +3 -3
  13. package/dist/development/route-debugger.d.ts +1 -1
  14. package/dist/development/route-inspector.d.ts +2 -2
  15. package/dist/file-serving/static-files.d.ts +16 -0
  16. package/dist/index.d.ts +17 -1
  17. package/dist/index.js +1159 -1380
  18. package/dist/middleware/cors.d.ts +9 -0
  19. package/dist/middleware/csrf.d.ts +7 -0
  20. package/dist/middleware/ddos_protection.d.ts +16 -1
  21. package/dist/middleware/rate_limit.d.ts +7 -1
  22. package/dist/middleware/request_tracer.d.ts +15 -9
  23. package/dist/middleware/response_cache.d.ts +2 -1
  24. package/dist/observability/integration.d.ts +1 -1
  25. package/dist/request/context.d.ts +12 -1
  26. package/dist/request/macros.d.ts +40 -2
  27. package/dist/response/macros.d.ts +4 -4
  28. package/dist/router/fluent-routing.d.ts +50 -13
  29. package/dist/router/handler-resolver.d.ts +8 -0
  30. package/dist/router/index.d.ts +9 -7
  31. package/dist/router/route-compiler.d.ts +8 -10
  32. package/dist/router/route-trie.d.ts +7 -1
  33. package/dist/router/router.d.ts +13 -34
  34. package/dist/router/validation-integration.d.ts +10 -4
  35. package/dist/testing/performance-testing.d.ts +2 -2
  36. package/dist/testing/test-client.d.ts +1 -1
  37. package/dist/testing/websocket-testing.d.ts +1 -1
  38. package/dist/types/middleware-types.d.ts +1 -1
  39. package/dist/types/route-inference.d.ts +9 -2
  40. package/dist/types.d.ts +62 -9
  41. package/dist/utils.d.ts +1 -1
  42. package/package.json +12 -3
  43. package/dist/router/fluent-router.d.ts +0 -315
  44. package/src/auth.ts +0 -469
  45. package/src/cache/lru-cache.ts +0 -457
  46. package/src/cache/middleware-memoization.ts +0 -531
  47. package/src/cache/route-cache-warmer.ts +0 -486
  48. package/src/cache/sqlite-cache.ts +0 -783
  49. package/src/cache/streaming-cache.ts +0 -572
  50. package/src/cli/colors.ts +0 -29
  51. package/src/cli/index.ts +0 -287
  52. package/src/cli/middleware.ts +0 -291
  53. package/src/cli/openapi.ts +0 -407
  54. package/src/cli/router.ts +0 -188
  55. package/src/cli/routes.ts +0 -265
  56. package/src/cli/utils.ts +0 -531
  57. package/src/cli.ts +0 -5
  58. package/src/config.ts +0 -322
  59. package/src/container/container.ts +0 -740
  60. package/src/container/contextual-binding.ts +0 -603
  61. package/src/container/decorators.ts +0 -359
  62. package/src/container/service-provider.ts +0 -596
  63. package/src/development/hot-reload.ts +0 -673
  64. package/src/development/index.ts +0 -499
  65. package/src/development/performance-profiler.ts +0 -717
  66. package/src/development/route-debugger.ts +0 -527
  67. package/src/development/route-inspector.ts +0 -749
  68. package/src/development/typescript-utilities.ts +0 -682
  69. package/src/docs.ts +0 -397
  70. package/src/errors/circuit-breaker.ts +0 -732
  71. package/src/errors/error-handler.ts +0 -569
  72. package/src/errors/error-reporting.ts +0 -672
  73. package/src/errors/exceptions.ts +0 -536
  74. package/src/errors/graceful-degradation.ts +0 -621
  75. package/src/errors/index.ts +0 -21
  76. package/src/errors/router-errors.ts +0 -632
  77. package/src/file-serving/static-files.ts +0 -581
  78. package/src/index.ts +0 -14
  79. package/src/middleware/auth.ts +0 -220
  80. package/src/middleware/content_security_policy.ts +0 -215
  81. package/src/middleware/cors.ts +0 -74
  82. package/src/middleware/csrf.ts +0 -118
  83. package/src/middleware/ddos_protection.ts +0 -255
  84. package/src/middleware/file_security.ts +0 -191
  85. package/src/middleware/file_upload.ts +0 -275
  86. package/src/middleware/helmet.ts +0 -268
  87. package/src/middleware/index.ts +0 -117
  88. package/src/middleware/input_validation.ts +0 -449
  89. package/src/middleware/json_body.ts +0 -37
  90. package/src/middleware/performance_alerting.ts +0 -538
  91. package/src/middleware/performance_dashboard.ts +0 -661
  92. package/src/middleware/performance_monitor.ts +0 -943
  93. package/src/middleware/pipeline.ts +0 -489
  94. package/src/middleware/rate_limit.ts +0 -245
  95. package/src/middleware/request_id.ts +0 -36
  96. package/src/middleware/request_signing.ts +0 -636
  97. package/src/middleware/request_tracer.ts +0 -636
  98. package/src/middleware/response_cache.ts +0 -743
  99. package/src/middleware/security.ts +0 -482
  100. package/src/middleware/security_suite.ts +0 -257
  101. package/src/middleware/session.ts +0 -91
  102. package/src/model-binding/index.ts +0 -18
  103. package/src/model-binding/model-middleware.ts +0 -425
  104. package/src/model-binding/model-registry.ts +0 -550
  105. package/src/model-binding.ts +0 -370
  106. package/src/model-resolver-factory.ts +0 -106
  107. package/src/observability/correlation.ts +0 -691
  108. package/src/observability/health-checks.ts +0 -729
  109. package/src/observability/index.ts +0 -184
  110. package/src/observability/integration.ts +0 -548
  111. package/src/observability/metrics.ts +0 -753
  112. package/src/observability/tracing.ts +0 -638
  113. package/src/optimization/bun-utilities.ts +0 -778
  114. package/src/query-builder-integration.ts +0 -137
  115. package/src/request/context.ts +0 -62
  116. package/src/request/enhanced-request.ts +0 -857
  117. package/src/request/macros.ts +0 -688
  118. package/src/response/macros.ts +0 -665
  119. package/src/response/response-factory.ts +0 -596
  120. package/src/router/api-routes.ts +0 -243
  121. package/src/router/file-based-routing.ts +0 -690
  122. package/src/router/file-streaming.ts +0 -383
  123. package/src/router/fluent-router.ts +0 -927
  124. package/src/router/fluent-routing.ts +0 -797
  125. package/src/router/group-organization.ts +0 -213
  126. package/src/router/handler-resolver.ts +0 -291
  127. package/src/router/http-methods.ts +0 -377
  128. package/src/router/index.ts +0 -187
  129. package/src/router/middleware-groups.ts +0 -222
  130. package/src/router/middleware-integration.ts +0 -399
  131. package/src/router/middleware.ts +0 -231
  132. package/src/router/model-binding.ts +0 -215
  133. package/src/router/optimized-route-matching.ts +0 -253
  134. package/src/router/route-building.ts +0 -221
  135. package/src/router/route-compiler.ts +0 -702
  136. package/src/router/route-matching.ts +0 -349
  137. package/src/router/route-trie.ts +0 -464
  138. package/src/router/router.ts +0 -1604
  139. package/src/router/server.ts +0 -462
  140. package/src/router/validation-integration.ts +0 -443
  141. package/src/router/view-rendering.ts +0 -233
  142. package/src/router/websocket.ts +0 -100
  143. package/src/routing/route-caching.ts +0 -402
  144. package/src/routing/route-throttling.ts +0 -469
  145. package/src/routing/subdomain-routing.ts +0 -492
  146. package/src/session/database-store.ts +0 -109
  147. package/src/session/file-store.ts +0 -148
  148. package/src/session/index.ts +0 -244
  149. package/src/session/memory-store.ts +0 -88
  150. package/src/session/redis-store.ts +0 -93
  151. package/src/streaming/index.ts +0 -17
  152. package/src/streaming/sse-handler.ts +0 -482
  153. package/src/streaming/stream-handler.ts +0 -552
  154. package/src/testing/auth-testing.ts +0 -446
  155. package/src/testing/file-upload-testing.ts +0 -543
  156. package/src/testing/index.ts +0 -10
  157. package/src/testing/middleware-testing.ts +0 -322
  158. package/src/testing/model-binding-testing.ts +0 -645
  159. package/src/testing/performance-testing.ts +0 -738
  160. package/src/testing/test-client.ts +0 -310
  161. package/src/testing/test-request.ts +0 -315
  162. package/src/testing/test-response.ts +0 -332
  163. package/src/testing/types.ts +0 -224
  164. package/src/testing/websocket-testing.ts +0 -590
  165. package/src/types/controller-types.ts +0 -385
  166. package/src/types/core.ts +0 -683
  167. package/src/types/middleware-types.ts +0 -419
  168. package/src/types/request-response-augmentation.ts +0 -489
  169. package/src/types/route-inference.ts +0 -357
  170. package/src/types.ts +0 -2067
  171. package/src/url.ts +0 -126
  172. package/src/utils/index.ts +0 -1
  173. package/src/utils/query-preservation.ts +0 -201
  174. package/src/utils.ts +0 -392
  175. package/src/validation/validator.ts +0 -685
  176. package/src/websocket/clustering.ts +0 -762
@@ -1,443 +0,0 @@
1
- /**
2
- * Router Validation Integration
3
- *
4
- * Integration layer for validation and macros with the router.
5
- * Provides RouteBuilder and FluentRouter for building routes with validation support.
6
- */
7
-
8
- import type { EnhancedRequest, MiddlewareHandler, NextFunction, RouteHandler } from '../types'
9
- import type { ValidationRules, ValidatorConfig } from '../validation/validator'
10
- import { RequestWithMacros } from '../request/macros'
11
- import { ResponseWithMacros } from '../response/macros'
12
- import { createValidationMiddleware } from '../validation/validator'
13
-
14
- /**
15
- * Route builder with validation support
16
- */
17
- export class RouteBuilder {
18
- private validationRules?: ValidationRules
19
- private validatorConfig?: ValidatorConfig
20
-
21
- constructor(
22
- private method: string,
23
- private path: string,
24
- private handler: RouteHandler,
25
- ) {}
26
-
27
- /**
28
- * Add validation to the route
29
- */
30
- validate(rules: ValidationRules, config?: ValidatorConfig): this {
31
- this.validationRules = rules
32
- this.validatorConfig = config
33
- return this
34
- }
35
-
36
- /**
37
- * Build the route with middleware
38
- */
39
- build(): { method: string, path: string, handler: RouteHandler, middleware?: MiddlewareHandler[] } {
40
- const middleware: MiddlewareHandler[] = []
41
-
42
- // Add validation middleware if rules are provided
43
- if (this.validationRules) {
44
- middleware.push(createValidationMiddleware(this.validationRules, this.validatorConfig))
45
- }
46
-
47
- // Add request macro middleware
48
- middleware.push(async (req: EnhancedRequest, next: NextFunction) => {
49
- // Apply request macros
50
- RequestWithMacros.applyMacros(req)
51
- const result = await next()
52
- return result || new Response('Not Found', { status: 404 })
53
- })
54
-
55
- return {
56
- method: this.method,
57
- path: this.path,
58
- handler: this.handler,
59
- middleware: middleware.length > 0 ? middleware : undefined,
60
- }
61
- }
62
- }
63
-
64
- /**
65
- * Fluent router for enhanced routing functionality
66
- */
67
- export class FluentRouter {
68
- private routes: Array<{
69
- method: string
70
- path: string
71
- handler: RouteHandler
72
- middleware?: MiddlewareHandler[]
73
- }> = []
74
-
75
- /**
76
- * Create GET route
77
- */
78
- get(path: string, handler: RouteHandler): RouteBuilder {
79
- return new RouteBuilder('GET', path, handler)
80
- }
81
-
82
- /**
83
- * Create POST route
84
- */
85
- post(path: string, handler: RouteHandler): RouteBuilder {
86
- return new RouteBuilder('POST', path, handler)
87
- }
88
-
89
- /**
90
- * Create PUT route
91
- */
92
- put(path: string, handler: RouteHandler): RouteBuilder {
93
- return new RouteBuilder('PUT', path, handler)
94
- }
95
-
96
- /**
97
- * Create PATCH route
98
- */
99
- patch(path: string, handler: RouteHandler): RouteBuilder {
100
- return new RouteBuilder('PATCH', path, handler)
101
- }
102
-
103
- /**
104
- * Create DELETE route
105
- */
106
- delete(path: string, handler: RouteHandler): RouteBuilder {
107
- return new RouteBuilder('DELETE', path, handler)
108
- }
109
-
110
- /**
111
- * Register a built route
112
- */
113
- register(routeBuilder: RouteBuilder): void {
114
- const route = routeBuilder.build()
115
- this.routes.push(route)
116
- }
117
-
118
- /**
119
- * Get all registered routes
120
- */
121
- getRoutes(): Array<{
122
- method: string
123
- path: string
124
- handler: RouteHandler
125
- middleware?: MiddlewareHandler[]
126
- }> {
127
- return this.routes
128
- }
129
- }
130
-
131
- /**
132
- * Router middleware factory for request/response enhancements
133
- */
134
- export function createEnhancementMiddleware() {
135
- return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
136
- // Apply request macros
137
- RequestWithMacros.applyMacros(req)
138
-
139
- // Add start time for age calculation
140
- ;(req as any).startTime = Date.now()
141
-
142
- return await next()
143
- }
144
- }
145
-
146
- /**
147
- * Validation middleware factory with fluent API
148
- */
149
- export class ValidationMiddlewareBuilder {
150
- private rules: ValidationRules = {}
151
- private config: ValidatorConfig = {}
152
-
153
- /**
154
- * Add validation rule for field
155
- */
156
- field(name: string, rules: string): this {
157
- this.rules[name] = rules
158
- return this
159
- }
160
-
161
- /**
162
- * Add multiple validation rules
163
- */
164
- fields(rules: ValidationRules): this {
165
- Object.assign(this.rules, rules)
166
- return this
167
- }
168
-
169
- /**
170
- * Set validator configuration
171
- */
172
- configure(config: ValidatorConfig): this {
173
- Object.assign(this.config, config)
174
- return this
175
- }
176
-
177
- /**
178
- * Stop on first validation failure
179
- */
180
- stopOnFirstFailure(): this {
181
- this.config.stopOnFirstFailure = true
182
- return this
183
- }
184
-
185
- /**
186
- * Set custom error messages
187
- */
188
- messages(messages: Record<string, string>): this {
189
- this.config.customMessages = messages
190
- return this
191
- }
192
-
193
- /**
194
- * Set custom field attributes
195
- */
196
- attributes(attributes: Record<string, string>): this {
197
- this.config.customAttributes = attributes
198
- return this
199
- }
200
-
201
- /**
202
- * Build the validation middleware
203
- */
204
- build(): MiddlewareHandler {
205
- return createValidationMiddleware(this.rules, this.config)
206
- }
207
- }
208
-
209
- /**
210
- * Factory function to create validation middleware builder
211
- */
212
- export function validate(): ValidationMiddlewareBuilder {
213
- return new ValidationMiddlewareBuilder()
214
- }
215
-
216
- /** Resource handlers configuration */
217
- export interface ResourceHandlers {
218
- index?: RouteHandler
219
- show?: RouteHandler
220
- store?: RouteHandler
221
- update?: RouteHandler
222
- destroy?: RouteHandler
223
- }
224
-
225
- /** Resource validation configuration */
226
- export interface ResourceValidation {
227
- store?: ValidationRules
228
- update?: ValidationRules
229
- }
230
-
231
- /**
232
- * Route helper functions
233
- */
234
- export const RouteHelpers: {
235
- validated: (method: string, path: string, handler: RouteHandler, rules: ValidationRules, config?: ValidatorConfig) => RouteBuilder
236
- apiRoute: (method: string, path: string, handler: RouteHandler, rules?: ValidationRules) => RouteBuilder
237
- resourceRoute: (basePath: string, handlers: ResourceHandlers, validation?: ResourceValidation) => RouteBuilder[]
238
- } = {
239
- /**
240
- * Create validated route
241
- */
242
- validated: (
243
- method: string,
244
- path: string,
245
- handler: RouteHandler,
246
- rules: ValidationRules,
247
- config?: ValidatorConfig,
248
- ): RouteBuilder => {
249
- const builder = new RouteBuilder(method, path, handler)
250
- return builder.validate(rules, config)
251
- },
252
-
253
- /**
254
- * Create API route with JSON validation
255
- */
256
- apiRoute: (
257
- method: string,
258
- path: string,
259
- handler: RouteHandler,
260
- rules?: ValidationRules,
261
- ): RouteBuilder => {
262
- const builder = new RouteBuilder(method, path, async (req): Promise<Response> => {
263
- // Ensure request expects JSON
264
- if (!req.expectsJson()) {
265
- return ResponseWithMacros.callMacro('error', 'API endpoint requires JSON Accept header', undefined, 406)
266
- }
267
-
268
- return await handler(req)
269
- })
270
-
271
- if (rules) {
272
- builder.validate(rules)
273
- }
274
-
275
- return builder
276
- },
277
-
278
- /**
279
- * Create resource route with validation
280
- */
281
- resourceRoute: (
282
- basePath: string,
283
- handlers: ResourceHandlers,
284
- validation?: ResourceValidation,
285
- ): RouteBuilder[] => {
286
- const routes: RouteBuilder[] = []
287
-
288
- if (handlers.index) {
289
- routes.push(new RouteBuilder('GET', basePath, handlers.index))
290
- }
291
-
292
- if (handlers.show) {
293
- routes.push(new RouteBuilder('GET', `${basePath}/{id}`, handlers.show))
294
- }
295
-
296
- if (handlers.store) {
297
- const builder = new RouteBuilder('POST', basePath, handlers.store)
298
- if (validation?.store) {
299
- builder.validate(validation.store)
300
- }
301
- routes.push(builder)
302
- }
303
-
304
- if (handlers.update) {
305
- const builder = new RouteBuilder('PUT', `${basePath}/{id}`, handlers.update)
306
- if (validation?.update) {
307
- builder.validate(validation.update)
308
- }
309
- routes.push(builder)
310
- }
311
-
312
- if (handlers.destroy) {
313
- routes.push(new RouteBuilder('DELETE', `${basePath}/{id}`, handlers.destroy))
314
- }
315
-
316
- return routes
317
- },
318
- }
319
-
320
- /**
321
- * Fluent router factory
322
- */
323
- export function createFluentRouter(): FluentRouter {
324
- return new FluentRouter()
325
- }
326
-
327
- /**
328
- * Middleware composition helpers
329
- */
330
- export const MiddlewareHelpers = {
331
- /**
332
- * Compose multiple middleware into one
333
- */
334
- compose: (...middleware: MiddlewareHandler[]): MiddlewareHandler => {
335
- return async (req: EnhancedRequest, next: NextFunction): Promise<Response | null> => {
336
- let index = 0
337
-
338
- const dispatch = async (): Promise<Response | null> => {
339
- if (index >= middleware.length) {
340
- return await next()
341
- }
342
-
343
- const currentMiddleware = middleware[index++]
344
- return await currentMiddleware(req, dispatch)
345
- }
346
-
347
- return await dispatch()
348
- }
349
- },
350
-
351
- /**
352
- * Create conditional middleware
353
- */
354
- when: (
355
- condition: (req: EnhancedRequest) => boolean,
356
- middleware: MiddlewareHandler,
357
- ): MiddlewareHandler => {
358
- return async (req: EnhancedRequest, next: NextFunction): Promise<Response | null> => {
359
- if (condition(req)) {
360
- return await middleware(req, next)
361
- }
362
- return await next()
363
- }
364
- },
365
-
366
- /**
367
- * Create middleware that runs unless condition is met
368
- */
369
- unless: (
370
- condition: (req: EnhancedRequest) => boolean,
371
- middleware: MiddlewareHandler,
372
- ): MiddlewareHandler => {
373
- return MiddlewareHelpers.when(req => !condition(req), middleware)
374
- },
375
-
376
- /**
377
- * Create middleware group
378
- */
379
- group: (middleware: MiddlewareHandler[]): MiddlewareHandler => {
380
- return MiddlewareHelpers.compose(...middleware)
381
- },
382
- }
383
-
384
- /** Enhancement middleware type */
385
- export type EnhancementMiddleware = (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response>
386
-
387
- /**
388
- * Request/Response enhancement presets
389
- */
390
- export const EnhancementPresets: {
391
- api: () => EnhancementMiddleware[]
392
- web: () => EnhancementMiddleware[]
393
- validation: (rules: ValidationRules, config?: ValidatorConfig) => EnhancementMiddleware[]
394
- } = {
395
- /**
396
- * API preset with JSON validation and response macros
397
- */
398
- api: (): EnhancementMiddleware[] => [
399
- createEnhancementMiddleware(),
400
- async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
401
- try {
402
- const response = await next()
403
-
404
- // Add API headers
405
- const headers = new Headers(response.headers)
406
- headers.set('X-API-Version', '1.0')
407
- headers.set('X-Response-Time', new Date().toISOString())
408
-
409
- return new Response(response.body, {
410
- status: response.status,
411
- statusText: response.statusText,
412
- headers,
413
- })
414
- }
415
- catch (error) {
416
- console.error(error)
417
- // Return JSON error response
418
- return ResponseWithMacros.callMacro('error', 'Internal server error', undefined, 500)
419
- }
420
- },
421
- ],
422
-
423
- /**
424
- * Web preset with request enhancements and CSRF protection
425
- */
426
- web: (): EnhancementMiddleware[] => [
427
- createEnhancementMiddleware(),
428
- async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
429
- // Add web-specific enhancements
430
- ;(req as any).session = {} // Placeholder for session
431
-
432
- return await next()
433
- },
434
- ],
435
-
436
- /**
437
- * Validation preset with comprehensive validation
438
- */
439
- validation: (rules: ValidationRules, config?: ValidatorConfig): EnhancementMiddleware[] => [
440
- createEnhancementMiddleware(),
441
- createValidationMiddleware(rules, config) as EnhancementMiddleware,
442
- ],
443
- }
@@ -1,233 +0,0 @@
1
- import type { ActionHandler, EnhancedRequest, RouterConfig } from '../types'
2
- import type { Router } from './router'
3
- import { join } from 'node:path'
4
- import { processHtmlTemplate, resolveViewPath, injectQueryPreservationScript } from '../utils'
5
-
6
- /**
7
- * View rendering extension for Router class
8
- */
9
- export function registerViewRendering(RouterClass: typeof Router): void {
10
- Object.defineProperties(RouterClass.prototype, {
11
- /**
12
- * Render a view with data
13
- */
14
- renderView: {
15
- async value(
16
- view: string,
17
- data: Record<string, any> = {},
18
- options: { layout?: string } = {},
19
- ): Promise<string> {
20
- const viewsConfig = this.config.views || {
21
- viewsPath: 'resources/views',
22
- extensions: ['.html', '.stx'],
23
- cache: Bun.env.NODE_ENV === 'production',
24
- engine: 'auto',
25
- }
26
-
27
- // Check cache first if enabled
28
- const cacheKey = `${view}:${options.layout || ''}`
29
- if (viewsConfig.cache && this.templateCache.has(cacheKey)) {
30
- return this.processTemplate(this.templateCache.get(cacheKey)!, data, viewsConfig)
31
- }
32
-
33
- // Resolve the view path
34
- const viewPath = await resolveViewPath(view, viewsConfig.viewsPath, viewsConfig.extensions)
35
- if (!viewPath) {
36
- throw new Error(`View '${view}' not found`)
37
- }
38
-
39
- // Read the view file
40
- let viewContent = await Bun.file(viewPath).text()
41
-
42
- // Apply layout if specified or if a default layout is configured
43
- const layoutName = options.layout || viewsConfig.defaultLayout
44
- if (layoutName) {
45
- const layoutPath = await resolveViewPath(
46
- join('layouts', layoutName),
47
- viewsConfig.viewsPath,
48
- viewsConfig.extensions,
49
- )
50
-
51
- if (!layoutPath) {
52
- throw new Error(`Layout '${layoutName}' not found`)
53
- }
54
-
55
- const layoutContent = await Bun.file(layoutPath).text()
56
- // Replace {{content}} placeholder with the view content
57
- viewContent = layoutContent.replace(/\{\{\s*content\s*\}\}/g, viewContent)
58
- }
59
-
60
- // Cache the template if caching is enabled
61
- if (viewsConfig.cache) {
62
- this.templateCache.set(cacheKey, viewContent)
63
- }
64
-
65
- // Process the template with data
66
- return this.processTemplate(viewContent, data, viewsConfig)
67
- },
68
- writable: true,
69
- configurable: true,
70
- },
71
-
72
- /**
73
- * Process a template with data
74
- */
75
- processTemplate: {
76
- async value(
77
- template: string,
78
- data: Record<string, any>,
79
- viewConfig: RouterConfig['views'],
80
- ): Promise<string> {
81
- // Choose template engine based on configuration
82
- const engine = viewConfig?.engine || 'auto'
83
-
84
- if (engine === 'custom' && viewConfig?.customRenderer) {
85
- return viewConfig.customRenderer(template, data, {})
86
- }
87
-
88
- // Default to simple template processing
89
- let processedTemplate = processHtmlTemplate(template, data)
90
-
91
- // Apply minification if configured
92
- if (viewConfig?.minify?.enabled) {
93
- try {
94
- const _minifyOptions = viewConfig.minify.options || {
95
- removeComments: true,
96
- collapseWhitespace: true,
97
- minifyJS: true,
98
- minifyCSS: true,
99
- }
100
-
101
- // In a real implementation, you would use a library like html-minifier
102
- // This is just a placeholder
103
- processedTemplate = processedTemplate
104
- .replace(/\s+/g, ' ')
105
- .replace(/<!--[\s\S]*?-->/g, '')
106
- }
107
- catch (err) {
108
- console.error('Error minifying HTML:', err)
109
- }
110
- }
111
-
112
- return processedTemplate
113
- },
114
- writable: true,
115
- configurable: true,
116
- },
117
-
118
- /**
119
- * Register a view route
120
- */
121
- view: {
122
- value(
123
- path: string,
124
- viewOrData: string | Record<string, any>,
125
- dataOrOptions: Record<string, any> | { layout?: string, status?: number, headers?: Record<string, string> } = {},
126
- optionsOrType: { layout?: string, status?: number, headers?: Record<string, string> } | 'web' | 'api' = {},
127
- typeOrName: 'web' | 'api' | string = 'web',
128
- name?: string,
129
- ): Router {
130
- let view: string
131
- let data: Record<string, any> = {}
132
- let options: { layout?: string, status?: number, headers?: Record<string, string> } = {}
133
- let type: 'web' | 'api' = 'web'
134
- let routeName: string | undefined
135
-
136
- // Parse the flexible parameters
137
- if (typeof viewOrData === 'string') {
138
- view = viewOrData
139
-
140
- if (typeof dataOrOptions === 'object' && !Array.isArray(dataOrOptions)) {
141
- // If dataOrOptions has layout, status, or headers, it's options
142
- if ('layout' in dataOrOptions || 'status' in dataOrOptions || 'headers' in dataOrOptions) {
143
- options = dataOrOptions as { layout?: string, status?: number, headers?: Record<string, string> }
144
- }
145
- else {
146
- // Otherwise it's data
147
- data = dataOrOptions
148
- }
149
- }
150
-
151
- if (typeof optionsOrType === 'object') {
152
- options = { ...options, ...optionsOrType }
153
- }
154
- else if (typeof optionsOrType === 'string') {
155
- type = optionsOrType as 'web' | 'api'
156
- }
157
-
158
- if (typeof typeOrName === 'string') {
159
- if (typeOrName === 'web' || typeOrName === 'api') {
160
- type = typeOrName
161
- }
162
- else {
163
- routeName = typeOrName
164
- }
165
- }
166
-
167
- if (name) {
168
- routeName = name
169
- }
170
- }
171
- else {
172
- // viewOrData is actually data
173
- data = viewOrData
174
-
175
- if (typeof dataOrOptions === 'string') {
176
- view = dataOrOptions
177
- }
178
- else {
179
- throw new TypeError('View name must be a string')
180
- }
181
-
182
- if (typeof optionsOrType === 'object') {
183
- options = optionsOrType
184
- }
185
- else if (typeof optionsOrType === 'string') {
186
- if (optionsOrType === 'web' || optionsOrType === 'api') {
187
- type = optionsOrType
188
- }
189
- else {
190
- view = optionsOrType
191
- type = 'web'
192
- }
193
- }
194
- }
195
-
196
- // Create the route handler
197
- const handler: ActionHandler = async (_req: EnhancedRequest) => {
198
- let renderedView = await this.renderView(view, data, {
199
- layout: options.layout,
200
- })
201
-
202
- // Inject query preservation script if configured
203
- const queryPreservationConfig = this.config?.queryPreservation
204
- if (queryPreservationConfig?.enabled !== false && queryPreservationConfig?.preserve?.length) {
205
- renderedView = injectQueryPreservationScript(renderedView, queryPreservationConfig)
206
- }
207
-
208
- const headers = new Headers()
209
- headers.set('Content-Type', 'text/html; charset=utf-8')
210
-
211
- // Add custom headers if provided
212
- if (options.headers) {
213
- for (const [key, value] of Object.entries(options.headers)) {
214
- headers.set(key, value)
215
- }
216
- }
217
-
218
- return new Response(renderedView, {
219
- status: options.status || 200,
220
- headers,
221
- })
222
- }
223
-
224
- // Register the route
225
- this.get(path, handler, type, routeName)
226
-
227
- return this
228
- },
229
- writable: true,
230
- configurable: true,
231
- },
232
- })
233
- }