0http-bun 1.1.3 → 1.2.0

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.
@@ -0,0 +1,758 @@
1
+ # Middleware Documentation
2
+
3
+ 0http-bun provides a comprehensive middleware system with built-in middlewares for common use cases. All middleware functions are TypeScript-ready and follow the standard middleware pattern.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Middleware Pattern](#middleware-pattern)
8
+ - [Built-in Middlewares](#built-in-middlewares)
9
+ - [Body Parser](#body-parser)
10
+ - [CORS](#cors)
11
+ - [JWT Authentication](#jwt-authentication)
12
+ - [Logger](#logger)
13
+ - [Rate Limiting](#rate-limiting)
14
+ - [Creating Custom Middleware](#creating-custom-middleware)
15
+
16
+ ## Middleware Pattern
17
+
18
+ All middlewares in 0http-bun follow the standard pattern:
19
+
20
+ ```typescript
21
+ import {ZeroRequest, StepFunction} from '0http-bun'
22
+
23
+ type Middleware = (
24
+ req: ZeroRequest,
25
+ next: StepFunction,
26
+ ) => Promise<Response> | Response
27
+ ```
28
+
29
+ ### TypeScript Support
30
+
31
+ TypeScript type definitions are available for both the core framework and middleware modules:
32
+
33
+ ```typescript
34
+ // Core framework types (from root module)
35
+ import {ZeroRequest, StepFunction, RequestHandler} from '0http-bun'
36
+
37
+ // Middleware-specific types (from middleware module)
38
+ import type {
39
+ LoggerOptions,
40
+ JWTAuthOptions,
41
+ RateLimitOptions,
42
+ RateLimitStore,
43
+ MemoryStore,
44
+ CORSOptions,
45
+ BodyParserOptions,
46
+ } from '0http-bun/lib/middleware'
47
+
48
+ // Import middleware functions
49
+ import {
50
+ createLogger,
51
+ createJWTAuth,
52
+ createRateLimit,
53
+ } from '0http-bun/lib/middleware'
54
+ ```
55
+
56
+ ## Built-in Middlewares
57
+
58
+ All middleware can be imported from the main middleware module:
59
+
60
+ ```javascript
61
+ // Import all middleware from the middleware index
62
+ const {
63
+ createBodyParser,
64
+ createCORS,
65
+ createJWTAuth,
66
+ createLogger,
67
+ createRateLimit,
68
+ } = require('0http-bun/lib/middleware')
69
+ ```
70
+
71
+ For TypeScript:
72
+
73
+ ```typescript
74
+ // Import middleware functions
75
+ import {
76
+ createBodyParser,
77
+ createCORS,
78
+ createJWTAuth,
79
+ createLogger,
80
+ createRateLimit,
81
+ } from '0http-bun/lib/middleware'
82
+
83
+ // Import types
84
+ import type {
85
+ BodyParserOptions,
86
+ CORSOptions,
87
+ JWTAuthOptions,
88
+ LoggerOptions,
89
+ RateLimitOptions,
90
+ } from '0http-bun/lib/middleware'
91
+ ```
92
+
93
+ ### Body Parser
94
+
95
+ Automatically parses request bodies based on Content-Type header.
96
+
97
+ ```javascript
98
+ const {createBodyParser} = require('0http-bun/lib/middleware')
99
+
100
+ const router = http()
101
+
102
+ // Basic usage
103
+ router.use(createBodyParser())
104
+
105
+ // Access parsed body
106
+ router.post('/api/data', (req) => {
107
+ console.log(req.body) // Parsed body content
108
+ return Response.json({received: req.body})
109
+ })
110
+ ```
111
+
112
+ **TypeScript Usage:**
113
+
114
+ ```typescript
115
+ import {createBodyParser} from '0http-bun/lib/middleware'
116
+ import type {BodyParserOptions} from '0http-bun/lib/middleware'
117
+
118
+ // With custom configuration
119
+ const bodyParserOptions: BodyParserOptions = {
120
+ json: {
121
+ limit: 10 * 1024 * 1024, // 10MB
122
+ strict: true,
123
+ },
124
+ urlencoded: {
125
+ extended: true,
126
+ limit: 1024 * 1024, // 1MB
127
+ },
128
+ }
129
+
130
+ router.use(createBodyParser(bodyParserOptions))
131
+ ```
132
+
133
+ **Supported Content Types:**
134
+
135
+ - `application/json` - Parsed as JSON
136
+ - `application/x-www-form-urlencoded` - Parsed as form data
137
+ - `multipart/form-data` - Parsed as FormData
138
+ - `text/*` - Parsed as plain text
139
+ - `application/octet-stream` - Parsed as ArrayBuffer
140
+
141
+ ### CORS
142
+
143
+ Cross-Origin Resource Sharing middleware with flexible configuration.
144
+
145
+ ```javascript
146
+ const {createCORS} = require('0http-bun/lib/middleware')
147
+
148
+ // Basic usage (allows all origins)
149
+ router.use(createCORS())
150
+
151
+ // Custom configuration
152
+ router.use(
153
+ createCORS({
154
+ origin: ['https://example.com', 'https://app.example.com'],
155
+ methods: ['GET', 'POST', 'PUT', 'DELETE'],
156
+ allowedHeaders: ['Content-Type', 'Authorization'],
157
+ exposedHeaders: ['X-Total-Count'],
158
+ credentials: true,
159
+ maxAge: 86400, // Preflight cache duration (seconds)
160
+ preflightContinue: false,
161
+ optionsSuccessStatus: 204,
162
+ }),
163
+ )
164
+
165
+ // Dynamic origin validation
166
+ router.use(
167
+ createCORS({
168
+ origin: (origin, req) => {
169
+ // Custom logic to validate origin
170
+ return (
171
+ origin?.endsWith('.mycompany.com') || origin === 'http://localhost:3000'
172
+ )
173
+ },
174
+ }),
175
+ )
176
+ ````
177
+
178
+ **TypeScript Usage:**
179
+
180
+ ```typescript
181
+ import {createCORS} from '0http-bun/lib/middleware'
182
+ import type {CORSOptions} from '0http-bun/lib/middleware'
183
+
184
+ const corsOptions: CORSOptions = {
185
+ origin: ['https://example.com', 'https://app.example.com'],
186
+ methods: ['GET', 'POST', 'PUT', 'DELETE'],
187
+ credentials: true,
188
+ }
189
+
190
+ router.use(createCORS(corsOptions))
191
+ ```
192
+
193
+ ### JWT Authentication
194
+
195
+ JSON Web Token authentication and authorization middleware with support for static secrets, JWKS endpoints, and API key authentication.
196
+
197
+ #### Basic JWT with Static Secret
198
+
199
+ ```javascript
200
+ const {createJWTAuth} = require('0http-bun/lib/middleware')
201
+
202
+ // Basic JWT verification with static secret
203
+ router.use(
204
+ '/api/protected/*',
205
+ createJWTAuth({
206
+ secret: 'your-secret-key',
207
+ algorithms: ['HS256'],
208
+ }),
209
+ )
210
+ ```
211
+
212
+ **TypeScript Usage:**
213
+
214
+ ```typescript
215
+ import {createJWTAuth} from '0http-bun/lib/middleware'
216
+ import type {JWTAuthOptions} from '0http-bun/lib/middleware'
217
+
218
+ const jwtOptions: JWTAuthOptions = {
219
+ secret: 'your-secret-key',
220
+ jwtOptions: {
221
+ algorithms: ['HS256'],
222
+ audience: 'your-api',
223
+ issuer: 'your-service',
224
+ },
225
+ }
226
+
227
+ router.use('/api/protected/*', createJWTAuth(jwtOptions))
228
+ ```
229
+
230
+ #### JWT with JWKS URI (Recommended for Production)
231
+
232
+ For production applications, especially when integrating with identity providers like Auth0, AWS Cognito, or Azure AD, use JWKS URI for automatic key rotation:
233
+
234
+ ```typescript
235
+ // Using JWKS URI (Auth0 example)
236
+ router.use(
237
+ '/api/protected/*',
238
+ createJWTAuth({
239
+ jwksUri: 'https://your-domain.auth0.com/.well-known/jwks.json',
240
+ algorithms: ['RS256'],
241
+ issuer: 'https://your-domain.auth0.com/',
242
+ audience: 'your-api-identifier',
243
+ }),
244
+ )
245
+
246
+ // AWS Cognito example
247
+ router.use(
248
+ '/api/protected/*',
249
+ createJWTAuth({
250
+ jwksUri:
251
+ 'https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json',
252
+ algorithms: ['RS256'],
253
+ issuer: 'https://cognito-idp.{region}.amazonaws.com/{userPoolId}',
254
+ audience: 'your-client-id',
255
+ }),
256
+ )
257
+
258
+ // Azure AD example
259
+ router.use(
260
+ '/api/protected/*',
261
+ createJWTAuth({
262
+ jwksUri: 'https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys',
263
+ algorithms: ['RS256'],
264
+ issuer: 'https://login.microsoftonline.com/{tenant}/v2.0',
265
+ audience: 'your-application-id',
266
+ }),
267
+ )
268
+
269
+ // Google Identity example
270
+ router.use(
271
+ '/api/protected/*',
272
+ createJWTAuth({
273
+ jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',
274
+ algorithms: ['RS256'],
275
+ issuer: 'https://accounts.google.com',
276
+ audience: 'your-client-id.apps.googleusercontent.com',
277
+ }),
278
+ )
279
+ ```
280
+
281
+ #### Advanced Configuration
282
+
283
+ ```typescript
284
+ // Complete configuration example
285
+ router.use(
286
+ createJWTAuth({
287
+ // Option 1: Static secret (for development/simple cases)
288
+ secret: process.env.JWT_SECRET,
289
+
290
+ // Option 2: JWKS URI (recommended for production)
291
+ jwksUri: process.env.JWKS_URI,
292
+
293
+ // JWT verification options
294
+ algorithms: ['HS256', 'RS256'],
295
+ issuer: 'your-app',
296
+ audience: 'your-users',
297
+ clockTolerance: 10, // Clock skew tolerance (seconds)
298
+ ignoreExpiration: false,
299
+ ignoreNotBefore: false,
300
+
301
+ // Custom token extraction
302
+ getToken: (req) => {
303
+ // Try multiple sources
304
+ return (
305
+ req.headers.get('x-auth-token') ||
306
+ req.headers.get('authorization')?.replace('Bearer ', '') ||
307
+ new URL(req.url).searchParams.get('token')
308
+ )
309
+ },
310
+
311
+ // Alternative token sources
312
+ tokenHeader: 'x-custom-token', // Custom header name
313
+ tokenQuery: 'access_token', // Query parameter name
314
+
315
+ // Error handling
316
+ onError: (err, req) => {
317
+ console.error('JWT Error:', err)
318
+ return Response.json(
319
+ {
320
+ error: 'Unauthorized',
321
+ code: err.name,
322
+ message:
323
+ process.env.NODE_ENV === 'development' ? err.message : undefined,
324
+ },
325
+ {status: 401},
326
+ )
327
+ },
328
+
329
+ // Custom unauthorized response
330
+ unauthorizedResponse: (error, req) => {
331
+ return Response.json(
332
+ {
333
+ error: 'Access denied',
334
+ requestId: req.headers.get('x-request-id'),
335
+ timestamp: new Date().toISOString(),
336
+ },
337
+ {status: 401},
338
+ )
339
+ },
340
+
341
+ // Optional authentication (proceed even without token)
342
+ optional: false,
343
+
344
+ // Exclude certain paths
345
+ excludePaths: ['/health', '/metrics', '/api/public'],
346
+ }),
347
+ )
348
+ ```
349
+
350
+ #### API Key Authentication
351
+
352
+ The JWT middleware also supports API key authentication as an alternative or fallback:
353
+
354
+ ```typescript
355
+ // API key with static keys
356
+ router.use(
357
+ '/api/*',
358
+ createJWTAuth({
359
+ apiKeys: ['key1', 'key2', 'key3'],
360
+ apiKeyHeader: 'x-api-key', // Default header
361
+ }),
362
+ )
363
+
364
+ // API key with custom validation
365
+ router.use(
366
+ '/api/*',
367
+ createJWTAuth({
368
+ apiKeyValidator: async (apiKey, req) => {
369
+ // Custom validation logic
370
+ const user = await validateApiKeyInDatabase(apiKey)
371
+ return user ? {id: user.id, name: user.name, apiKey} : false
372
+ },
373
+ apiKeyHeader: 'x-api-key',
374
+ }),
375
+ )
376
+
377
+ // Combined JWT + API Key authentication
378
+ router.use(
379
+ '/api/*',
380
+ createJWTAuth({
381
+ // JWT configuration
382
+ jwksUri: process.env.JWKS_URI,
383
+ algorithms: ['RS256'],
384
+
385
+ // API Key fallback
386
+ apiKeys: process.env.API_KEYS?.split(','),
387
+ apiKeyHeader: 'x-api-key',
388
+
389
+ // If JWT fails, try API key
390
+ optional: false,
391
+ }),
392
+ )
393
+ ```
394
+
395
+ #### Environment-Based Configuration
396
+
397
+ ```typescript
398
+ // Dynamic configuration based on environment
399
+ const jwtConfig =
400
+ process.env.NODE_ENV === 'production'
401
+ ? {
402
+ // Production: Use JWKS for security and key rotation
403
+ jwksUri: process.env.JWKS_URI,
404
+ algorithms: ['RS256'],
405
+ issuer: process.env.JWT_ISSUER,
406
+ audience: process.env.JWT_AUDIENCE,
407
+ }
408
+ : {
409
+ // Development: Use static secret for simplicity
410
+ secret: process.env.JWT_SECRET || 'dev-secret-key',
411
+ algorithms: ['HS256'],
412
+ }
413
+
414
+ router.use('/api/protected/*', createJWTAuth(jwtConfig))
415
+ ```
416
+
417
+ #### Access Decoded Token Data
418
+
419
+ ```typescript
420
+ // Access decoded token in route handlers
421
+ router.get('/api/profile', (req) => {
422
+ // Multiple ways to access user data
423
+ console.log(req.user) // Decoded JWT payload
424
+ console.log(req.ctx.user) // Same as req.user
425
+ console.log(req.jwt) // Full JWT info (payload, header, token)
426
+ console.log(req.ctx.jwt) // Same as req.jwt
427
+
428
+ // API key authentication data (if used)
429
+ console.log(req.apiKey) // API key value
430
+ console.log(req.ctx.apiKey) // Same as req.apiKey
431
+
432
+ return Response.json({
433
+ user: req.user,
434
+ tokenInfo: {
435
+ issuer: req.jwt?.payload.iss,
436
+ audience: req.jwt?.payload.aud,
437
+ expiresAt: new Date(req.jwt?.payload.exp * 1000),
438
+ issuedAt: new Date(req.jwt?.payload.iat * 1000),
439
+ },
440
+ })
441
+ })
442
+ ```
443
+
444
+ ### Logger
445
+
446
+ Request logging middleware with customizable output formats.
447
+
448
+ ```javascript
449
+ const {createLogger, simpleLogger} = require('0http-bun/lib/middleware')
450
+
451
+ // Simple logging
452
+ router.use(simpleLogger())
453
+
454
+ // Detailed logging with custom format
455
+ router.use(
456
+ createLogger({
457
+ pinoOptions: {
458
+ level: 'info',
459
+ transport: {
460
+ target: 'pino-pretty',
461
+ options: {colorize: true},
462
+ },
463
+ },
464
+ logBody: false,
465
+ excludePaths: ['/health', '/metrics'],
466
+ }),
467
+ )
468
+ ```
469
+
470
+ **TypeScript Usage:**
471
+
472
+ ```typescript
473
+ import {createLogger, simpleLogger} from '0http-bun/lib/middleware'
474
+ import type {LoggerOptions} from '0http-bun/lib/middleware'
475
+
476
+ const loggerOptions: LoggerOptions = {
477
+ pinoOptions: {
478
+ level: 'info',
479
+ transport: {
480
+ target: 'pino-pretty',
481
+ options: {colorize: true},
482
+ },
483
+ },
484
+ logBody: true,
485
+ excludePaths: ['/health', '/ping'],
486
+ serializers: {
487
+ req: (req) => ({
488
+ method: req.method,
489
+ url: req.url,
490
+ userAgent: req.headers.get('user-agent'),
491
+ }),
492
+ },
493
+ }
494
+
495
+ router.use(createLogger(loggerOptions))
496
+ ```
497
+
498
+ **Available Formats:**
499
+
500
+ - `combined` - Apache Combined Log Format
501
+ - `common` - Apache Common Log Format
502
+ - `short` - Shorter than common, includes response time
503
+ - `tiny` - Minimal output
504
+ - `dev` - Development-friendly colored output
505
+
506
+ ### Rate Limiting
507
+
508
+ Configurable rate limiting middleware with multiple store options.
509
+
510
+ ```javascript
511
+ const {createRateLimit, MemoryStore} = require('0http-bun/lib/middleware')
512
+
513
+ // Basic rate limiting
514
+ router.use(
515
+ createRateLimit({
516
+ windowMs: 15 * 60 * 1000, // 15 minutes
517
+ max: 100, // Max 100 requests per windowMs
518
+ }),
519
+ )
520
+
521
+ // Advanced configuration
522
+ router.use(
523
+ createRateLimit({
524
+ windowMs: 60 * 1000, // 1 minute
525
+ max: 20, // Max requests
526
+ keyGenerator: (req) => {
527
+ // Custom key generation (default: IP address)
528
+ return req.headers.get('x-user-id') || req.headers.get('x-forwarded-for')
529
+ },
530
+ skip: (req) => {
531
+ // Skip rate limiting for certain requests
532
+ return req.url.startsWith('/health')
533
+ },
534
+ handler: (req, totalHits, max, resetTime) => {
535
+ // Custom rate limit exceeded response
536
+ return Response.json(
537
+ {
538
+ error: 'Rate limit exceeded',
539
+ resetTime: resetTime.toISOString(),
540
+ retryAfter: Math.ceil((resetTime.getTime() - Date.now()) / 1000),
541
+ },
542
+ {status: 429},
543
+ )
544
+ },
545
+ standardHeaders: true, // Send X-RateLimit-* headers
546
+ excludePaths: ['/health', '/metrics'],
547
+ }),
548
+ )
549
+
550
+ // Custom store (for distributed systems)
551
+ router.use(
552
+ createRateLimit({
553
+ store: new MemoryStore(), // Built-in memory store
554
+ // Or implement custom store with increment() method
555
+ }),
556
+ )
557
+ ```
558
+
559
+ **TypeScript Usage:**
560
+
561
+ ```typescript
562
+ import {createRateLimit, MemoryStore} from '0http-bun/lib/middleware'
563
+ import type {RateLimitOptions, RateLimitStore} from '0http-bun/lib/middleware'
564
+
565
+ const rateLimitOptions: RateLimitOptions = {
566
+ windowMs: 15 * 60 * 1000, // 15 minutes
567
+ max: 100,
568
+ keyGenerator: (req) => {
569
+ return (
570
+ req.headers.get('x-user-id') ||
571
+ req.headers.get('x-forwarded-for') ||
572
+ 'anonymous'
573
+ )
574
+ },
575
+ standardHeaders: true,
576
+ excludePaths: ['/health', '/ping'],
577
+ }
578
+
579
+ router.use(createRateLimit(rateLimitOptions))
580
+
581
+ // Custom store implementation
582
+ class CustomStore implements RateLimitStore {
583
+ async increment(
584
+ key: string,
585
+ windowMs: number,
586
+ ): Promise<{totalHits: number; resetTime: Date}> {
587
+ // Custom implementation
588
+ return {totalHits: 1, resetTime: new Date(Date.now() + windowMs)}
589
+ }
590
+ }
591
+ ```
592
+
593
+ ````
594
+
595
+ **Rate Limit Headers:**
596
+
597
+ - `X-RateLimit-Limit` - Request limit
598
+ - `X-RateLimit-Remaining` - Remaining requests
599
+ - `X-RateLimit-Reset` - Reset time (Unix timestamp)
600
+ - `X-RateLimit-Used` - Used requests
601
+
602
+ ## Creating Custom Middleware
603
+
604
+ ### Basic Middleware
605
+
606
+ ```typescript
607
+ import {ZeroRequest, StepFunction} from '0http-bun'
608
+
609
+ const customMiddleware = (req: ZeroRequest, next: StepFunction) => {
610
+ // Pre-processing
611
+ req.ctx = req.ctx || {}
612
+ req.ctx.startTime = Date.now()
613
+
614
+ // Continue to next middleware/handler
615
+ const response = next()
616
+
617
+ // Post-processing (if needed)
618
+ return response
619
+ }
620
+
621
+ router.use(customMiddleware)
622
+ ````
623
+
624
+ ### Async Middleware
625
+
626
+ ```typescript
627
+ const asyncMiddleware = async (req: ZeroRequest, next: StepFunction) => {
628
+ // Async pre-processing
629
+ const user = await validateUserSession(req)
630
+ req.ctx = {user}
631
+
632
+ // Continue
633
+ const response = await next()
634
+
635
+ // Async post-processing
636
+ await logUserActivity(user, req.url)
637
+
638
+ return response
639
+ }
640
+ ```
641
+
642
+ ### Error Handling in Middleware
643
+
644
+ ```typescript
645
+ const errorHandlingMiddleware = async (
646
+ req: ZeroRequest,
647
+ next: StepFunction,
648
+ ) => {
649
+ try {
650
+ return await next()
651
+ } catch (error) {
652
+ console.error('Middleware error:', error)
653
+
654
+ // Return error response
655
+ return Response.json(
656
+ {
657
+ error: 'Internal server error',
658
+ message:
659
+ process.env.NODE_ENV === 'development' ? error.message : undefined,
660
+ },
661
+ {status: 500},
662
+ )
663
+ }
664
+ }
665
+ ```
666
+
667
+ ## Middleware Execution Order
668
+
669
+ Middlewares execute in the order they are registered:
670
+
671
+ ```typescript
672
+ router.use(middleware1) // Executes first
673
+ router.use(middleware2) // Executes second
674
+ router.use(middleware3) // Executes third
675
+
676
+ router.get('/test', handler) // Final handler
677
+ ```
678
+
679
+ ## Path-Specific Middleware
680
+
681
+ Apply middleware only to specific paths:
682
+
683
+ ```typescript
684
+ // API-only middleware
685
+ router.use('/api/*', jwtAuth({secret: 'api-secret'}))
686
+ router.use('/api/*', rateLimit({max: 1000}))
687
+
688
+ // Admin-only middleware
689
+ router.use('/admin/*', adminAuthMiddleware)
690
+ router.use('/admin/*', auditLogMiddleware)
691
+
692
+ // Public paths (no auth required)
693
+ router.get('/health', healthCheckHandler)
694
+ router.get('/metrics', metricsHandler)
695
+ ```
696
+
697
+ ## Best Practices
698
+
699
+ 1. **Order Matters**: Place security middleware (CORS, auth) before business logic
700
+ 2. **Error Handling**: Always handle errors in async middleware
701
+ 3. **Performance**: Use `skip` functions to avoid unnecessary processing
702
+ 4. **Context**: Use `req.ctx` to pass data between middlewares
703
+ 5. **Immutability**: Don't modify the original request object directly
704
+ 6. **Logging**: Log middleware errors for debugging
705
+ 7. **Testing**: Test middleware in isolation with mock requests
706
+
707
+ ## Examples
708
+
709
+ ### Complete Middleware Stack
710
+
711
+ ```typescript
712
+ const {
713
+ createCORS,
714
+ createLogger,
715
+ createBodyParser,
716
+ createJWTAuth,
717
+ createRateLimit,
718
+ } = require('0http-bun/lib/middleware')
719
+
720
+ const router = http()
721
+
722
+ // 1. CORS (handle preflight requests first)
723
+ router.use(
724
+ createCORS({
725
+ origin: process.env.ALLOWED_ORIGINS?.split(','),
726
+ credentials: true,
727
+ }),
728
+ )
729
+
730
+ // 2. Logging (log all requests)
731
+ router.use(createLogger({format: 'combined'}))
732
+
733
+ // 3. Rate limiting (protect against abuse)
734
+ router.use(
735
+ createRateLimit({
736
+ windowMs: 15 * 60 * 1000,
737
+ max: 1000,
738
+ }),
739
+ )
740
+
741
+ // 4. Body parsing (parse request bodies)
742
+ router.use(createBodyParser({limit: '10mb'}))
743
+
744
+ // 5. Authentication (protect API routes)
745
+ router.use(
746
+ '/api/*',
747
+ createJWTAuth({
748
+ secret: process.env.JWT_SECRET,
749
+ skip: (req) => req.url.includes('/api/public/'),
750
+ }),
751
+ )
752
+
753
+ // Routes
754
+ router.get('/api/public/status', () => Response.json({status: 'ok'}))
755
+ router.get('/api/protected/data', (req) => Response.json({user: req.user}))
756
+ ```
757
+
758
+ This middleware stack provides a solid foundation for most web applications with security, logging, and performance features built-in.