blaizejs 0.6.0 → 0.7.1

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 (25) hide show
  1. package/dist/{chunk-WTCIDURS.js → chunk-DCFSCRSA.js} +3 -3
  2. package/dist/{chunk-YE7LYWE6.js → chunk-EAXYRQ3P.js} +3 -3
  3. package/dist/{chunk-5C4WI3A7.js → chunk-FCV6YEV5.js} +3 -3
  4. package/dist/{chunk-EOCNAQ76.js → chunk-FZ7VQAU3.js} +2 -2
  5. package/dist/{chunk-EOCNAQ76.js.map → chunk-FZ7VQAU3.js.map} +1 -1
  6. package/dist/{chunk-GNLJMVOB.js → chunk-O2UQAGER.js} +3 -3
  7. package/dist/index.cjs +16 -14
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +2548 -1411
  10. package/dist/index.d.ts +2548 -1411
  11. package/dist/index.js +17 -15
  12. package/dist/index.js.map +1 -1
  13. package/dist/{internal-server-error-MFDGHZTW.js → internal-server-error-3NM7IWUS.js} +3 -3
  14. package/dist/{payload-too-large-error-JESAYGED.js → payload-too-large-error-WI42VGZU.js} +3 -3
  15. package/dist/{unsupported-media-type-error-ZDQCGXCO.js → unsupported-media-type-error-TA5IO6FC.js} +3 -3
  16. package/dist/{validation-error-KGPRZ5X7.js → validation-error-NO2FE2IP.js} +3 -3
  17. package/package.json +2 -2
  18. /package/dist/{chunk-WTCIDURS.js.map → chunk-DCFSCRSA.js.map} +0 -0
  19. /package/dist/{chunk-YE7LYWE6.js.map → chunk-EAXYRQ3P.js.map} +0 -0
  20. /package/dist/{chunk-5C4WI3A7.js.map → chunk-FCV6YEV5.js.map} +0 -0
  21. /package/dist/{chunk-GNLJMVOB.js.map → chunk-O2UQAGER.js.map} +0 -0
  22. /package/dist/{internal-server-error-MFDGHZTW.js.map → internal-server-error-3NM7IWUS.js.map} +0 -0
  23. /package/dist/{payload-too-large-error-JESAYGED.js.map → payload-too-large-error-WI42VGZU.js.map} +0 -0
  24. /package/dist/{unsupported-media-type-error-ZDQCGXCO.js.map → unsupported-media-type-error-TA5IO6FC.js.map} +0 -0
  25. /package/dist/{validation-error-KGPRZ5X7.js.map → validation-error-NO2FE2IP.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -7,6 +7,546 @@ import { Readable } from 'node:stream';
7
7
  import { AsyncLocalStorage } from 'node:async_hooks';
8
8
  import { EventEmitter } from 'node:events';
9
9
 
10
+ /**
11
+ * Logger Type Interfaces for BlaizeJS
12
+ *
13
+ * Comprehensive type definitions for the structured logging system.
14
+ * Integrates with the context system via ctx.services.log and supports
15
+ * request-scoped child loggers with automatic correlation ID propagation.
16
+ *
17
+ * @packageDocumentation
18
+ * @since 0.5.0
19
+ */
20
+ /**
21
+ * Log levels supported by the logger system
22
+ *
23
+ * Levels in order of severity (lowest to highest):
24
+ * - `debug`: Detailed diagnostic information for development
25
+ * - `info`: General informational messages about application flow
26
+ * - `warn`: Warning messages for potentially harmful situations
27
+ * - `error`: Error messages for failures that don't stop the application
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const level: LogLevel = 'info';
32
+ * ```
33
+ */
34
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
35
+ /**
36
+ * Arbitrary metadata that can be attached to log entries
37
+ *
38
+ * Used to add structured context to logs. Keys are strings and values
39
+ * can be any JSON-serializable data. The logger will handle Error objects
40
+ * specially by extracting message, stack, and name properties.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const meta: LogMetadata = {
45
+ * userId: '123',
46
+ * action: 'login',
47
+ * duration: 145,
48
+ * tags: ['auth', 'success']
49
+ * };
50
+ * ```
51
+ */
52
+ interface LogMetadata {
53
+ [key: string]: unknown;
54
+ }
55
+ /**
56
+ * Core logger interface implemented by the Logger class
57
+ *
58
+ * Provides structured logging with automatic metadata enrichment,
59
+ * child logger creation for request-scoped logging, and graceful
60
+ * shutdown support via flush().
61
+ *
62
+ * The logger is available in all route handlers via `ctx.services.log`
63
+ * and automatically includes request context (correlationId, method, path).
64
+ *
65
+ * @example Basic Usage
66
+ * ```typescript
67
+ * // In route handler
68
+ * export const GET = appRoute.get({
69
+ * handler: async (ctx) => {
70
+ * ctx.services.log.info('User requested profile', {
71
+ * userId: ctx.params.userId
72
+ * });
73
+ *
74
+ * try {
75
+ * const user = await getUser(ctx.params.userId);
76
+ * return user;
77
+ * } catch (error) {
78
+ * ctx.services.log.error('Failed to fetch user', {
79
+ * userId: ctx.params.userId,
80
+ * error
81
+ * });
82
+ * throw error;
83
+ * }
84
+ * }
85
+ * });
86
+ * ```
87
+ *
88
+ * @example Child Loggers
89
+ * ```typescript
90
+ * // Create a child logger with additional context
91
+ * const dbLogger = ctx.services.log.child({
92
+ * component: 'database',
93
+ * operation: 'user-lookup'
94
+ * });
95
+ *
96
+ * dbLogger.debug('Executing query', { query: 'SELECT * FROM users' });
97
+ * // Output includes: { component: 'database', operation: 'user-lookup', ... }
98
+ * ```
99
+ */
100
+ interface BlaizeLogger {
101
+ /**
102
+ * Log a debug message
103
+ *
104
+ * Use for detailed diagnostic information during development.
105
+ * These logs are typically disabled in production environments.
106
+ *
107
+ * @param message - The log message
108
+ * @param meta - Optional metadata to attach
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * ctx.services.log.debug('Cache lookup', {
113
+ * key: 'user:123',
114
+ * hit: true,
115
+ * ttl: 3600
116
+ * });
117
+ * ```
118
+ */
119
+ debug(message: string, meta?: LogMetadata): void;
120
+ /**
121
+ * Log an info message
122
+ *
123
+ * Use for general informational messages about application flow.
124
+ * This is the default log level for production environments.
125
+ *
126
+ * @param message - The log message
127
+ * @param meta - Optional metadata to attach
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * ctx.services.log.info('User login successful', {
132
+ * userId: '123',
133
+ * method: 'oauth',
134
+ * provider: 'google'
135
+ * });
136
+ * ```
137
+ */
138
+ info(message: string, meta?: LogMetadata): void;
139
+ /**
140
+ * Log a warning message
141
+ *
142
+ * Use for potentially harmful situations that don't prevent
143
+ * the application from functioning.
144
+ *
145
+ * @param message - The log message
146
+ * @param meta - Optional metadata to attach
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * ctx.services.log.warn('Rate limit approaching threshold', {
151
+ * userId: '123',
152
+ * currentCount: 95,
153
+ * limit: 100
154
+ * });
155
+ * ```
156
+ */
157
+ warn(message: string, meta?: LogMetadata): void;
158
+ /**
159
+ * Log an error message
160
+ *
161
+ * Use for error conditions that don't stop the application.
162
+ * The logger automatically extracts stack traces from Error objects.
163
+ *
164
+ * @param message - The log message
165
+ * @param meta - Optional metadata to attach
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * ctx.services.log.error('Database query failed', {
170
+ * query: 'SELECT * FROM users',
171
+ * error: err, // Error object - stack trace will be extracted
172
+ * retryCount: 3
173
+ * });
174
+ * ```
175
+ */
176
+ error(message: string, meta?: LogMetadata): void;
177
+ /**
178
+ * Create a child logger with inherited metadata
179
+ *
180
+ * Child loggers inherit all metadata from their parent and add
181
+ * their own. This is useful for adding component-specific context
182
+ * without polluting the parent logger.
183
+ *
184
+ * Child metadata overrides parent metadata for the same keys.
185
+ *
186
+ * @param meta - Metadata to add to all logs from this child
187
+ * @returns A new logger instance with merged metadata
188
+ *
189
+ * @example Component-Scoped Logging
190
+ * ```typescript
191
+ * // Create a child logger for a specific component
192
+ * const authLogger = ctx.services.log.child({
193
+ * component: 'auth',
194
+ * action: 'verify-token'
195
+ * });
196
+ *
197
+ * authLogger.debug('Verifying JWT token');
198
+ * // Output includes: { correlationId, method, path, component: 'auth', ... }
199
+ *
200
+ * authLogger.info('Token verified', { userId: '123' });
201
+ * // Output includes all parent + child metadata
202
+ * ```
203
+ *
204
+ * @example Nested Child Loggers
205
+ * ```typescript
206
+ * const dbLogger = ctx.services.log.child({ component: 'database' });
207
+ * const queryLogger = dbLogger.child({ operation: 'select' });
208
+ *
209
+ * queryLogger.debug('Executing query');
210
+ * // Output includes: { correlationId, component: 'database', operation: 'select', ... }
211
+ * ```
212
+ */
213
+ child(meta: LogMetadata): BlaizeLogger;
214
+ /**
215
+ * Flush any buffered logs and wait for completion
216
+ *
217
+ * Call this during graceful shutdown to ensure all logs are written
218
+ * before the process exits. This is especially important for transports
219
+ * that batch writes (e.g., sending logs to external services).
220
+ *
221
+ * If the transport doesn't implement flush(), this is a no-op.
222
+ *
223
+ * @returns Promise that resolves when all logs are flushed
224
+ *
225
+ * @example Graceful Shutdown
226
+ * ```typescript
227
+ * // In server shutdown handler
228
+ * process.on('SIGTERM', async () => {
229
+ * console.log('Shutting down gracefully...');
230
+ *
231
+ * // Flush logs before exit
232
+ * await server._logger.flush();
233
+ *
234
+ * await server.close();
235
+ * process.exit(0);
236
+ * });
237
+ * ```
238
+ */
239
+ flush(): Promise<void>;
240
+ }
241
+ /**
242
+ * Transport adapter interface for log output destinations
243
+ *
244
+ * Transports are responsible for writing log entries to a destination
245
+ * (console, file, external service, etc.). Multiple transports can be
246
+ * used simultaneously.
247
+ *
248
+ * Transports must be stateless to support concurrent logging.
249
+ *
250
+ * @example Console Transport
251
+ * ```typescript
252
+ * class ConsoleTransport implements BlaizeLogTransport {
253
+ * write(level: LogLevel, message: string, meta: LogMetadata): void {
254
+ * const timestamp = new Date().toISOString();
255
+ * const levelUpper = level.toUpperCase();
256
+ * const metaStr = JSON.stringify(meta);
257
+ *
258
+ * console.log(`[${timestamp}] ${levelUpper}: ${message} ${metaStr}`);
259
+ * }
260
+ * }
261
+ * ```
262
+ *
263
+ * @example Custom HTTP Transport
264
+ * ```typescript
265
+ * class HTTPTransport implements BlaizeLogTransport {
266
+ * constructor(private endpoint: string) {}
267
+ *
268
+ * write(level: LogLevel, message: string, meta: LogMetadata): void {
269
+ * // Non-blocking fire-and-forget
270
+ * fetch(this.endpoint, {
271
+ * method: 'POST',
272
+ * headers: { 'Content-Type': 'application/json' },
273
+ * body: JSON.stringify({ level, message, meta, timestamp: Date.now() })
274
+ * }).catch(err => console.error('Failed to send log', err));
275
+ * }
276
+ *
277
+ * async flush(): Promise<void> {
278
+ * // Optional: wait for pending requests
279
+ * }
280
+ * }
281
+ * ```
282
+ */
283
+ interface BlaizeLogTransport {
284
+ /**
285
+ * Write a log entry to the transport destination
286
+ *
287
+ * This method must be synchronous and non-blocking. For transports
288
+ * that need to perform async I/O (network, disk), use fire-and-forget
289
+ * pattern or internal buffering.
290
+ *
291
+ * @param level - The log level
292
+ * @param message - The log message
293
+ * @param meta - Structured metadata (already redacted)
294
+ */
295
+ write(level: LogLevel, message: string, meta: LogMetadata): void;
296
+ /**
297
+ * Flush any buffered logs (optional)
298
+ *
299
+ * Implement this if your transport batches writes or has pending
300
+ * async operations. Called during graceful shutdown via logger.flush().
301
+ *
302
+ * @returns Promise that resolves when all logs are written
303
+ */
304
+ flush?(): Promise<void>;
305
+ }
306
+ /**
307
+ * Configuration for the logger system
308
+ *
309
+ * Controls logging behavior including log levels, output destinations,
310
+ * sensitive data redaction, and request lifecycle logging.
311
+ *
312
+ * @example Development Configuration
313
+ * ```typescript
314
+ * import { createServer } from 'blaizejs';
315
+ *
316
+ * const server = createServer({
317
+ * port: 3000,
318
+ * logging: {
319
+ * level: 'debug',
320
+ * // Uses ConsoleTransport by default in development
321
+ * includeTimestamp: true,
322
+ * requestLogging: true,
323
+ * requestLoggerOptions: {
324
+ * includeHeaders: true,
325
+ * includeQuery: true
326
+ * }
327
+ * }
328
+ * });
329
+ * ```
330
+ *
331
+ * @example Production Configuration
332
+ * ```typescript
333
+ * import { JSONTransport } from 'blaizejs';
334
+ *
335
+ * const server = createServer({
336
+ * port: 3000,
337
+ * logging: {
338
+ * level: 'info',
339
+ * transport: new JSONTransport(), // Single-line JSON for log aggregators
340
+ * redactKeys: ['password', 'apiKey', 'secret', 'token'],
341
+ * includeTimestamp: true,
342
+ * requestLogging: true,
343
+ * requestLoggerOptions: {
344
+ * includeHeaders: true,
345
+ * headerWhitelist: ['content-type', 'user-agent']
346
+ * }
347
+ * }
348
+ * });
349
+ * ```
350
+ */
351
+ interface LoggerConfig {
352
+ /**
353
+ * Minimum log level to output
354
+ *
355
+ * Logs below this level are filtered out (zero overhead).
356
+ *
357
+ * @default 'debug' in development, 'info' in production
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * logging: {
362
+ * level: 'warn' // Only log warnings and errors
363
+ * }
364
+ * ```
365
+ */
366
+ level?: LogLevel;
367
+ /**
368
+ * Transport adapter for log output
369
+ *
370
+ * Determines where and how logs are written.
371
+ *
372
+ * @default ConsoleTransport in development, JSONTransport in production
373
+ *
374
+ * @example Multiple Transports
375
+ * ```typescript
376
+ * import { ConsoleTransport, JSONTransport } from 'blaizejs';
377
+ *
378
+ * class MultiTransport implements BlaizeLogTransport {
379
+ * private transports = [
380
+ * new ConsoleTransport(),
381
+ * new JSONTransport()
382
+ * ];
383
+ *
384
+ * write(level: LogLevel, message: string, meta: LogMetadata): void {
385
+ * this.transports.forEach(t => t.write(level, message, meta));
386
+ * }
387
+ * }
388
+ *
389
+ * logging: {
390
+ * transport: new MultiTransport()
391
+ * }
392
+ * ```
393
+ */
394
+ transport?: BlaizeLogTransport;
395
+ /**
396
+ * Keys to redact from log metadata (case-insensitive)
397
+ *
398
+ * Matching keys are replaced with '[REDACTED]' in the output.
399
+ * Redaction is shallow (only top-level keys are checked).
400
+ *
401
+ * @default []
402
+ *
403
+ * @example
404
+ * ```typescript
405
+ * logging: {
406
+ * redactKeys: ['password', 'apiKey', 'creditCard', 'ssn']
407
+ * }
408
+ *
409
+ * // Usage
410
+ * ctx.services.log.info('User created', {
411
+ * email: 'user@example.com',
412
+ * password: 'secret123' // Will be '[REDACTED]' in output
413
+ * });
414
+ * ```
415
+ */
416
+ redactKeys?: string[];
417
+ /**
418
+ * Whether to include ISO 8601 timestamps in log metadata
419
+ *
420
+ * @default true
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * logging: {
425
+ * includeTimestamp: true
426
+ * }
427
+ *
428
+ * // Output includes: { timestamp: '2025-10-20T15:30:45.123Z', ... }
429
+ * ```
430
+ */
431
+ includeTimestamp?: boolean;
432
+ }
433
+ /**
434
+ * Resolved logger configuration with all defaults applied
435
+ *
436
+ */
437
+ interface ResolvedLoggerConfig {
438
+ /** Minimum log level to output */
439
+ level: LogLevel;
440
+ /** Transport adapter for log output */
441
+ transport: BlaizeLogTransport;
442
+ /** Keys to redact from metadata (case-insensitive) */
443
+ redactKeys: string[];
444
+ /** Whether to include ISO 8601 timestamps */
445
+ includeTimestamp: boolean;
446
+ }
447
+ /**
448
+ * Serialized error structure
449
+ */
450
+ interface SerializedError {
451
+ message: string;
452
+ name: string;
453
+ stack?: string;
454
+ }
455
+ /**
456
+ * Options for request logger middleware
457
+ *
458
+ * Controls what request data is automatically included in log metadata
459
+ * for the child logger created for each request.
460
+ *
461
+ * @example Basic Configuration
462
+ * ```typescript
463
+ * requestLoggerOptions: {
464
+ * includeHeaders: true, // Include safe headers
465
+ * includeQuery: true // Include query parameters
466
+ * }
467
+ * ```
468
+ *
469
+ * @example Custom Header Whitelist
470
+ * ```typescript
471
+ * requestLoggerOptions: {
472
+ * includeHeaders: true,
473
+ * headerWhitelist: [
474
+ * 'content-type',
475
+ * 'user-agent',
476
+ * 'accept',
477
+ * 'x-custom-header'
478
+ * ]
479
+ * }
480
+ * ```
481
+ */
482
+ interface RequestLoggerOptions {
483
+ /**
484
+ * Include request headers in log metadata
485
+ *
486
+ * Only safe headers are included by default. Sensitive headers
487
+ * (authorization, cookie, x-api-key, proxy-authorization) are
488
+ * ALWAYS redacted even if included in the whitelist.
489
+ *
490
+ * @default false
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * requestLoggerOptions: {
495
+ * includeHeaders: true
496
+ * }
497
+ *
498
+ * // Default safe headers included:
499
+ * // - accept
500
+ * // - content-type
501
+ * // - user-agent
502
+ * // - x-correlation-id
503
+ * ```
504
+ */
505
+ includeHeaders?: boolean;
506
+ /**
507
+ * Whitelist of header names to include (case-insensitive)
508
+ *
509
+ * Only used when includeHeaders is true. If not specified,
510
+ * default safe headers are used. Sensitive headers are ALWAYS
511
+ * redacted regardless of this whitelist.
512
+ *
513
+ * @default ['accept', 'content-type', 'user-agent', 'x-correlation-id']
514
+ *
515
+ * @example
516
+ * ```typescript
517
+ * requestLoggerOptions: {
518
+ * includeHeaders: true,
519
+ * headerWhitelist: [
520
+ * 'content-type',
521
+ * 'user-agent',
522
+ * 'x-request-id',
523
+ * 'x-custom-header'
524
+ * ]
525
+ * }
526
+ * ```
527
+ */
528
+ headerWhitelist?: string[];
529
+ /**
530
+ * Include query parameters in log metadata
531
+ *
532
+ * Query parameters are included as a `query` object in metadata.
533
+ * Be careful with sensitive data in query strings.
534
+ *
535
+ * @default false
536
+ *
537
+ * @example
538
+ * ```typescript
539
+ * requestLoggerOptions: {
540
+ * includeQuery: true
541
+ * }
542
+ *
543
+ * // Request: GET /users?page=1&limit=10
544
+ * // Log includes: { query: { page: '1', limit: '10' }, ... }
545
+ * ```
546
+ */
547
+ includeQuery?: boolean;
548
+ }
549
+
10
550
  /**
11
551
  * Represents an uploaded file in a multipart/form-data request
12
552
  */
@@ -354,8 +894,19 @@ type UnknownFunction = (...args: unknown[]) => unknown;
354
894
  type NextFunction = () => Promise<void> | void;
355
895
  /**
356
896
  * Middleware function signature
897
+ *
898
+ * @param ctx - The Blaize context object
899
+ * @param next - Function to invoke the next middleware in the chain
900
+ * @param logger - Logger instance for logging within the middleware
901
+ *
902
+ * @example
903
+ * const myMiddleware: MiddlewareFunction = async (ctx, next, logger) => {
904
+ * logger.info('Executing my middleware');
905
+ * // Middleware logic here
906
+ * await next();
907
+ * };
357
908
  */
358
- type MiddlewareFunction = (ctx: Context, next: NextFunction) => Promise<void> | void;
909
+ type MiddlewareFunction = (ctx: Context, next: NextFunction, logger: BlaizeLogger) => Promise<void> | void;
359
910
  /**
360
911
  * Named middleware options
361
912
  */
@@ -411,9 +962,22 @@ ED extends z.ZodType = z.ZodType<any>> {
411
962
  }
412
963
  /**
413
964
  * Route handler function with strongly typed params and response
965
+ *
966
+ * @param ctx - The Blaize context object
967
+ * @param params - Extracted route parameters
968
+ * @param logger - Logger instance for logging within the handler
969
+ *
970
+ * @returns The response data of type TResponse
971
+ *
972
+ * @example
973
+ * const myRouteHandler: RouteHandler = async (ctx, params, logger) => {
974
+ * logger.info('Handling route with params:', params);
975
+ * // Handler logic here
976
+ * return { message: 'Success' }
977
+ * };
414
978
  */
415
979
  type RouteHandler<TParams = Record<string, string>, TQuery = Record<string, string | string[] | undefined>, TBody = unknown, TResponse = unknown, TState extends State = State, // NEW in v0.4.0
416
- TServices extends Services = Services> = (ctx: Context<TState, TServices, TBody, TQuery>, params: TParams) => Promise<TResponse> | TResponse;
980
+ TServices extends Services = Services> = (ctx: Context<TState, TServices, TBody, TQuery>, params: TParams, logger: BlaizeLogger) => Promise<TResponse> | TResponse;
417
981
  /**
418
982
  * Options for a route method with schema-based type inference
419
983
  */
@@ -485,7 +1049,7 @@ interface RouterOptions {
485
1049
  */
486
1050
  interface Router {
487
1051
  /** Handle an incoming request */
488
- handleRequest: (ctx: Context) => Promise<void>;
1052
+ handleRequest: (ctx: Context, logger: BlaizeLogger) => Promise<void>;
489
1053
  /** Get all registered routes */
490
1054
  getRoutes: () => Route[];
491
1055
  /** Add a route programmatically */
@@ -762,441 +1326,122 @@ type CreateOptionsRoute = <TState extends State = State, TServices extends Servi
762
1326
  };
763
1327
 
764
1328
  /**
765
- * Compose multiple middleware functions into a single middleware function
766
- */
767
- declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
768
-
769
- /**
770
- * CORS Types for BlaizeJS Framework
1329
+ * Error type definitions and interfaces for the BlaizeJS framework
771
1330
  *
772
- * Comprehensive type definitions for W3C-compliant CORS middleware
773
- * with support for string, regex, and async function origin validation.
774
- *
775
- * @module @blaizejs/types/cors
1331
+ * This module contains all the type definitions used for error handling
1332
+ * across the BlaizeJS framework, including server-side errors, client-side
1333
+ * errors, and HTTP response formats.
776
1334
  */
777
-
778
1335
  /**
779
- * Origin configuration type supporting multiple validation methods
780
- *
781
- * @example
782
- * ```typescript
783
- * // String origin (exact match)
784
- * const origin: CorsOrigin = 'https://example.com';
785
- *
786
- * // RegExp pattern
787
- * const origin: CorsOrigin = /^https:\/\/.*\.example\.com$/;
1336
+ * Structure of error responses sent over HTTP
788
1337
  *
789
- * // Dynamic validation function
790
- * const origin: CorsOrigin = async (origin, ctx) => {
791
- * return await checkOriginAllowed(origin, ctx?.state.user);
792
- * };
1338
+ * This interface defines the JSON format used for all error responses
1339
+ * from BlaizeJS servers. It matches the structure returned by BlaizeError.toJSON()
793
1340
  *
794
- * // Array of mixed types
795
- * const origin: CorsOrigin = [
796
- * 'https://localhost:3000',
797
- * /^https:\/\/.*\.example\.com$/,
798
- * (origin) => origin.endsWith('.trusted.com')
799
- * ];
1341
+ * @example
1342
+ * ```json
1343
+ * {
1344
+ * "type": "VALIDATION_ERROR",
1345
+ * "title": "Request validation failed",
1346
+ * "status": 400,
1347
+ * "correlationId": "req_abc123",
1348
+ * "timestamp": "2024-01-15T10:30:00.000Z",
1349
+ * "details": {
1350
+ * "fields": ["email", "password"]
1351
+ * }
1352
+ * }
800
1353
  * ```
801
1354
  */
802
- type CorsOrigin = string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>) | Array<string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>)>;
803
- /**
804
- * HTTP methods that can be allowed in CORS
805
- * Based on W3C CORS specification
806
- */
807
- type CorsHttpMethod = HttpMethod | 'CONNECT' | 'TRACE';
1355
+ interface BlaizeErrorResponse {
1356
+ /** Error type from the ErrorType enum */
1357
+ type: ErrorType;
1358
+ /** Human-readable error message */
1359
+ title: string;
1360
+ /** HTTP status code */
1361
+ status: number;
1362
+ /** Correlation ID for request tracing */
1363
+ correlationId: string;
1364
+ /** ISO timestamp when error occurred */
1365
+ timestamp: string;
1366
+ /** Optional error-specific details */
1367
+ details?: unknown;
1368
+ }
808
1369
  /**
809
- * Main CORS configuration options
1370
+ * Context information for network-related errors
810
1371
  *
811
- * @example
812
- * ```typescript
813
- * const corsOptions: CorsOptions = {
814
- * origin: 'https://example.com',
815
- * methods: ['GET', 'POST'],
816
- * credentials: true,
817
- * maxAge: 86400
818
- * };
819
- * ```
1372
+ * Used by client-side error classes to provide additional context
1373
+ * about network failures, timeouts, and connection issues.
820
1374
  */
821
- interface CorsOptions {
822
- /**
823
- * Configures the Access-Control-Allow-Origin header
824
- *
825
- * Possible values:
826
- * - `true`: Allow all origins (sets to '*' unless credentials is true, then reflects origin)
827
- * - `false`: Disable CORS (no headers set)
828
- * - `string`: Specific origin to allow
829
- * - `RegExp`: Pattern to match origins
830
- * - `function`: Custom validation logic
831
- * - `array`: Multiple origin configurations
832
- *
833
- * @default false
834
- */
835
- origin?: boolean | CorsOrigin;
836
- /**
837
- * Configures the Access-Control-Allow-Methods header
838
- *
839
- * @default ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
840
- * @example ['GET', 'POST']
841
- */
842
- methods?: CorsHttpMethod[] | string;
843
- /**
844
- * Configures the Access-Control-Allow-Headers header
845
- *
846
- * Pass an array of allowed headers or a comma-delimited string.
847
- *
848
- * @default Request's Access-Control-Request-Headers header value
849
- * @example ['Content-Type', 'Authorization']
850
- */
851
- allowedHeaders?: string[] | string;
852
- /**
853
- * Configures the Access-Control-Expose-Headers header
854
- *
855
- * Headers that the browser is allowed to access.
856
- *
857
- * @default []
858
- * @example ['Content-Range', 'X-Content-Range']
859
- */
860
- exposedHeaders?: string[] | string;
861
- /**
862
- * Configures the Access-Control-Allow-Credentials header
863
- *
864
- * Set to true to allow credentials (cookies, authorization headers, TLS client certificates).
865
- * Note: Cannot be used with origin: '*' for security reasons.
866
- *
867
- * @default false
868
- */
869
- credentials?: boolean;
870
- /**
871
- * Configures the Access-Control-Max-Age header in seconds
872
- *
873
- * Indicates how long browsers can cache preflight response.
874
- * Set to -1 to disable caching.
875
- *
876
- * @default undefined (browser decides)
877
- * @example 86400 // 24 hours
878
- */
879
- maxAge?: number;
880
- /**
881
- * Whether to pass the CORS preflight response to the next handler
882
- *
883
- * When false, the preflight response is sent immediately.
884
- * When true, control passes to the next middleware/handler.
885
- *
886
- * @default false
887
- */
888
- preflightContinue?: boolean;
889
- /**
890
- * HTTP status code for successful OPTIONS requests
891
- *
892
- * Some legacy browsers require 200, while 204 is more correct.
893
- *
894
- * @default 204
895
- */
896
- optionsSuccessStatus?: number;
1375
+ interface NetworkErrorContext {
1376
+ /** The URL that failed */
1377
+ url: string;
1378
+ /** HTTP method being attempted */
1379
+ method: string;
1380
+ /** Correlation ID for tracing */
1381
+ correlationId: string;
1382
+ /** Timeout value if applicable */
1383
+ timeout?: number;
1384
+ /** The original error that caused the network failure */
1385
+ originalError: Error;
1386
+ /** Additional network-specific details */
1387
+ networkDetails?: {
1388
+ /** Whether this was a connection timeout */
1389
+ isTimeout?: boolean;
1390
+ /** Whether this was a DNS resolution failure */
1391
+ isDnsFailure?: boolean;
1392
+ /** Whether this was a connection refused error */
1393
+ isConnectionRefused?: boolean;
1394
+ /** HTTP status code if received before failure */
1395
+ statusCode?: number;
1396
+ };
897
1397
  }
898
1398
  /**
899
- * Internal CORS validation result
900
- * Used by middleware implementation
1399
+ * Context information for request timeout errors
1400
+ *
1401
+ * Specialized context for timeout-specific errors with timing information.
901
1402
  */
902
- interface CorsValidationResult {
903
- /**
904
- * Whether the origin is allowed
905
- */
906
- allowed: boolean;
907
- /**
908
- * The origin value to set in the header
909
- * Can be '*', specific origin, or 'null'
910
- */
911
- origin?: string;
912
- /**
913
- * Whether to add Vary: Origin header
914
- */
915
- vary?: boolean;
1403
+ interface TimeoutErrorContext {
1404
+ /** The URL that timed out */
1405
+ url: string;
1406
+ /** HTTP method being attempted */
1407
+ method: string;
1408
+ /** Correlation ID for tracing */
1409
+ correlationId: string;
1410
+ /** Configured timeout value in milliseconds */
1411
+ timeoutMs: number;
1412
+ /** Actual duration before timeout in milliseconds */
1413
+ elapsedMs: number;
1414
+ /** Type of timeout (request, connection, etc.) */
1415
+ timeoutType: 'request' | 'connection' | 'response' | 'idle';
916
1416
  }
917
1417
  /**
918
- * CORS preflight request information
919
- * Extracted from OPTIONS request headers
1418
+ * Context information for response parsing errors
1419
+ *
1420
+ * Used when the client receives a response but cannot parse it properly.
920
1421
  */
921
- interface CorsPreflightInfo {
922
- /**
923
- * The origin making the request
924
- */
925
- origin?: string;
926
- /**
927
- * The method that will be used in the actual request
928
- * From Access-Control-Request-Method header
929
- */
930
- requestedMethod?: string;
931
- /**
932
- * The headers that will be sent in the actual request
933
- * From Access-Control-Request-Headers header
934
- */
935
- requestedHeaders?: string[];
1422
+ interface ParseErrorContext {
1423
+ /** The URL that returned unparseable content */
1424
+ url: string;
1425
+ /** HTTP method used */
1426
+ method: string;
1427
+ /** Correlation ID for tracing */
1428
+ correlationId: string;
1429
+ /** HTTP status code received */
1430
+ statusCode: number;
1431
+ /** Content-Type header if available */
1432
+ contentType?: string;
1433
+ /** Expected response format */
1434
+ expectedFormat: 'json' | 'text' | 'binary';
1435
+ /** Sample of the actual response content (truncated for safety) */
1436
+ responseSample?: string;
1437
+ /** The original parsing error */
1438
+ originalError: Error;
936
1439
  }
937
1440
  /**
938
- * Cache entry for origin validation results
939
- * Used for performance optimization
940
- */
941
- interface CorsOriginCacheEntry {
942
- /**
943
- * Whether the origin is allowed
944
- */
945
- allowed: boolean;
946
- /**
947
- * When this cache entry expires (timestamp)
948
- */
949
- expiresAt: number;
950
- /**
951
- * Optional user identifier for cache key
952
- */
953
- userId?: string;
954
- }
955
- /**
956
- * Configuration for CORS origin validation cache
957
- */
958
- interface CorsOriginCacheConfig {
959
- /**
960
- * Time-to-live for cache entries in milliseconds
961
- * @default 60000 (1 minute)
962
- */
963
- ttl?: number;
964
- /**
965
- * Maximum number of entries in the cache
966
- * @default 1000
967
- */
968
- maxSize?: number;
969
- /**
970
- * Whether to include user ID in cache key
971
- * @default true
972
- */
973
- includeUserId?: boolean;
974
- }
975
- /**
976
- * Statistics for CORS middleware performance monitoring
977
- */
978
- interface CorsStats {
979
- /**
980
- * Total number of CORS requests processed
981
- */
982
- totalRequests: number;
983
- /**
984
- * Number of preflight requests handled
985
- */
986
- preflightRequests: number;
987
- /**
988
- * Number of allowed origins
989
- */
990
- allowedOrigins: number;
991
- /**
992
- * Number of denied origins
993
- */
994
- deniedOrigins: number;
995
- /**
996
- * Cache hit rate for origin validation
997
- */
998
- cacheHitRate: number;
999
- /**
1000
- * Average origin validation time in milliseconds
1001
- */
1002
- avgValidationTime: number;
1003
- }
1004
- /**
1005
- * Cache entry type
1006
- */
1007
- interface CacheEntry {
1008
- allowed: boolean;
1009
- expiresAt: number;
1010
- lastAccessed: number;
1011
- }
1012
- /**
1013
- * Cache configuration
1014
- */
1015
- interface CacheConfig {
1016
- ttl: number;
1017
- maxSize: number;
1018
- }
1019
-
1020
- /**
1021
- * Create CORS middleware with the specified options
1022
- *
1023
- * @param userOptions - CORS configuration options or boolean
1024
- * @returns Middleware function that handles CORS
1025
- *
1026
- * @example
1027
- * ```typescript
1028
- * import { cors } from '@blaize-core/middleware/cors';
1029
- *
1030
- * // Development mode - allow all origins
1031
- * server.use(cors(true));
1032
- *
1033
- * // Production - specific origin
1034
- * server.use(cors({
1035
- * origin: 'https://app.example.com',
1036
- * credentials: true,
1037
- * maxAge: 86400
1038
- * }));
1039
- *
1040
- * // Multiple origins with regex
1041
- * server.use(cors({
1042
- * origin: [
1043
- * 'https://app.example.com',
1044
- * /^https:\/\/.*\.example\.com$/
1045
- * ]
1046
- * }));
1047
- *
1048
- * // Dynamic origin validation
1049
- * server.use(cors({
1050
- * origin: async (origin, ctx) => {
1051
- * return await checkOriginAllowed(origin, ctx.state.user);
1052
- * }
1053
- * }));
1054
- * ```
1055
- */
1056
- declare function cors(userOptions?: CorsOptions | boolean): Middleware;
1057
-
1058
- /**
1059
- * Create a middleware
1060
- */
1061
- declare function create$1<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
1062
- /**
1063
- * Create a middleware that only contributes state (no services)
1064
- * Convenience helper for state-only middleware
1065
- *
1066
- * @template T - Type of state to contribute
1067
- * @param handler - Middleware function that adds state
1068
- * @returns Middleware that contributes state only
1069
- *
1070
- */
1071
- declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
1072
- /**
1073
- * Create a middleware that only contributes services (no state)
1074
- * Convenience helper for service-only middleware
1075
- *
1076
- * @template T - Type of services to contribute
1077
- * @param handler - Middleware function that adds services
1078
- * @returns Middleware that contributes services only
1079
- *
1080
- */
1081
- declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
1082
-
1083
- /**
1084
- * Error type definitions and interfaces for the BlaizeJS framework
1085
- *
1086
- * This module contains all the type definitions used for error handling
1087
- * across the BlaizeJS framework, including server-side errors, client-side
1088
- * errors, and HTTP response formats.
1089
- */
1090
- /**
1091
- * Structure of error responses sent over HTTP
1092
- *
1093
- * This interface defines the JSON format used for all error responses
1094
- * from BlaizeJS servers. It matches the structure returned by BlaizeError.toJSON()
1095
- *
1096
- * @example
1097
- * ```json
1098
- * {
1099
- * "type": "VALIDATION_ERROR",
1100
- * "title": "Request validation failed",
1101
- * "status": 400,
1102
- * "correlationId": "req_abc123",
1103
- * "timestamp": "2024-01-15T10:30:00.000Z",
1104
- * "details": {
1105
- * "fields": ["email", "password"]
1106
- * }
1107
- * }
1108
- * ```
1109
- */
1110
- interface BlaizeErrorResponse {
1111
- /** Error type from the ErrorType enum */
1112
- type: ErrorType;
1113
- /** Human-readable error message */
1114
- title: string;
1115
- /** HTTP status code */
1116
- status: number;
1117
- /** Correlation ID for request tracing */
1118
- correlationId: string;
1119
- /** ISO timestamp when error occurred */
1120
- timestamp: string;
1121
- /** Optional error-specific details */
1122
- details?: unknown;
1123
- }
1124
- /**
1125
- * Context information for network-related errors
1126
- *
1127
- * Used by client-side error classes to provide additional context
1128
- * about network failures, timeouts, and connection issues.
1129
- */
1130
- interface NetworkErrorContext {
1131
- /** The URL that failed */
1132
- url: string;
1133
- /** HTTP method being attempted */
1134
- method: string;
1135
- /** Correlation ID for tracing */
1136
- correlationId: string;
1137
- /** Timeout value if applicable */
1138
- timeout?: number;
1139
- /** The original error that caused the network failure */
1140
- originalError: Error;
1141
- /** Additional network-specific details */
1142
- networkDetails?: {
1143
- /** Whether this was a connection timeout */
1144
- isTimeout?: boolean;
1145
- /** Whether this was a DNS resolution failure */
1146
- isDnsFailure?: boolean;
1147
- /** Whether this was a connection refused error */
1148
- isConnectionRefused?: boolean;
1149
- /** HTTP status code if received before failure */
1150
- statusCode?: number;
1151
- };
1152
- }
1153
- /**
1154
- * Context information for request timeout errors
1155
- *
1156
- * Specialized context for timeout-specific errors with timing information.
1157
- */
1158
- interface TimeoutErrorContext {
1159
- /** The URL that timed out */
1160
- url: string;
1161
- /** HTTP method being attempted */
1162
- method: string;
1163
- /** Correlation ID for tracing */
1164
- correlationId: string;
1165
- /** Configured timeout value in milliseconds */
1166
- timeoutMs: number;
1167
- /** Actual duration before timeout in milliseconds */
1168
- elapsedMs: number;
1169
- /** Type of timeout (request, connection, etc.) */
1170
- timeoutType: 'request' | 'connection' | 'response' | 'idle';
1171
- }
1172
- /**
1173
- * Context information for response parsing errors
1174
- *
1175
- * Used when the client receives a response but cannot parse it properly.
1176
- */
1177
- interface ParseErrorContext {
1178
- /** The URL that returned unparseable content */
1179
- url: string;
1180
- /** HTTP method used */
1181
- method: string;
1182
- /** Correlation ID for tracing */
1183
- correlationId: string;
1184
- /** HTTP status code received */
1185
- statusCode: number;
1186
- /** Content-Type header if available */
1187
- contentType?: string;
1188
- /** Expected response format */
1189
- expectedFormat: 'json' | 'text' | 'binary';
1190
- /** Sample of the actual response content (truncated for safety) */
1191
- responseSample?: string;
1192
- /** The original parsing error */
1193
- originalError: Error;
1194
- }
1195
- /**
1196
- * Validation error field details
1197
- *
1198
- * Structure for field-level validation errors with multiple error messages
1199
- * per field.
1441
+ * Validation error field details
1442
+ *
1443
+ * Structure for field-level validation errors with multiple error messages
1444
+ * per field.
1200
1445
  */
1201
1446
  interface ValidationFieldError {
1202
1447
  /** Field name or path (e.g., "email", "user.profile.name") */
@@ -1731,1186 +1976,2066 @@ interface SSEOptions {
1731
1976
  bufferStrategy?: SSEBufferStrategy;
1732
1977
  }
1733
1978
  /**
1734
- * Connection states for SSE streams
1979
+ * Connection states for SSE streams
1980
+ */
1981
+ type SSEConnectionState = 'connecting' | 'connected' | 'disconnected' | 'closed';
1982
+ /**
1983
+ * SSE stream interface for managing server-sent events
1984
+ *
1985
+ * @example
1986
+ * ```typescript
1987
+ * const stream: SSEStream = createSSEStream(response);
1988
+ *
1989
+ * // Send typed event
1990
+ * stream.send('notification', { type: 'info', message: 'Update available' });
1991
+ *
1992
+ * // Send error event
1993
+ * stream.sendError(new Error('Processing failed'));
1994
+ *
1995
+ * // Clean up on close
1996
+ * stream.onClose(() => {
1997
+ * console.log('Client disconnected');
1998
+ * });
1999
+ *
2000
+ * // Close stream
2001
+ * stream.close();
2002
+ * ```
2003
+ */
2004
+ interface SSEStream {
2005
+ /**
2006
+ * Send an event with typed data to the client
2007
+ * @template T - Type of the data payload
2008
+ * @param event - Event name/type
2009
+ * @param data - Event data payload
2010
+ */
2011
+ send<T>(event: string, data: T): void;
2012
+ /**
2013
+ * Send an error event to the client
2014
+ * @param error - Error object to send
2015
+ */
2016
+ sendError(error: Error): void;
2017
+ /**
2018
+ * Close the SSE stream connection
2019
+ */
2020
+ close(): void;
2021
+ /**
2022
+ * Register a callback for stream closure
2023
+ * @param cb - Callback function to execute on close
2024
+ */
2025
+ onClose(cb: () => void): void;
2026
+ }
2027
+ /**
2028
+ * Extended SSE stream with additional control methods
2029
+ */
2030
+ interface SSEStreamExtended extends SSEStream {
2031
+ readonly id: string;
2032
+ [Symbol.asyncIterator](): AsyncGenerator<BufferedEvent, void, unknown>;
2033
+ /** Current connection state */
2034
+ readonly state: SSEConnectionState;
2035
+ /** Number of events in the buffer */
2036
+ readonly bufferSize: number;
2037
+ /** Check if stream is writable */
2038
+ readonly isWritable: boolean;
2039
+ /**
2040
+ * Ping the client to keep connection alive
2041
+ * @param comment - Optional comment to include in ping
2042
+ */
2043
+ ping(comment?: string): void;
2044
+ /**
2045
+ * Set retry interval for client reconnection
2046
+ * @param milliseconds - Retry interval in milliseconds
2047
+ */
2048
+ setRetry(milliseconds: number): void;
2049
+ /**
2050
+ * Flush any buffered events immediately
2051
+ */
2052
+ flush(): void;
2053
+ getMetrics(): StreamMetrics;
2054
+ }
2055
+ /**
2056
+ * SSE event serialization format
2057
+ */
2058
+ interface SSESerializedEvent {
2059
+ /** Event ID field */
2060
+ id?: string;
2061
+ /** Event type field */
2062
+ event?: string;
2063
+ /** Data field (can be multi-line) */
2064
+ data: string;
2065
+ /** Retry field */
2066
+ retry?: number;
2067
+ /** Comment field for keep-alive */
2068
+ comment?: string;
2069
+ }
2070
+ /**
2071
+ * SSE event handler function type
2072
+ * @template T - Type of the event data
2073
+ */
2074
+ type SSEEventHandler<T = unknown> = (event: SSEEvent<T>) => void | Promise<void>;
2075
+ /**
2076
+ * SSE event listener registration
2077
+ */
2078
+ interface SSEEventListener {
2079
+ /** Event type to listen for (use '*' for all events) */
2080
+ event: string;
2081
+ /** Handler function for the event */
2082
+ handler: SSEEventHandler;
2083
+ /** Optional listener identifier for removal */
2084
+ id?: string;
2085
+ }
2086
+ /**
2087
+ * SSE metrics for monitoring stream performance
2088
+ */
2089
+ interface SSEMetrics {
2090
+ /** Total number of events sent */
2091
+ eventsSent: number;
2092
+ /** Total number of events dropped */
2093
+ eventsDropped: number;
2094
+ /** Current number of connected clients */
2095
+ activeConnections: number;
2096
+ /** Total bytes sent */
2097
+ bytesSent: number;
2098
+ /** Average event send latency in milliseconds */
2099
+ averageLatency: number;
2100
+ /** Connection duration in milliseconds */
2101
+ connectionDuration: number;
2102
+ }
2103
+ /**
2104
+ * SSE stream manager for handling multiple clients
2105
+ */
2106
+ interface SSEStreamManager {
2107
+ /**
2108
+ * Create a new SSE stream for a client
2109
+ * @param clientId - Unique identifier for the client
2110
+ * @param options - Stream configuration options
2111
+ */
2112
+ createStream(clientId: string, options?: SSEOptions): SSEStream;
2113
+ /**
2114
+ * Get an existing stream by client ID
2115
+ * @param clientId - Client identifier
2116
+ */
2117
+ getStream(clientId: string): SSEStream | undefined;
2118
+ /**
2119
+ * Broadcast an event to all connected clients
2120
+ * @template T - Type of the event data
2121
+ * @param event - Event name
2122
+ * @param data - Event data
2123
+ */
2124
+ broadcast<T>(event: string, data: T): void;
2125
+ /**
2126
+ * Broadcast to specific clients
2127
+ * @template T - Type of the event data
2128
+ * @param clientIds - Array of client IDs
2129
+ * @param event - Event name
2130
+ * @param data - Event data
2131
+ */
2132
+ multicast<T>(clientIds: string[], event: string, data: T): void;
2133
+ /**
2134
+ * Close a specific client stream
2135
+ * @param clientId - Client identifier
2136
+ */
2137
+ closeStream(clientId: string): void;
2138
+ /**
2139
+ * Close all active streams
2140
+ */
2141
+ closeAll(): void;
2142
+ /**
2143
+ * Get metrics for all streams
2144
+ */
2145
+ getMetrics(): SSEMetrics;
2146
+ }
2147
+ /**
2148
+ * Result type for operations that can fail
2149
+ */
2150
+ type RegistryResult<T> = {
2151
+ success: true;
2152
+ value: T;
2153
+ } | {
2154
+ success: false;
2155
+ error: string;
2156
+ };
2157
+ /**
2158
+ * Connection metadata stored in the registry
2159
+ */
2160
+ interface ConnectionEntry {
2161
+ stream: SSEStream;
2162
+ connectedAt: number;
2163
+ lastActivity: number;
2164
+ clientIp?: string;
2165
+ userAgent?: string;
2166
+ }
2167
+ /**
2168
+ * Internal connection registry interface
2169
+ */
2170
+ interface ConnectionRegistry {
2171
+ /** Add a new connection to the registry */
2172
+ add: (id: string, stream: SSEStream, metadata?: {
2173
+ clientIp?: string;
2174
+ userAgent?: string;
2175
+ }) => void;
2176
+ /** Remove a connection from the registry */
2177
+ remove: (id: string) => void;
2178
+ /** Get current connection count */
2179
+ count: () => number;
2180
+ /** Clean up inactive or closed connections */
2181
+ cleanup: () => void;
2182
+ /** Get connection by ID (for internal use) */
2183
+ get: (id: string) => SSEStream | undefined;
2184
+ /** Check if a connection exists */
2185
+ has: (id: string) => boolean;
2186
+ /** Get all connection IDs */
2187
+ getIds: () => string[];
2188
+ /** Shutdown the registry and close all connections */
2189
+ shutdown: () => void;
2190
+ }
2191
+ /**
2192
+ * Extended stream interface for typed events
2193
+ */
2194
+ interface TypedSSEStream<TEvents extends Record<string, z.ZodType>> extends SSEStreamExtended {
2195
+ send<K extends keyof TEvents>(event: K & string, data: z.infer<TEvents[K]>): void;
2196
+ }
2197
+ /**
2198
+ * Schema for SSE route validation with generic type parameters
2199
+ */
2200
+ interface SSERouteSchema<P extends z.ZodType = z.ZodType<any>, Q extends z.ZodType = z.ZodType<any>, E = any> {
2201
+ /** Parameter schema for validation */
2202
+ params?: P;
2203
+ /** Query schema for validation */
2204
+ query?: Q;
2205
+ /** Events schema for validation (SSE-specific, replaces response) */
2206
+ events?: E;
2207
+ }
2208
+ /**
2209
+ * SSE route handler function with stream as first parameter
2210
+ * This is the user-facing API - they write handlers with this signature
2211
+ */
2212
+ type SSERouteHandler<TStream extends SSEStreamExtended = SSEStreamExtended, TParams = Record<string, string>, TQuery = Record<string, string | string[] | undefined>, TState extends State = State, TServices extends Services = Services> = (stream: TStream, ctx: Context<TState, TServices, never, TQuery>, // SSE never has body
2213
+ params: TParams, logger: BlaizeLogger) => Promise<void> | void;
2214
+ /**
2215
+ * SSE route creator with state and services support
2216
+ * Returns a higher-order function to handle generics properly
2217
+ *
2218
+ * The return type matches what the implementation actually returns:
2219
+ * - A route object with a GET property
2220
+ * - The GET property contains the wrapped handler and schemas
2221
+ * - The wrapped handler has the standard (ctx, params) signature expected by the router
2222
+ */
2223
+ type CreateSSERoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, E = never>(config: {
2224
+ schema?: {
2225
+ params?: P extends never ? never : P;
2226
+ query?: Q extends never ? never : Q;
2227
+ events?: E extends never ? never : E;
2228
+ };
2229
+ handler: SSERouteHandler<E extends Record<string, z.ZodType> ? TypedSSEStream<E> : SSEStreamExtended, P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, TState, TServices>;
2230
+ middleware?: Middleware[];
2231
+ options?: Record<string, unknown>;
2232
+ }) => {
2233
+ GET: {
2234
+ handler: (ctx: any, params: any, logger: BlaizeLogger) => Promise<void>;
2235
+ schema?: {
2236
+ params?: P extends never ? undefined : P;
2237
+ query?: Q extends never ? undefined : Q;
2238
+ };
2239
+ middleware?: Middleware[];
2240
+ options?: Record<string, unknown>;
2241
+ };
2242
+ SSE: {
2243
+ schema: {
2244
+ params?: P extends never ? undefined : P;
2245
+ query?: Q extends never ? undefined : Q;
2246
+ events?: E extends never ? undefined : E;
2247
+ };
2248
+ };
2249
+ path: string;
2250
+ };
2251
+ /**
2252
+ * Buffered event with metadata
2253
+ */
2254
+ interface BufferedEvent {
2255
+ id: string;
2256
+ event: string;
2257
+ data: unknown;
2258
+ size: number;
2259
+ timestamp: number;
2260
+ correlationId: string;
2261
+ }
2262
+ /**
2263
+ * Stream metrics for monitoring
2264
+ */
2265
+ interface StreamMetrics {
2266
+ eventsSent: number;
2267
+ eventsDropped: number;
2268
+ bytesWritten: number;
2269
+ bufferHighWatermark: number;
2270
+ lastEventTime: number;
2271
+ }
2272
+
2273
+ /**
2274
+ * SSE Client Types for BlaizeJS
2275
+ * Location: packages/blaize-client/src/sse/types.ts
2276
+ */
2277
+
2278
+ /**
2279
+ * Event handlers map
2280
+ */
2281
+ interface EventHandlers {
2282
+ [event: string]: Set<(data: any) => void>;
2283
+ }
2284
+ /**
2285
+ * SSE connection configuration options
2286
+ */
2287
+ interface SSEClientOptions {
2288
+ headers?: Record<string, string>;
2289
+ withCredentials?: boolean;
2290
+ reconnect?: {
2291
+ enabled: boolean;
2292
+ maxAttempts?: number;
2293
+ strategy?: ReconnectStrategy;
2294
+ initialDelay?: number;
2295
+ };
2296
+ bufferMissedEvents?: boolean;
2297
+ maxMissedEvents?: number;
2298
+ heartbeatTimeout?: number;
2299
+ parseJSON?: boolean;
2300
+ /**
2301
+ * Whether to wait for connection before resolving the promise.
2302
+ * If false, returns the client immediately without waiting.
2303
+ * Default: true
2304
+ */
2305
+ waitForConnection?: boolean;
2306
+ /**
2307
+ * Optional timeout for initial connection in milliseconds.
2308
+ * If not set, no timeout is applied (relies on EventSource native timeout).
2309
+ * Only applies if waitForConnection is true.
2310
+ */
2311
+ connectionTimeout?: number;
2312
+ }
2313
+ /**
2314
+ * Metrics for SSE connection monitoring
2315
+ */
2316
+ interface SSEClientMetrics {
2317
+ eventsReceived: number;
2318
+ bytesReceived: number;
2319
+ connectionDuration: number;
2320
+ reconnectAttempts: number;
2321
+ lastEventId?: string;
2322
+ }
2323
+ /**
2324
+ * Reconnection delay calculation strategy
2325
+ */
2326
+ type ReconnectStrategy = (attempt: number) => number;
2327
+ /**
2328
+ * SSE Client interface with type-safe event handling
2329
+ */
2330
+ interface SSEClient<TEvents extends Record<string, unknown> = Record<string, unknown>> {
2331
+ on<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
2332
+ on(event: 'error', handler: (error: BlaizeError) => void): void;
2333
+ on(event: 'open', handler: () => void): void;
2334
+ on(event: 'close', handler: (event: CloseEvent) => void): void;
2335
+ off<K extends keyof TEvents>(event: K & string, handler?: (data: TEvents[K]) => void): void;
2336
+ off(event: 'error', handler?: (error: BlaizeError) => void): void;
2337
+ off(event: 'open', handler?: () => void): void;
2338
+ off(event: 'close', handler?: (event: CloseEvent) => void): void;
2339
+ once<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
2340
+ once(event: 'error', handler: (error: BlaizeError) => void): void;
2341
+ once(event: 'open', handler: () => void): void;
2342
+ once(event: 'close', handler: (event: CloseEvent) => void): void;
2343
+ close(): void;
2344
+ readonly state: SSEConnectionState;
2345
+ readonly metrics: SSEClientMetrics;
2346
+ readonly lastEventId?: string;
2347
+ }
2348
+ /**
2349
+ * Close event for SSE connections
2350
+ */
2351
+ interface CloseEvent {
2352
+ reconnect: boolean;
2353
+ reason?: string;
2354
+ }
2355
+ /**
2356
+ * Internal SSE connection factory
2357
+ * Returns a Promise that resolves to an SSEClient instance
2358
+ */
2359
+ type SSEConnectionFactory<TEvents extends Record<string, unknown> = Record<string, unknown>> = (options?: SSEClientOptions) => Promise<SSEClient<TEvents>>;
2360
+
2361
+ type ExtractMethod<T> = T extends {
2362
+ GET: any;
2363
+ } ? 'GET' : T extends {
2364
+ POST: any;
2365
+ } ? 'POST' : T extends {
2366
+ PUT: any;
2367
+ } ? 'PUT' : T extends {
2368
+ DELETE: any;
2369
+ } ? 'DELETE' : T extends {
2370
+ PATCH: any;
2371
+ } ? 'PATCH' : T extends {
2372
+ HEAD: any;
2373
+ } ? 'HEAD' : T extends {
2374
+ OPTIONS: any;
2375
+ } ? 'OPTIONS' : never;
2376
+ type BuildRoutesRegistry<TRoutes extends Record<string, any>> = {
2377
+ [Method in ExtractMethod<TRoutes[keyof TRoutes]> as `$${Lowercase<Method>}`]: {
2378
+ [K in keyof TRoutes as ExtractMethod<TRoutes[K]> extends Method ? K : never]: TRoutes[K];
2379
+ };
2380
+ };
2381
+ type GetRouteMethodOptions<TRoute> = TRoute extends {
2382
+ GET: infer M;
2383
+ } ? M : TRoute extends {
2384
+ POST: infer M;
2385
+ } ? M : TRoute extends {
2386
+ PUT: infer M;
2387
+ } ? M : TRoute extends {
2388
+ DELETE: infer M;
2389
+ } ? M : TRoute extends {
2390
+ PATCH: infer M;
2391
+ } ? M : TRoute extends {
2392
+ HEAD: infer M;
2393
+ } ? M : TRoute extends {
2394
+ OPTIONS: infer M;
2395
+ } ? M : never;
2396
+ type IsNever$1<T> = [T] extends [never] ? true : false;
2397
+ type BuildArgsObject<P, Q, B> = (IsNever$1<P> extends true ? {} : {
2398
+ params: Infer<P>;
2399
+ }) & (IsNever$1<Q> extends true ? {} : {
2400
+ query: Infer<Q>;
2401
+ }) & (IsNever$1<B> extends true ? {} : {
2402
+ body: Infer<B>;
2403
+ });
2404
+ type IsEmptyObject<T> = keyof T extends never ? true : false;
2405
+ type BuildArgs<P, Q, B> = IsEmptyObject<BuildArgsObject<P, Q, B>> extends true ? void : BuildArgsObject<P, Q, B>;
2406
+ type CreateClientMethod<TRoute> = GetRouteMethodOptions<TRoute> extends RouteMethodOptions<infer P, infer Q, infer B, infer R> ? BuildArgs<P, Q, B> extends void ? () => Promise<R extends z.ZodType ? Infer<R> : unknown> : (args: BuildArgs<P, Q, B>) => Promise<R extends z.ZodType ? Infer<R> : unknown> : never;
2407
+ type CreateClient<TRoutes extends Record<string, Record<string, any>>> = {
2408
+ [Method in keyof TRoutes]: {
2409
+ [RouteName in keyof TRoutes[Method]]: CreateClientMethod<TRoutes[Method][RouteName]>;
2410
+ };
2411
+ };
2412
+ interface ClientConfig {
2413
+ baseUrl: string;
2414
+ defaultHeaders?: Record<string, string>;
2415
+ timeout?: number;
2416
+ sse?: SSEClientOptions;
2417
+ }
2418
+ interface InternalRequestArgs {
2419
+ params?: Record<string, any>;
2420
+ query?: Record<string, any>;
2421
+ body?: any;
2422
+ }
2423
+ interface RequestOptions {
2424
+ method: string;
2425
+ url: string;
2426
+ headers: Record<string, string>;
2427
+ body?: string;
2428
+ timeout: number;
2429
+ }
2430
+ /**
2431
+ * Detect if a route has SSE support
2432
+ * SSE routes have a special 'SSE' method key
2433
+ */
2434
+ type HasSSEMethod<TRoute> = TRoute extends {
2435
+ SSE: any;
2436
+ } ? true : false;
2437
+ /**
2438
+ * Extract SSE event types from route schema
2439
+ */
2440
+ /**
2441
+ * Extract SSE event types from route schema
2442
+ */
2443
+ type ExtractSSEEvents<TRoute> = TRoute extends {
2444
+ SSE: {
2445
+ schema?: {
2446
+ events?: infer E;
2447
+ };
2448
+ };
2449
+ } ? E extends z.ZodType ? z.infer<E> : E extends Record<string, z.ZodType> ? {
2450
+ [K in keyof E]: z.infer<E[K]>;
2451
+ } : Record<string, unknown> : Record<string, unknown>;
2452
+ /**
2453
+ * Extract SSE query parameters from route
2454
+ */
2455
+ type ExtractSSEQuery<TRoute> = TRoute extends {
2456
+ SSE: {
2457
+ schema?: {
2458
+ query?: infer Q;
2459
+ };
2460
+ };
2461
+ } ? Q extends z.ZodType ? z.infer<Q> : never : never;
2462
+ /**
2463
+ * Extract SSE params from route
2464
+ */
2465
+ type ExtractSSEParams<TRoute> = TRoute extends {
2466
+ SSE: {
2467
+ schema?: {
2468
+ params?: infer P;
2469
+ };
2470
+ };
2471
+ } ? P extends z.ZodType ? z.infer<P> : never : never;
2472
+ /**
2473
+ * Check if an object type has any required keys
2474
+ */
2475
+ type HasRequiredKeys<T> = {
2476
+ [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
2477
+ }[keyof T] extends never ? false : true;
2478
+ /**
2479
+ * Build SSE method arguments with proper optionality
2480
+ */
2481
+ type BuildSSEArgs<TRoute> = ExtractSSEParams<TRoute> extends never ? ExtractSSEQuery<TRoute> extends never ? {
2482
+ options?: SSEClientOptions;
2483
+ } : HasRequiredKeys<ExtractSSEQuery<TRoute>> extends true ? {
2484
+ query: ExtractSSEQuery<TRoute>;
2485
+ options?: SSEClientOptions;
2486
+ } : {
2487
+ query?: ExtractSSEQuery<TRoute>;
2488
+ options?: SSEClientOptions;
2489
+ } : ExtractSSEQuery<TRoute> extends never ? {
2490
+ params: ExtractSSEParams<TRoute>;
2491
+ options?: SSEClientOptions;
2492
+ } : HasRequiredKeys<ExtractSSEQuery<TRoute>> extends true ? {
2493
+ params: ExtractSSEParams<TRoute>;
2494
+ query: ExtractSSEQuery<TRoute>;
2495
+ options?: SSEClientOptions;
2496
+ } : {
2497
+ params: ExtractSSEParams<TRoute>;
2498
+ query?: ExtractSSEQuery<TRoute>;
2499
+ options?: SSEClientOptions;
2500
+ };
2501
+ /**
2502
+ * Create SSE client method
2503
+ */
2504
+ type CreateSSEMethod<TRoute> = HasSSEMethod<TRoute> extends true ? BuildSSEArgs<TRoute> extends {
2505
+ options?: SSEClientOptions;
2506
+ } ? (args?: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : (args: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : never;
2507
+ /**
2508
+ * Extract SSE routes from registry
2509
+ */
2510
+ type ExtractSSERoutes<TRoutes extends Record<string, any>> = {
2511
+ [K in keyof TRoutes as HasSSEMethod<TRoutes[K]> extends true ? K : never]: TRoutes[K];
2512
+ };
2513
+ /**
2514
+ * Enhanced client with SSE support
2515
+ */
2516
+ type CreateEnhancedClient<TRoutes extends Record<string, any>, TRegistry> = TRegistry & {
2517
+ $sse: {
2518
+ [K in keyof ExtractSSERoutes<TRoutes>]: CreateSSEMethod<TRoutes[K]>;
2519
+ };
2520
+ };
2521
+
2522
+ /**
2523
+ * CORS Types for BlaizeJS Framework
2524
+ *
2525
+ * Comprehensive type definitions for W3C-compliant CORS middleware
2526
+ * with support for string, regex, and async function origin validation.
2527
+ *
2528
+ * @module @blaizejs/types/cors
2529
+ */
2530
+
2531
+ /**
2532
+ * Origin configuration type supporting multiple validation methods
2533
+ *
2534
+ * @example
2535
+ * ```typescript
2536
+ * // String origin (exact match)
2537
+ * const origin: CorsOrigin = 'https://example.com';
2538
+ *
2539
+ * // RegExp pattern
2540
+ * const origin: CorsOrigin = /^https:\/\/.*\.example\.com$/;
2541
+ *
2542
+ * // Dynamic validation function
2543
+ * const origin: CorsOrigin = async (origin, ctx) => {
2544
+ * return await checkOriginAllowed(origin, ctx?.state.user);
2545
+ * };
2546
+ *
2547
+ * // Array of mixed types
2548
+ * const origin: CorsOrigin = [
2549
+ * 'https://localhost:3000',
2550
+ * /^https:\/\/.*\.example\.com$/,
2551
+ * (origin) => origin.endsWith('.trusted.com')
2552
+ * ];
2553
+ * ```
2554
+ */
2555
+ type CorsOrigin = string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>) | Array<string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>)>;
2556
+ /**
2557
+ * HTTP methods that can be allowed in CORS
2558
+ * Based on W3C CORS specification
2559
+ */
2560
+ type CorsHttpMethod = HttpMethod | 'CONNECT' | 'TRACE';
2561
+ /**
2562
+ * Main CORS configuration options
2563
+ *
2564
+ * @example
2565
+ * ```typescript
2566
+ * const corsOptions: CorsOptions = {
2567
+ * origin: 'https://example.com',
2568
+ * methods: ['GET', 'POST'],
2569
+ * credentials: true,
2570
+ * maxAge: 86400
2571
+ * };
2572
+ * ```
2573
+ */
2574
+ interface CorsOptions {
2575
+ /**
2576
+ * Configures the Access-Control-Allow-Origin header
2577
+ *
2578
+ * Possible values:
2579
+ * - `true`: Allow all origins (sets to '*' unless credentials is true, then reflects origin)
2580
+ * - `false`: Disable CORS (no headers set)
2581
+ * - `string`: Specific origin to allow
2582
+ * - `RegExp`: Pattern to match origins
2583
+ * - `function`: Custom validation logic
2584
+ * - `array`: Multiple origin configurations
2585
+ *
2586
+ * @default false
2587
+ */
2588
+ origin?: boolean | CorsOrigin;
2589
+ /**
2590
+ * Configures the Access-Control-Allow-Methods header
2591
+ *
2592
+ * @default ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
2593
+ * @example ['GET', 'POST']
2594
+ */
2595
+ methods?: CorsHttpMethod[] | string;
2596
+ /**
2597
+ * Configures the Access-Control-Allow-Headers header
2598
+ *
2599
+ * Pass an array of allowed headers or a comma-delimited string.
2600
+ *
2601
+ * @default Request's Access-Control-Request-Headers header value
2602
+ * @example ['Content-Type', 'Authorization']
2603
+ */
2604
+ allowedHeaders?: string[] | string;
2605
+ /**
2606
+ * Configures the Access-Control-Expose-Headers header
2607
+ *
2608
+ * Headers that the browser is allowed to access.
2609
+ *
2610
+ * @default []
2611
+ * @example ['Content-Range', 'X-Content-Range']
2612
+ */
2613
+ exposedHeaders?: string[] | string;
2614
+ /**
2615
+ * Configures the Access-Control-Allow-Credentials header
2616
+ *
2617
+ * Set to true to allow credentials (cookies, authorization headers, TLS client certificates).
2618
+ * Note: Cannot be used with origin: '*' for security reasons.
2619
+ *
2620
+ * @default false
2621
+ */
2622
+ credentials?: boolean;
2623
+ /**
2624
+ * Configures the Access-Control-Max-Age header in seconds
2625
+ *
2626
+ * Indicates how long browsers can cache preflight response.
2627
+ * Set to -1 to disable caching.
2628
+ *
2629
+ * @default undefined (browser decides)
2630
+ * @example 86400 // 24 hours
2631
+ */
2632
+ maxAge?: number;
2633
+ /**
2634
+ * Whether to pass the CORS preflight response to the next handler
2635
+ *
2636
+ * When false, the preflight response is sent immediately.
2637
+ * When true, control passes to the next middleware/handler.
2638
+ *
2639
+ * @default false
2640
+ */
2641
+ preflightContinue?: boolean;
2642
+ /**
2643
+ * HTTP status code for successful OPTIONS requests
2644
+ *
2645
+ * Some legacy browsers require 200, while 204 is more correct.
2646
+ *
2647
+ * @default 204
2648
+ */
2649
+ optionsSuccessStatus?: number;
2650
+ }
2651
+ /**
2652
+ * Internal CORS validation result
2653
+ * Used by middleware implementation
2654
+ */
2655
+ interface CorsValidationResult {
2656
+ /**
2657
+ * Whether the origin is allowed
2658
+ */
2659
+ allowed: boolean;
2660
+ /**
2661
+ * The origin value to set in the header
2662
+ * Can be '*', specific origin, or 'null'
2663
+ */
2664
+ origin?: string;
2665
+ /**
2666
+ * Whether to add Vary: Origin header
2667
+ */
2668
+ vary?: boolean;
2669
+ }
2670
+ /**
2671
+ * CORS preflight request information
2672
+ * Extracted from OPTIONS request headers
2673
+ */
2674
+ interface CorsPreflightInfo {
2675
+ /**
2676
+ * The origin making the request
2677
+ */
2678
+ origin?: string;
2679
+ /**
2680
+ * The method that will be used in the actual request
2681
+ * From Access-Control-Request-Method header
2682
+ */
2683
+ requestedMethod?: string;
2684
+ /**
2685
+ * The headers that will be sent in the actual request
2686
+ * From Access-Control-Request-Headers header
2687
+ */
2688
+ requestedHeaders?: string[];
2689
+ }
2690
+ /**
2691
+ * Cache entry for origin validation results
2692
+ * Used for performance optimization
2693
+ */
2694
+ interface CorsOriginCacheEntry {
2695
+ /**
2696
+ * Whether the origin is allowed
2697
+ */
2698
+ allowed: boolean;
2699
+ /**
2700
+ * When this cache entry expires (timestamp)
2701
+ */
2702
+ expiresAt: number;
2703
+ /**
2704
+ * Optional user identifier for cache key
2705
+ */
2706
+ userId?: string;
2707
+ }
2708
+ /**
2709
+ * Configuration for CORS origin validation cache
2710
+ */
2711
+ interface CorsOriginCacheConfig {
2712
+ /**
2713
+ * Time-to-live for cache entries in milliseconds
2714
+ * @default 60000 (1 minute)
2715
+ */
2716
+ ttl?: number;
2717
+ /**
2718
+ * Maximum number of entries in the cache
2719
+ * @default 1000
2720
+ */
2721
+ maxSize?: number;
2722
+ /**
2723
+ * Whether to include user ID in cache key
2724
+ * @default true
2725
+ */
2726
+ includeUserId?: boolean;
2727
+ }
2728
+ /**
2729
+ * Statistics for CORS middleware performance monitoring
2730
+ */
2731
+ interface CorsStats {
2732
+ /**
2733
+ * Total number of CORS requests processed
2734
+ */
2735
+ totalRequests: number;
2736
+ /**
2737
+ * Number of preflight requests handled
2738
+ */
2739
+ preflightRequests: number;
2740
+ /**
2741
+ * Number of allowed origins
2742
+ */
2743
+ allowedOrigins: number;
2744
+ /**
2745
+ * Number of denied origins
2746
+ */
2747
+ deniedOrigins: number;
2748
+ /**
2749
+ * Cache hit rate for origin validation
2750
+ */
2751
+ cacheHitRate: number;
2752
+ /**
2753
+ * Average origin validation time in milliseconds
2754
+ */
2755
+ avgValidationTime: number;
2756
+ }
2757
+ /**
2758
+ * Cache entry type
2759
+ */
2760
+ interface CacheEntry {
2761
+ allowed: boolean;
2762
+ expiresAt: number;
2763
+ lastAccessed: number;
2764
+ }
2765
+ /**
2766
+ * Cache configuration
2767
+ */
2768
+ interface CacheConfig {
2769
+ ttl: number;
2770
+ maxSize: number;
2771
+ }
2772
+
2773
+ /**
2774
+ * BlaizeJS Server Module - Enhanced with Correlation Configuration
2775
+ *
2776
+ * Provides the core HTTP/2 server implementation with HTTP/1.1 fallback
2777
+ * and correlation ID tracking configuration.
2778
+ */
2779
+
2780
+ type UnknownServer = Server<Record<string, unknown>, Record<string, unknown>>;
2781
+ interface Http2Options {
2782
+ enabled?: boolean | undefined;
2783
+ keyFile?: string | undefined;
2784
+ certFile?: string | undefined;
2785
+ }
2786
+ interface StartOptions {
2787
+ port?: number;
2788
+ host?: string;
2789
+ }
2790
+ interface StopOptions {
2791
+ timeout?: number;
2792
+ plugins?: Plugin[];
2793
+ onStopping?: () => Promise<void> | void;
2794
+ onStopped?: () => Promise<void> | void;
2795
+ }
2796
+ /**
2797
+ * Correlation ID configuration options
2798
+ */
2799
+ interface CorrelationOptions {
2800
+ /**
2801
+ * The HTTP header name to use for correlation IDs
2802
+ * @default 'x-correlation-id'
2803
+ */
2804
+ headerName?: string;
2805
+ /**
2806
+ * Custom correlation ID generator function
2807
+ * @default () => `req_${timestamp}_${random}`
2808
+ */
2809
+ generator?: () => string;
2810
+ }
2811
+ /**
2812
+ * Server options for configuring the BlaizeJS server
2813
+ */
2814
+ interface ServerOptionsInput {
2815
+ /** Port to listen on (default: 3000) */
2816
+ port?: number;
2817
+ /** Host to bind to (default: localhost) */
2818
+ host?: string;
2819
+ /** Directory containing route files (default: ./routes) */
2820
+ routesDir?: string;
2821
+ /** HTTP/2 options */
2822
+ http2?: {
2823
+ /** Enable HTTP/2 (default: true) */
2824
+ enabled?: boolean | undefined;
2825
+ /** Path to key file for HTTPS/HTTP2 */
2826
+ keyFile?: string | undefined;
2827
+ /** Path to certificate file for HTTPS/HTTP2 */
2828
+ certFile?: string | undefined;
2829
+ };
2830
+ /** Global middleware to apply to all routes */
2831
+ middleware?: Middleware[];
2832
+ /** Plugins to register */
2833
+ plugins?: Plugin[];
2834
+ /**
2835
+ * Correlation ID configuration
2836
+ * @since 0.4.0
2837
+ */
2838
+ correlation?: CorrelationOptions;
2839
+ /**
2840
+ * CORS configuration
2841
+ *
2842
+ * - `true`: Enable CORS with development defaults (allow all origins)
2843
+ * - `false`: Disable CORS (no headers set)
2844
+ * - `CorsOptions`: Custom CORS configuration
2845
+ *
2846
+ * @default false (CORS disabled)
2847
+ * @since 0.5.0
2848
+ *
2849
+ * @example
2850
+ * ```typescript
2851
+ * // Enable with dev defaults
2852
+ * const server = createServer({ cors: true });
2853
+ *
2854
+ * // Custom configuration
2855
+ * const server = createServer({
2856
+ * cors: {
2857
+ * origin: 'https://example.com',
2858
+ * credentials: true,
2859
+ * maxAge: 86400
2860
+ * }
2861
+ * });
2862
+ *
2863
+ * // Disable CORS
2864
+ * const server = createServer({ cors: false });
2865
+ * ```
2866
+ */
2867
+ cors?: CorsOptions | boolean;
2868
+ bodyLimits?: Partial<BodyLimits>;
2869
+ /**
2870
+ * Logger configuration
2871
+ *
2872
+ * Controls logging behavior including log levels, transports,
2873
+ * redaction, and request lifecycle logging.
2874
+ *
2875
+ * @default Development: ConsoleTransport with debug level
2876
+ * @default Production: JSONTransport with info level
2877
+ * @since 0.4.0
2878
+ *
2879
+ * @example Development Configuration
2880
+ * ```typescript
2881
+ * import { createServer } from 'blaizejs';
2882
+ *
2883
+ * const server = createServer({
2884
+ * port: 3000,
2885
+ * logging: {
2886
+ * level: 'debug',
2887
+ * includeTimestamp: true,
2888
+ * requestLogging: true
2889
+ * }
2890
+ * });
2891
+ * ```
2892
+ *
2893
+ * @example Production Configuration
2894
+ * ```typescript
2895
+ * import { createServer, JSONTransport } from 'blaizejs';
2896
+ *
2897
+ * const server = createServer({
2898
+ * port: 3000,
2899
+ * logging: {
2900
+ * level: 'info',
2901
+ * transport: new JSONTransport(),
2902
+ * redactKeys: ['password', 'apiKey', 'secret'],
2903
+ * requestLogging: true
2904
+ * }
2905
+ * });
2906
+ * ```
2907
+ */
2908
+ logging?: LoggerConfig;
2909
+ }
2910
+ /**
2911
+ * Configuration for a BlaizeJS server
2912
+ */
2913
+ interface ServerOptions {
2914
+ /** Port to listen on (default: 3000) */
2915
+ port: number;
2916
+ /** Host to bind to (default: localhost) */
2917
+ host: string;
2918
+ /** Directory containing route files (default: ./routes) */
2919
+ routesDir: string;
2920
+ /** HTTP/2 options */
2921
+ http2?: {
2922
+ /** Enable HTTP/2 (default: true) */
2923
+ enabled?: boolean | undefined;
2924
+ /** Path to key file for HTTPS/HTTP2 */
2925
+ keyFile?: string | undefined;
2926
+ /** Path to certificate file for HTTPS/HTTP2 */
2927
+ certFile?: string | undefined;
2928
+ };
2929
+ /** Global middleware to apply to all routes */
2930
+ middleware?: Middleware[];
2931
+ /** Plugins to register */
2932
+ plugins?: Plugin[];
2933
+ /**
2934
+ * Correlation ID configuration
2935
+ * @since 0.4.0
2936
+ */
2937
+ correlation?: CorrelationOptions;
2938
+ /**
2939
+ * CORS configuration
2940
+ * @since 0.5.0
2941
+ */
2942
+ cors?: CorsOptions | boolean;
2943
+ /** Body size limits for incoming requests */
2944
+ bodyLimits: BodyLimits;
2945
+ /** Logger configuration */
2946
+ logging?: LoggerConfig;
2947
+ }
2948
+ /**
2949
+ * BlaizeJS Server instance with generic type accumulation
2950
+ *
2951
+ * @template TState - The accumulated state type from middleware
2952
+ * @template TServices - The accumulated services type from middleware and plugins
2953
+ *
2954
+ */
2955
+ interface Server<TState, TServices> {
2956
+ /** The underlying HTTP or HTTP/2 server */
2957
+ server: http.Server | http2.Http2Server | undefined;
2958
+ /** The port the server is configured to listen on */
2959
+ port: number;
2960
+ /** CORS configuration for this server */
2961
+ corsOptions?: CorsOptions | boolean;
2962
+ /** Body size limits for incoming requests */
2963
+ bodyLimits: BodyLimits;
2964
+ /** The host the server is bound to */
2965
+ host: string;
2966
+ events: EventEmitter;
2967
+ /** Direct access to registered plugins */
2968
+ plugins: Plugin[];
2969
+ /** Direct access to registered plugins */
2970
+ middleware: Middleware[];
2971
+ /** Internal property for signal handlers */
2972
+ _signalHandlers?: {
2973
+ unregister: () => void;
2974
+ };
2975
+ /** Internal logger instance (for server use only) */
2976
+ _logger: BlaizeLogger;
2977
+ /** Start the server and listen for connections */
2978
+ listen: (port?: number, host?: string) => Promise<Server<TState, TServices>>;
2979
+ /** Stop the server */
2980
+ close: (stopOptions?: StopOptions) => Promise<void>;
2981
+ /**
2982
+ * Add global middleware to the server
2983
+ *
2984
+ * @param middleware - Single middleware or array of middleware to add
2985
+ * @returns New Server instance with accumulated types from the middleware
2986
+ *
2987
+ * @example
2988
+ * ```typescript
2989
+ * // Single middleware
2990
+ * const serverWithAuth = server.use(authMiddleware);
2991
+ * // serverWithAuth has type Server<{user: User}, {auth: AuthService}>
2992
+ *
2993
+ * // Array of middleware
2994
+ * const serverWithMiddleware = server.use([authMiddleware, loggerMiddleware]);
2995
+ * // serverWithMiddleware has type Server<{user, requestId}, {auth, logger}>
2996
+ * ```
2997
+ */
2998
+ use<MS, MSvc>(middleware: Middleware<MS, MSvc>): Server<TState & MS, TServices & MSvc>;
2999
+ use<MW extends readonly Middleware<any, any>[]>(middleware: MW): Server<TState & UnionToIntersection<ExtractMiddlewareState<MW[number]>>, TServices & UnionToIntersection<ExtractMiddlewareServices<MW[number]>>>;
3000
+ /**
3001
+ * Register a plugin with the server
3002
+ *
3003
+ * @param plugin - Single plugin or array of plugins to register
3004
+ * @returns Promise resolving to new Server instance with accumulated types
3005
+ *
3006
+ * @example
3007
+ * ```typescript
3008
+ * // Single plugin
3009
+ * const serverWithDb = await server.register(databasePlugin);
3010
+ * // serverWithDb has type Server<{}, {db: DatabaseService}>
3011
+ *
3012
+ * // Array of plugins
3013
+ * const serverWithPlugins = await server.register([dbPlugin, cachePlugin]);
3014
+ * // serverWithPlugins has type Server<{}, {db, cache}>
3015
+ * ```
3016
+ */
3017
+ register<PS, PSvc>(plugin: Plugin<PS, PSvc>): Promise<Server<TState & PS, TServices & PSvc>>;
3018
+ register<P extends readonly Plugin<any, any>[]>(plugin: P): Promise<Server<TState & UnionToIntersection<ExtractPluginState<P[number]>>, TServices & UnionToIntersection<ExtractPluginServices<P[number]>>>>;
3019
+ /** Access to the routing system */
3020
+ router: Router;
3021
+ /** Context storage system */
3022
+ context: AsyncLocalStorage<Context>;
3023
+ pluginManager: PluginLifecycleManager;
3024
+ }
3025
+ type RequestHandler = (req: http.IncomingMessage | http2.Http2ServerRequest, res: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
3026
+
3027
+ /**
3028
+ * BlaizeJS Plugin Module
3029
+ *
3030
+ * Provides the plugin system for extending framework functionality.
1735
3031
  */
1736
- type SSEConnectionState = 'connecting' | 'connected' | 'disconnected' | 'closed';
3032
+
1737
3033
  /**
1738
- * SSE stream interface for managing server-sent events
1739
- *
1740
- * @example
1741
- * ```typescript
1742
- * const stream: SSEStream = createSSEStream(response);
1743
- *
1744
- * // Send typed event
1745
- * stream.send('notification', { type: 'info', message: 'Update available' });
1746
- *
1747
- * // Send error event
1748
- * stream.sendError(new Error('Processing failed'));
1749
- *
1750
- * // Clean up on close
1751
- * stream.onClose(() => {
1752
- * console.log('Client disconnected');
1753
- * });
3034
+ * Plugin options
3035
+ */
3036
+ interface PluginOptions<_T = any> {
3037
+ /** Plugin configuration */
3038
+ [key: string]: any;
3039
+ }
3040
+ /**
3041
+ * Plugin lifecycle hooks with full type safety
1754
3042
  *
1755
- * // Close stream
1756
- * stream.close();
1757
- * ```
3043
+ * Plugins execute in this order:
3044
+ * 1. register() - Add middleware, routes
3045
+ * 2. initialize() - Create resources
3046
+ * 3. onServerStart() - Start background work
3047
+ * 4. onServerStop() - Stop background work
3048
+ * 5. terminate() - Cleanup resources
1758
3049
  */
1759
- interface SSEStream {
1760
- /**
1761
- * Send an event with typed data to the client
1762
- * @template T - Type of the data payload
1763
- * @param event - Event name/type
1764
- * @param data - Event data payload
1765
- */
1766
- send<T>(event: string, data: T): void;
1767
- /**
1768
- * Send an error event to the client
1769
- * @param error - Error object to send
1770
- */
1771
- sendError(error: Error): void;
3050
+ interface PluginHooks<TState = {}, TServices = {}> {
1772
3051
  /**
1773
- * Close the SSE stream connection
3052
+ * Called when plugin is registered to server
3053
+ *
3054
+ * Use this hook to:
3055
+ * - Add middleware via server.use()
3056
+ * - Add routes via server.router.addRoute()
3057
+ * - Subscribe to server events
3058
+ *
3059
+ * @param server - BlaizeJS server instance
3060
+ * @example
3061
+ * ```typescript
3062
+ * register: async (server) => {
3063
+ * server.use(createMiddleware({
3064
+ * handler: async (ctx, next) => {
3065
+ * ctx.services.db = db;
3066
+ * await next();
3067
+ * },
3068
+ * }));
3069
+ * }
3070
+ * ```
1774
3071
  */
1775
- close(): void;
3072
+ register?: (server: Server<TState, TServices>) => void | Promise<void>;
1776
3073
  /**
1777
- * Register a callback for stream closure
1778
- * @param cb - Callback function to execute on close
3074
+ * Called during server initialization
3075
+ *
3076
+ * Use this hook to:
3077
+ * - Create database connections
3078
+ * - Initialize services
3079
+ * - Allocate resources
3080
+ *
3081
+ * @example
3082
+ * ```typescript
3083
+ * initialize: async () => {
3084
+ * db = await Database.connect(config);
3085
+ * }
3086
+ * ```
1779
3087
  */
1780
- onClose(cb: () => void): void;
1781
- }
1782
- /**
1783
- * Extended SSE stream with additional control methods
1784
- */
1785
- interface SSEStreamExtended extends SSEStream {
1786
- readonly id: string;
1787
- [Symbol.asyncIterator](): AsyncGenerator<BufferedEvent, void, unknown>;
1788
- /** Current connection state */
1789
- readonly state: SSEConnectionState;
1790
- /** Number of events in the buffer */
1791
- readonly bufferSize: number;
1792
- /** Check if stream is writable */
1793
- readonly isWritable: boolean;
3088
+ initialize?: (server: Server<TState, TServices>) => void | Promise<void>;
1794
3089
  /**
1795
- * Ping the client to keep connection alive
1796
- * @param comment - Optional comment to include in ping
3090
+ * Called when server starts listening
3091
+ *
3092
+ * Use this hook to:
3093
+ * - Start background workers
3094
+ * - Start cron jobs
3095
+ * - Begin health checks
3096
+ *
3097
+ * @example
3098
+ * ```typescript
3099
+ * onServerStart: async () => {
3100
+ * worker = new BackgroundWorker();
3101
+ * await worker.start();
3102
+ * }
3103
+ * ```
1797
3104
  */
1798
- ping(comment?: string): void;
3105
+ onServerStart?: (server: Http2Server | Server$1) => void | Promise<void>;
1799
3106
  /**
1800
- * Set retry interval for client reconnection
1801
- * @param milliseconds - Retry interval in milliseconds
3107
+ * Called when server stops listening
3108
+ *
3109
+ * Use this hook to:
3110
+ * - Stop background workers
3111
+ * - Flush buffers
3112
+ * - Complete in-flight work
3113
+ *
3114
+ * @example
3115
+ * ```typescript
3116
+ * onServerStop: async () => {
3117
+ * await worker.stop({ graceful: true });
3118
+ * }
3119
+ * ```
1802
3120
  */
1803
- setRetry(milliseconds: number): void;
3121
+ onServerStop?: (server: Http2Server | Server$1) => void | Promise<void>;
1804
3122
  /**
1805
- * Flush any buffered events immediately
3123
+ * Called during server termination
3124
+ *
3125
+ * Use this hook to:
3126
+ * - Close database connections
3127
+ * - Release file handles
3128
+ * - Free memory
3129
+ *
3130
+ * @example
3131
+ * ```typescript
3132
+ * terminate: async () => {
3133
+ * await db?.close();
3134
+ * }
3135
+ * ```
1806
3136
  */
1807
- flush(): void;
1808
- getMetrics(): StreamMetrics;
1809
- }
1810
- /**
1811
- * SSE event serialization format
1812
- */
1813
- interface SSESerializedEvent {
1814
- /** Event ID field */
1815
- id?: string;
1816
- /** Event type field */
1817
- event?: string;
1818
- /** Data field (can be multi-line) */
1819
- data: string;
1820
- /** Retry field */
1821
- retry?: number;
1822
- /** Comment field for keep-alive */
1823
- comment?: string;
1824
- }
1825
- /**
1826
- * SSE event handler function type
1827
- * @template T - Type of the event data
1828
- */
1829
- type SSEEventHandler<T = unknown> = (event: SSEEvent<T>) => void | Promise<void>;
1830
- /**
1831
- * SSE event listener registration
1832
- */
1833
- interface SSEEventListener {
1834
- /** Event type to listen for (use '*' for all events) */
1835
- event: string;
1836
- /** Handler function for the event */
1837
- handler: SSEEventHandler;
1838
- /** Optional listener identifier for removal */
1839
- id?: string;
1840
- }
1841
- /**
1842
- * SSE metrics for monitoring stream performance
1843
- */
1844
- interface SSEMetrics {
1845
- /** Total number of events sent */
1846
- eventsSent: number;
1847
- /** Total number of events dropped */
1848
- eventsDropped: number;
1849
- /** Current number of connected clients */
1850
- activeConnections: number;
1851
- /** Total bytes sent */
1852
- bytesSent: number;
1853
- /** Average event send latency in milliseconds */
1854
- averageLatency: number;
1855
- /** Connection duration in milliseconds */
1856
- connectionDuration: number;
3137
+ terminate?: (server: Server<TState, TServices>) => void | Promise<void>;
1857
3138
  }
1858
3139
  /**
1859
- * SSE stream manager for handling multiple clients
3140
+ * Options for creating a plugin with createPlugin()
3141
+ *
3142
+ * @template TConfig - Plugin configuration shape
3143
+ * @template TState - State added to context
3144
+ * @template TServices - Services added to context
1860
3145
  */
1861
- interface SSEStreamManager {
1862
- /**
1863
- * Create a new SSE stream for a client
1864
- * @param clientId - Unique identifier for the client
1865
- * @param options - Stream configuration options
1866
- */
1867
- createStream(clientId: string, options?: SSEOptions): SSEStream;
3146
+ interface CreatePluginOptions<TConfig, TState = {}, TServices = {}> {
1868
3147
  /**
1869
- * Get an existing stream by client ID
1870
- * @param clientId - Client identifier
3148
+ * Plugin name (e.g., '@blaizejs/metrics')
3149
+ * Must be unique within a server instance
1871
3150
  */
1872
- getStream(clientId: string): SSEStream | undefined;
3151
+ name: string;
1873
3152
  /**
1874
- * Broadcast an event to all connected clients
1875
- * @template T - Type of the event data
1876
- * @param event - Event name
1877
- * @param data - Event data
3153
+ * Semantic version (e.g., '1.0.0')
3154
+ * Used for compatibility checks
1878
3155
  */
1879
- broadcast<T>(event: string, data: T): void;
3156
+ version: string;
1880
3157
  /**
1881
- * Broadcast to specific clients
1882
- * @template T - Type of the event data
1883
- * @param clientIds - Array of client IDs
1884
- * @param event - Event name
1885
- * @param data - Event data
3158
+ * Default configuration values
3159
+ * Merged with user config when plugin is created
3160
+ *
3161
+ * @example
3162
+ * ```typescript
3163
+ * defaultConfig: {
3164
+ * enabled: true,
3165
+ * timeout: 30000,
3166
+ * }
3167
+ * ```
1886
3168
  */
1887
- multicast<T>(clientIds: string[], event: string, data: T): void;
3169
+ defaultConfig?: TConfig;
1888
3170
  /**
1889
- * Close a specific client stream
1890
- * @param clientId - Client identifier
3171
+ * Setup function that returns lifecycle hooks
3172
+ *
3173
+ * Receives merged config (defaultConfig + userConfig).
3174
+ * Returns partial hook object - all hooks optional.
3175
+ *
3176
+ * @param config - Merged configuration
3177
+ * @returns Partial plugin hooks
3178
+ *
3179
+ * @example
3180
+ * ```typescript
3181
+ * setup: (config) => {
3182
+ * let db: Database;
3183
+ *
3184
+ * return {
3185
+ * initialize: async () => {
3186
+ * db = await Database.connect(config);
3187
+ * },
3188
+ * terminate: async () => {
3189
+ * await db?.close();
3190
+ * },
3191
+ * };
3192
+ * }
3193
+ * ```
1891
3194
  */
1892
- closeStream(clientId: string): void;
3195
+ setup: (config: TConfig, logger: BlaizeLogger) => Partial<PluginHooks<TState, TServices>>;
3196
+ }
3197
+ /**
3198
+ * Plugin interface
3199
+ */
3200
+ interface Plugin<TState = {}, TServices = {}> extends PluginHooks<TState, TServices> {
3201
+ /** Plugin name */
3202
+ name: string;
3203
+ /** Plugin version */
3204
+ version: string;
1893
3205
  /**
1894
- * Close all active streams
3206
+ * Called when plugin is registered to server
3207
+ *
3208
+ * This hook is always present - createPlugin provides a default empty async function
3209
+ * if not specified by the plugin author.
3210
+ *
3211
+ * @override Makes register required (not optional like in PluginHooks)
1895
3212
  */
1896
- closeAll(): void;
3213
+ register: (server: Server<TState, TServices>) => void | Promise<void>;
1897
3214
  /**
1898
- * Get metrics for all streams
3215
+ * Type carriers for compile-time type information
3216
+ * These are never used at runtime but allow TypeScript to track types
1899
3217
  */
1900
- getMetrics(): SSEMetrics;
3218
+ _state?: TState;
3219
+ _services?: TServices;
1901
3220
  }
1902
3221
  /**
1903
- * Result type for operations that can fail
3222
+ * Plugin factory function
1904
3223
  */
1905
- type RegistryResult<T> = {
1906
- success: true;
1907
- value: T;
1908
- } | {
1909
- success: false;
1910
- error: string;
1911
- };
3224
+ type PluginFactory<TConfig = any, TState = {}, TServices = {}> = (options?: Partial<TConfig>) => Plugin<TState, TServices>;
3225
+ interface PluginLifecycleManager {
3226
+ initializePlugins(server: Server<any, any>): Promise<void>;
3227
+ terminatePlugins(server: Server<any, any>): Promise<void>;
3228
+ onServerStart(server: Server<any, any>, httpServer: any): Promise<void>;
3229
+ onServerStop(server: Server<any, any>, httpServer: any): Promise<void>;
3230
+ }
3231
+ interface PluginLifecycleOptions {
3232
+ /** Continue initialization even if a plugin fails */
3233
+ continueOnError?: boolean;
3234
+ /** Custom error handler for plugin failures */
3235
+ onError?: (plugin: Plugin, phase: string, error: Error) => void;
3236
+ }
3237
+
1912
3238
  /**
1913
- * Connection metadata stored in the registry
3239
+ * Type composition utilities for extracting and composing middleware type contributions
3240
+ * @module composition
3241
+ * @since v0.4.0
1914
3242
  */
1915
- interface ConnectionEntry {
1916
- stream: SSEStream;
1917
- connectedAt: number;
1918
- lastActivity: number;
1919
- clientIp?: string;
1920
- userAgent?: string;
1921
- }
3243
+
1922
3244
  /**
1923
- * Internal connection registry interface
3245
+ * Extracts the State type contribution from a middleware
3246
+ * @template T - The middleware type to extract from
3247
+ * @returns The state type if present, empty object otherwise
1924
3248
  */
1925
- interface ConnectionRegistry {
1926
- /** Add a new connection to the registry */
1927
- add: (id: string, stream: SSEStream, metadata?: {
1928
- clientIp?: string;
1929
- userAgent?: string;
1930
- }) => void;
1931
- /** Remove a connection from the registry */
1932
- remove: (id: string) => void;
1933
- /** Get current connection count */
1934
- count: () => number;
1935
- /** Clean up inactive or closed connections */
1936
- cleanup: () => void;
1937
- /** Get connection by ID (for internal use) */
1938
- get: (id: string) => SSEStream | undefined;
1939
- /** Check if a connection exists */
1940
- has: (id: string) => boolean;
1941
- /** Get all connection IDs */
1942
- getIds: () => string[];
1943
- /** Shutdown the registry and close all connections */
1944
- shutdown: () => void;
1945
- }
3249
+ type ExtractMiddlewareState<T> = T extends Middleware<infer S, any> ? S : {};
1946
3250
  /**
1947
- * Extended stream interface for typed events
3251
+ * Extracts the State type contribution from a plugin
3252
+ * @template T - The plugin type to extract from
3253
+ * @returns The state type if present, empty object otherwise
1948
3254
  */
1949
- interface TypedSSEStream<TEvents extends Record<string, z.ZodType>> extends SSEStreamExtended {
1950
- send<K extends keyof TEvents>(event: K & string, data: z.infer<TEvents[K]>): void;
1951
- }
3255
+ type ExtractPluginState<T> = T extends Plugin<infer S, any> ? S : {};
1952
3256
  /**
1953
- * Schema for SSE route validation with generic type parameters
3257
+ * Extracts the Services type contribution from a middleware
3258
+ * @template T - The middleware type to extract from
3259
+ * @returns The services type if present, empty object otherwise
1954
3260
  */
1955
- interface SSERouteSchema<P extends z.ZodType = z.ZodType<any>, Q extends z.ZodType = z.ZodType<any>, E = any> {
1956
- /** Parameter schema for validation */
1957
- params?: P;
1958
- /** Query schema for validation */
1959
- query?: Q;
1960
- /** Events schema for validation (SSE-specific, replaces response) */
1961
- events?: E;
1962
- }
3261
+ type ExtractMiddlewareServices<T> = T extends Middleware<any, infer S> ? S : {};
1963
3262
  /**
1964
- * SSE route handler function with stream as first parameter
1965
- * This is the user-facing API - they write handlers with this signature
3263
+ * Extracts the Services type contribution from a plugin
3264
+ * @template T - The plugin type to extract from
3265
+ * @returns The services type if present, empty object otherwise
1966
3266
  */
1967
- type SSERouteHandler<TStream extends SSEStreamExtended = SSEStreamExtended, TParams = Record<string, string>, TQuery = Record<string, string | string[] | undefined>, TState extends State = State, TServices extends Services = Services> = (stream: TStream, ctx: Context<TState, TServices, never, TQuery>, // SSE never has body
1968
- params: TParams) => Promise<void> | void;
3267
+ type ExtractPluginServices<T> = T extends Plugin<any, infer S> ? S : {};
1969
3268
  /**
1970
- * SSE route creator with state and services support
1971
- * Returns a higher-order function to handle generics properly
3269
+ * Utility type to convert a union type to an intersection type
3270
+ * This is the magic that allows us to compose multiple middleware contributions
3271
+ *
3272
+ * @example
3273
+ * type U = { a: string } | { b: number }
3274
+ * type I = UnionToIntersection<U> // { a: string } & { b: number }
1972
3275
  *
1973
- * The return type matches what the implementation actually returns:
1974
- * - A route object with a GET property
1975
- * - The GET property contains the wrapped handler and schemas
1976
- * - The wrapped handler has the standard (ctx, params) signature expected by the router
1977
3276
  */
1978
- type CreateSSERoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, E = never>(config: {
1979
- schema?: {
1980
- params?: P extends never ? never : P;
1981
- query?: Q extends never ? never : Q;
1982
- events?: E extends never ? never : E;
1983
- };
1984
- handler: SSERouteHandler<E extends Record<string, z.ZodType> ? TypedSSEStream<E> : SSEStreamExtended, P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, TState, TServices>;
1985
- middleware?: Middleware[];
1986
- options?: Record<string, unknown>;
1987
- }) => {
1988
- GET: {
1989
- handler: (ctx: any, params: any) => Promise<void>;
1990
- schema?: {
1991
- params?: P extends never ? undefined : P;
1992
- query?: Q extends never ? undefined : Q;
1993
- };
1994
- middleware?: Middleware[];
1995
- options?: Record<string, unknown>;
1996
- };
1997
- path: string;
1998
- };
3277
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
1999
3278
  /**
2000
- * Buffered event with metadata
3279
+ * Composes state contributions from an array of middleware
3280
+ * Merges all state types into a single intersection type
3281
+ *
3282
+ * @template T - ReadonlyArray of Middleware
3283
+ * @returns Intersection of all state contributions
3284
+ *
3285
+ * @example
3286
+ * const middlewares = [authMiddleware, loggerMiddleware] as const;
3287
+ * type ComposedState = ComposeStates<typeof middlewares>;
3288
+ * // Result: { user: User } & { requestId: string }
2001
3289
  */
2002
- interface BufferedEvent {
2003
- id: string;
2004
- event: string;
2005
- data: unknown;
2006
- size: number;
2007
- timestamp: number;
2008
- correlationId: string;
2009
- }
3290
+ type ComposeMiddlewareStates<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareState<T[number]>>;
2010
3291
  /**
2011
- * Stream metrics for monitoring
3292
+ * Composes state contributions from an array of plugins
3293
+ * Merges all state types into a single intersection type
3294
+ *
3295
+ * @template T - ReadonlyArray of Plugin
3296
+ * @returns Intersection of all state contributions
3297
+ *
3298
+ * @example
3299
+ * const plugins = [authPlugin, dbPlugin] as const;
3300
+ * type ComposedState = ComposePluginStates<typeof plugins>;
3301
+ * // Result: { config: AuthConfig } & { dbConnected: boolean }
2012
3302
  */
2013
- interface StreamMetrics {
2014
- eventsSent: number;
2015
- eventsDropped: number;
2016
- bytesWritten: number;
2017
- bufferHighWatermark: number;
2018
- lastEventTime: number;
2019
- }
2020
-
3303
+ type ComposePluginStates<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginState<T[number]>>;
3304
+ /**
3305
+ * Composes service contributions from an array of middleware
3306
+ * Merges all service types into a single intersection type
3307
+ *
3308
+ * @template T - ReadonlyArray of Middleware
3309
+ * @returns Intersection of all service contributions
3310
+ *
3311
+ * @example
3312
+ * const middlewares = [dbMiddleware, cacheMiddleware] as const;
3313
+ * type ComposedServices = ComposeServices<typeof middlewares>;
3314
+ * // Result: { db: Database } & { cache: Cache }
3315
+ */
3316
+ type ComposeMiddlewareServices<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareServices<T[number]>>;
3317
+ /**
3318
+ * Composes service contributions from an array of plugins
3319
+ * Merges all service types into a single intersection type
3320
+ *
3321
+ * @template T - ReadonlyArray of Plugin
3322
+ * @returns Intersection of all service contributions
3323
+ *
3324
+ * @example
3325
+ * const plugins = [dbPlugin, cachePlugin] as const;
3326
+ * type ComposedServices = ComposePluginServices<typeof plugins>;
3327
+ * // Result: { db: Database } & { cache: Cache }
3328
+ */
3329
+ type ComposePluginServices<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginServices<T[number]>>;
3330
+ /**
3331
+ * Safe version of ExtractState that handles edge cases
3332
+ * @template T - The middleware type to extract from
3333
+ * @returns The state type, handling never/any/unknown gracefully
3334
+ */
3335
+ type SafeExtractMiddlewareState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<infer S, any> ? unknown extends S ? {} : S : {};
3336
+ /**
3337
+ * Safe version of ExtractPluginState that handles edge cases
3338
+ * @template T - The plugin type to extract from
3339
+ * @returns The state type, handling never/any/unknown gracefully
3340
+ */
3341
+ type SafeExtractPluginState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<infer S, any> ? unknown extends S ? {} : S : {};
3342
+ /**
3343
+ * Safe version of ExtractServices that handles edge cases
3344
+ * @template T - The middleware type to extract from
3345
+ * @returns The services type, handling never/any/unknown gracefully
3346
+ */
3347
+ type SafeExtractMiddlewareServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<any, infer S> ? unknown extends S ? {} : S : {};
2021
3348
  /**
2022
- * SSE Client Types for BlaizeJS
2023
- * Location: packages/blaize-client/src/sse/types.ts
3349
+ * Safe version of ExtractPluginServices that handles edge cases
3350
+ * @template T - The plugin type to extract from
3351
+ * @returns The services type, handling never/any/unknown gracefully
2024
3352
  */
2025
-
3353
+ type SafeExtractPluginServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<any, infer S> ? unknown extends S ? {} : S : {};
2026
3354
  /**
2027
- * Event handlers map
3355
+ * Composes state with better edge case handling
3356
+ * @template T - ReadonlyArray of Middleware
3357
+ * @returns Safely composed state types
2028
3358
  */
2029
- interface EventHandlers {
2030
- [event: string]: Set<(data: any) => void>;
2031
- }
3359
+ type SafeComposeMiddlewareStates<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Middleware ? Rest extends ReadonlyArray<Middleware> ? SafeExtractMiddlewareState<First> & SafeComposeMiddlewareStates<Rest> : SafeExtractMiddlewareState<First> : {} : UnionToIntersection<SafeExtractMiddlewareState<T[number]>>;
2032
3360
  /**
2033
- * SSE connection configuration options
3361
+ * Composes plugin state with better edge case handling
3362
+ * @template T - ReadonlyArray of Plugin
3363
+ * @returns Safely composed state types
2034
3364
  */
2035
- interface SSEClientOptions {
2036
- headers?: Record<string, string>;
2037
- withCredentials?: boolean;
2038
- reconnect?: {
2039
- enabled: boolean;
2040
- maxAttempts?: number;
2041
- strategy?: ReconnectStrategy;
2042
- initialDelay?: number;
2043
- };
2044
- bufferMissedEvents?: boolean;
2045
- maxMissedEvents?: number;
2046
- heartbeatTimeout?: number;
2047
- parseJSON?: boolean;
2048
- /**
2049
- * Whether to wait for connection before resolving the promise.
2050
- * If false, returns the client immediately without waiting.
2051
- * Default: true
2052
- */
2053
- waitForConnection?: boolean;
2054
- /**
2055
- * Optional timeout for initial connection in milliseconds.
2056
- * If not set, no timeout is applied (relies on EventSource native timeout).
2057
- * Only applies if waitForConnection is true.
2058
- */
2059
- connectionTimeout?: number;
2060
- }
3365
+ type SafeComposePluginStates<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Plugin<any, any> ? Rest extends ReadonlyArray<Plugin<any, any>> ? SafeExtractPluginState<First> & SafeComposePluginStates<Rest> : SafeExtractPluginState<First> : {} : UnionToIntersection<SafeExtractPluginState<T[number]>>;
2061
3366
  /**
2062
- * Metrics for SSE connection monitoring
3367
+ * Composes services with better edge case handling
3368
+ * @template T - ReadonlyArray of Middleware
3369
+ * @returns Safely composed service types
2063
3370
  */
2064
- interface SSEClientMetrics {
2065
- eventsReceived: number;
2066
- bytesReceived: number;
2067
- connectionDuration: number;
2068
- reconnectAttempts: number;
2069
- lastEventId?: string;
2070
- }
3371
+ type SafeComposeMiddlewareServices<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Middleware ? Rest extends ReadonlyArray<Middleware> ? SafeExtractMiddlewareServices<First> & SafeComposeMiddlewareServices<Rest> : SafeExtractMiddlewareServices<First> : {} : UnionToIntersection<SafeExtractMiddlewareServices<T[number]>>;
2071
3372
  /**
2072
- * Reconnection delay calculation strategy
3373
+ * Composes plugin services with better edge case handling
3374
+ * @template T - ReadonlyArray of Plugin
3375
+ * @returns Safely composed service types
2073
3376
  */
2074
- type ReconnectStrategy = (attempt: number) => number;
3377
+ type SafeComposePluginServices<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Plugin<any, any> ? Rest extends ReadonlyArray<Plugin<any, any>> ? SafeExtractPluginServices<First> & SafeComposePluginServices<Rest> : SafeExtractPluginServices<First> : {} : UnionToIntersection<SafeExtractPluginServices<T[number]>>;
2075
3378
  /**
2076
- * SSE Client interface with type-safe event handling
3379
+ * Utility to merge two state types
3380
+ * Handles conflicts by using the rightmost (latest) type
3381
+ *
3382
+ * @template A - First state type
3383
+ * @template B - Second state type
3384
+ * @returns Merged state with B taking precedence
2077
3385
  */
2078
- interface SSEClient<TEvents extends Record<string, unknown> = Record<string, unknown>> {
2079
- on<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
2080
- on(event: 'error', handler: (error: BlaizeError) => void): void;
2081
- on(event: 'open', handler: () => void): void;
2082
- on(event: 'close', handler: (event: CloseEvent) => void): void;
2083
- off<K extends keyof TEvents>(event: K & string, handler?: (data: TEvents[K]) => void): void;
2084
- off(event: 'error', handler?: (error: BlaizeError) => void): void;
2085
- off(event: 'open', handler?: () => void): void;
2086
- off(event: 'close', handler?: (event: CloseEvent) => void): void;
2087
- once<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
2088
- once(event: 'error', handler: (error: BlaizeError) => void): void;
2089
- once(event: 'open', handler: () => void): void;
2090
- once(event: 'close', handler: (event: CloseEvent) => void): void;
2091
- close(): void;
2092
- readonly state: SSEConnectionState;
2093
- readonly metrics: SSEClientMetrics;
2094
- readonly lastEventId?: string;
2095
- }
3386
+ type MergeStates<A, B> = Omit<A, keyof B> & B;
2096
3387
  /**
2097
- * Close event for SSE connections
3388
+ * Utility to merge two service types
3389
+ * Handles conflicts by using the rightmost (latest) type
3390
+ *
3391
+ * @template A - First services type
3392
+ * @template B - Second services type
3393
+ * @returns Merged services with B taking precedence
2098
3394
  */
2099
- interface CloseEvent {
2100
- reconnect: boolean;
2101
- reason?: string;
2102
- }
3395
+ type MergeServices<A, B> = Omit<A, keyof B> & B;
2103
3396
  /**
2104
- * Internal SSE connection factory
2105
- * Returns a Promise that resolves to an SSEClient instance
3397
+ * Extract both state and services from a middleware at once
3398
+ * @template T - The middleware type
3399
+ * @returns Object with state and services types
2106
3400
  */
2107
- type SSEConnectionFactory<TEvents extends Record<string, unknown> = Record<string, unknown>> = (options?: SSEClientOptions) => Promise<SSEClient<TEvents>>;
2108
-
2109
- type ExtractMethod<T> = T extends {
2110
- GET: any;
2111
- } ? 'GET' : T extends {
2112
- POST: any;
2113
- } ? 'POST' : T extends {
2114
- PUT: any;
2115
- } ? 'PUT' : T extends {
2116
- DELETE: any;
2117
- } ? 'DELETE' : T extends {
2118
- PATCH: any;
2119
- } ? 'PATCH' : T extends {
2120
- HEAD: any;
2121
- } ? 'HEAD' : T extends {
2122
- OPTIONS: any;
2123
- } ? 'OPTIONS' : never;
2124
- type BuildRoutesRegistry<TRoutes extends Record<string, any>> = {
2125
- [Method in ExtractMethod<TRoutes[keyof TRoutes]> as `$${Lowercase<Method>}`]: {
2126
- [K in keyof TRoutes as ExtractMethod<TRoutes[K]> extends Method ? K : never]: TRoutes[K];
2127
- };
2128
- };
2129
- type GetRouteMethodOptions<TRoute> = TRoute extends {
2130
- GET: infer M;
2131
- } ? M : TRoute extends {
2132
- POST: infer M;
2133
- } ? M : TRoute extends {
2134
- PUT: infer M;
2135
- } ? M : TRoute extends {
2136
- DELETE: infer M;
2137
- } ? M : TRoute extends {
2138
- PATCH: infer M;
2139
- } ? M : TRoute extends {
2140
- HEAD: infer M;
2141
- } ? M : TRoute extends {
2142
- OPTIONS: infer M;
2143
- } ? M : never;
2144
- type IsNever$1<T> = [T] extends [never] ? true : false;
2145
- type BuildArgsObject<P, Q, B> = (IsNever$1<P> extends true ? {} : {
2146
- params: Infer<P>;
2147
- }) & (IsNever$1<Q> extends true ? {} : {
2148
- query: Infer<Q>;
2149
- }) & (IsNever$1<B> extends true ? {} : {
2150
- body: Infer<B>;
2151
- });
2152
- type IsEmptyObject<T> = keyof T extends never ? true : false;
2153
- type BuildArgs<P, Q, B> = IsEmptyObject<BuildArgsObject<P, Q, B>> extends true ? void : BuildArgsObject<P, Q, B>;
2154
- type CreateClientMethod<TRoute> = GetRouteMethodOptions<TRoute> extends RouteMethodOptions<infer P, infer Q, infer B, infer R> ? BuildArgs<P, Q, B> extends void ? () => Promise<R extends z.ZodType ? Infer<R> : unknown> : (args: BuildArgs<P, Q, B>) => Promise<R extends z.ZodType ? Infer<R> : unknown> : never;
2155
- type CreateClient<TRoutes extends Record<string, Record<string, any>>> = {
2156
- [Method in keyof TRoutes]: {
2157
- [RouteName in keyof TRoutes[Method]]: CreateClientMethod<TRoutes[Method][RouteName]>;
2158
- };
3401
+ type ExtractMiddlewareTypes<T> = {
3402
+ state: ExtractMiddlewareState<T>;
3403
+ services: ExtractMiddlewareServices<T>;
2159
3404
  };
2160
- interface ClientConfig {
2161
- baseUrl: string;
2162
- defaultHeaders?: Record<string, string>;
2163
- timeout?: number;
2164
- sse?: SSEClientOptions;
2165
- }
2166
- interface InternalRequestArgs {
2167
- params?: Record<string, any>;
2168
- query?: Record<string, any>;
2169
- body?: any;
2170
- }
2171
- interface RequestOptions {
2172
- method: string;
2173
- url: string;
2174
- headers: Record<string, string>;
2175
- body?: string;
2176
- timeout: number;
2177
- }
2178
3405
  /**
2179
- * Detect if a route has SSE support
2180
- * SSE routes have a special 'SSE' method key
3406
+ * Extract both state and services from a plugin at once
3407
+ * @template T - The plugin type
3408
+ * @returns Object with state and services types
2181
3409
  */
2182
- type HasSSEMethod<TRoute> = TRoute extends {
2183
- SSE: any;
2184
- } ? true : false;
3410
+ type ExtractPluginTypes<T> = {
3411
+ state: ExtractPluginState<T>;
3412
+ services: ExtractPluginServices<T>;
3413
+ };
2185
3414
  /**
2186
- * Extract SSE event types from route schema
3415
+ * Compose both state and services from middleware array at once
3416
+ * @template T - ReadonlyArray of Middleware
3417
+ * @returns Object with composed state and services
2187
3418
  */
2188
- type ExtractSSEEvents<TRoute> = TRoute extends {
2189
- SSE: {
2190
- events?: infer E;
2191
- };
2192
- } ? E extends z.ZodType ? z.infer<E> : Record<string, unknown> : Record<string, unknown>;
3419
+ type ComposeMiddlewareTypes<T extends ReadonlyArray<Middleware>> = {
3420
+ state: ComposeMiddlewareStates<T>;
3421
+ services: ComposeMiddlewareServices<T>;
3422
+ };
2193
3423
  /**
2194
- * Extract SSE query parameters from route
3424
+ * Compose both state and services from plugin array at once
3425
+ * @template T - ReadonlyArray of Plugin
3426
+ * @returns Object with composed state and services
2195
3427
  */
2196
- type ExtractSSEQuery<TRoute> = TRoute extends {
2197
- SSE: {
2198
- schema?: {
2199
- query?: infer Q;
2200
- };
2201
- };
2202
- } ? Q extends z.ZodType ? z.infer<Q> : Record<string, unknown> : never;
3428
+ type ComposePluginTypes<T extends ReadonlyArray<Plugin<any, any>>> = {
3429
+ state: ComposePluginStates<T>;
3430
+ services: ComposePluginServices<T>;
3431
+ };
2203
3432
  /**
2204
- * Extract SSE params from route
3433
+ * Type guard to check if a value is a Middleware
3434
+ * @param value - Value to check
3435
+ * @returns True if value is a Middleware
2205
3436
  */
2206
- type ExtractSSEParams<TRoute> = TRoute extends {
2207
- SSE: {
2208
- schema?: {
2209
- params?: infer P;
2210
- };
2211
- };
2212
- } ? P extends z.ZodType ? z.infer<P> : Record<string, string> : never;
3437
+ declare function isMiddleware(value: unknown): value is Middleware;
2213
3438
  /**
2214
- * Build SSE method arguments
3439
+ * Type guard to check if a value is a Plugin
3440
+ * @param value - Value to check
3441
+ * @returns True if value is a Plugin
2215
3442
  */
2216
- type BuildSSEArgs<TRoute> = ExtractSSEParams<TRoute> extends never ? ExtractSSEQuery<TRoute> extends never ? {
2217
- options?: SSEClientOptions;
2218
- } : {
2219
- query: ExtractSSEQuery<TRoute>;
2220
- options?: SSEClientOptions;
2221
- } : ExtractSSEQuery<TRoute> extends never ? {
2222
- params: ExtractSSEParams<TRoute>;
2223
- options?: SSEClientOptions;
2224
- } : {
2225
- params: ExtractSSEParams<TRoute>;
2226
- query: ExtractSSEQuery<TRoute>;
2227
- options?: SSEClientOptions;
2228
- };
3443
+ declare function isPlugin(value: unknown): value is Plugin;
3444
+ /**
3445
+ * Type helper for middleware arrays
3446
+ * Ensures proper readonly array typing for composition
3447
+ *
3448
+ * @example
3449
+ * const middlewares = asMiddlewareArray([auth, logger, cache]);
3450
+ * type State = ComposeStates<typeof middlewares>;
3451
+ */
3452
+ declare function asMiddlewareArray<T extends ReadonlyArray<Middleware>>(middlewares: T): T;
2229
3453
  /**
2230
- * Create SSE client method
3454
+ * Type helper for plugin arrays
3455
+ * Ensures proper readonly array typing for composition
3456
+ *
3457
+ * @example
3458
+ * const plugins = asPluginArray([dbPlugin, cachePlugin]);
3459
+ * type Services = ComposePluginServices<typeof plugins>;
2231
3460
  */
2232
- type CreateSSEMethod<TRoute> = HasSSEMethod<TRoute> extends true ? BuildSSEArgs<TRoute> extends {
2233
- options?: SSEClientOptions;
2234
- } ? (args?: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : (args: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : never;
3461
+ declare function asPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(plugins: T): T;
2235
3462
  /**
2236
- * Extract SSE routes from registry
3463
+ * Create a typed middleware array with inferred types
3464
+ * Useful for getting proper const assertions
3465
+ *
3466
+ * @example
3467
+ * const middlewares = createMiddlewareArray(auth, logger, cache);
3468
+ * type State = ComposeStates<typeof middlewares>;
2237
3469
  */
2238
- type ExtractSSERoutes<TRoutes extends Record<string, any>> = {
2239
- [K in keyof TRoutes as HasSSEMethod<TRoutes[K]> extends true ? K : never]: TRoutes[K];
2240
- };
3470
+ declare function createMiddlewareArray<T extends ReadonlyArray<Middleware>>(...middlewares: T): T;
2241
3471
  /**
2242
- * Enhanced client with SSE support
3472
+ * Create a typed plugin array with inferred types
3473
+ * Useful for getting proper const assertions
3474
+ *
3475
+ * @example
3476
+ * const plugins = createPluginArray(dbPlugin, cachePlugin);
3477
+ * type Services = ComposePluginServices<typeof plugins>;
2243
3478
  */
2244
- type CreateEnhancedClient<TRoutes extends Record<string, any>, TRegistry> = TRegistry & {
2245
- $sse: {
2246
- [K in keyof ExtractSSERoutes<TRoutes>]: CreateSSEMethod<TRoutes[K]>;
2247
- };
2248
- };
3479
+ declare function createPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(...plugins: T): T;
2249
3480
 
2250
3481
  /**
2251
- * BlaizeJS Server Module - Enhanced with Correlation Configuration
3482
+ * Console Transport for Development
2252
3483
  *
2253
- * Provides the core HTTP/2 server implementation with HTTP/1.1 fallback
2254
- * and correlation ID tracking configuration.
3484
+ * Pretty-prints logs with colors for human-readable development output.
3485
+ * Uses Node.js built-in util.inspect for metadata formatting.
3486
+ *
3487
+ * @packageDocumentation
2255
3488
  */
2256
3489
 
2257
- type UnknownServer = Server<Record<string, unknown>, Record<string, unknown>>;
2258
- interface Http2Options {
2259
- enabled?: boolean | undefined;
2260
- keyFile?: string | undefined;
2261
- certFile?: string | undefined;
2262
- }
2263
- interface StartOptions {
2264
- port?: number;
2265
- host?: string;
2266
- }
2267
- interface StopOptions {
2268
- timeout?: number;
2269
- plugins?: Plugin[];
2270
- onStopping?: () => Promise<void> | void;
2271
- onStopped?: () => Promise<void> | void;
2272
- }
2273
3490
  /**
2274
- * Correlation ID configuration options
3491
+ * Console transport for development logging
3492
+ *
3493
+ * Outputs colorized, human-readable logs to the console.
3494
+ * Uses console.log/warn/error appropriately based on log level.
3495
+ *
3496
+ * Features:
3497
+ * - Colorized log levels (debug=gray, info=blue, warn=yellow, error=red)
3498
+ * - Pretty-printed metadata with util.inspect
3499
+ * - Error objects automatically serialized with stack traces
3500
+ * - Stateless - safe for concurrent logging
3501
+ *
3502
+ * @example
3503
+ * ```typescript
3504
+ * import { ConsoleTransport } from './transports';
3505
+ *
3506
+ * const transport = new ConsoleTransport();
3507
+ *
3508
+ * transport.write('info', 'User login', {
3509
+ * userId: '123',
3510
+ * method: 'oauth',
3511
+ * timestamp: '2025-10-20T15:30:00Z'
3512
+ * });
3513
+ *
3514
+ * // Output:
3515
+ * // [INFO] User login
3516
+ * // {
3517
+ * // userId: '123',
3518
+ * // method: 'oauth',
3519
+ * // timestamp: '2025-10-20T15:30:00Z'
3520
+ * // }
3521
+ * ```
2275
3522
  */
2276
- interface CorrelationOptions {
2277
- /**
2278
- * The HTTP header name to use for correlation IDs
2279
- * @default 'x-correlation-id'
2280
- */
2281
- headerName?: string;
3523
+ declare class ConsoleTransport implements BlaizeLogTransport {
2282
3524
  /**
2283
- * Custom correlation ID generator function
2284
- * @default () => `req_${timestamp}_${random}`
3525
+ * Write a log entry to the console
3526
+ *
3527
+ * @param level - Log level
3528
+ * @param message - Log message
3529
+ * @param meta - Structured metadata
2285
3530
  */
2286
- generator?: () => string;
3531
+ write(level: LogLevel, message: string, meta: LogMetadata): void;
2287
3532
  }
3533
+
2288
3534
  /**
2289
- * Server options for configuring the BlaizeJS server
3535
+ * JSON Transport for Production
3536
+ *
3537
+ * Outputs single-line JSON logs for log aggregators and monitoring systems.
3538
+ * Handles circular references and serializes Error objects.
3539
+ *
3540
+ * @packageDocumentation
2290
3541
  */
2291
- interface ServerOptionsInput {
2292
- /** Port to listen on (default: 3000) */
2293
- port?: number;
2294
- /** Host to bind to (default: localhost) */
2295
- host?: string;
2296
- /** Directory containing route files (default: ./routes) */
2297
- routesDir?: string;
2298
- /** HTTP/2 options */
2299
- http2?: {
2300
- /** Enable HTTP/2 (default: true) */
2301
- enabled?: boolean | undefined;
2302
- /** Path to key file for HTTPS/HTTP2 */
2303
- keyFile?: string | undefined;
2304
- /** Path to certificate file for HTTPS/HTTP2 */
2305
- certFile?: string | undefined;
2306
- };
2307
- /** Global middleware to apply to all routes */
2308
- middleware?: Middleware[];
2309
- /** Plugins to register */
2310
- plugins?: Plugin[];
3542
+
3543
+ /**
3544
+ * JSON transport for production logging
3545
+ *
3546
+ * Outputs single-line JSON to stdout for log aggregators (CloudWatch,
3547
+ * Datadog, Splunk, etc.). Handles circular references safely and
3548
+ * serializes Error objects with stack traces.
3549
+ *
3550
+ * Features:
3551
+ * - Single-line JSON output (no pretty-printing)
3552
+ * - Circular reference handling via replacer function
3553
+ * - Error objects serialized with message, name, and stack
3554
+ * - Stateless - safe for concurrent logging
3555
+ * - All metadata flattened into top-level JSON object
3556
+ *
3557
+ * @example
3558
+ * ```typescript
3559
+ * import { JSONTransport } from './transports';
3560
+ *
3561
+ * const transport = new JSONTransport();
3562
+ *
3563
+ * transport.write('info', 'User login', {
3564
+ * userId: '123',
3565
+ * method: 'oauth',
3566
+ * timestamp: '2025-10-20T15:30:00Z',
3567
+ * correlationId: 'req_abc123'
3568
+ * });
3569
+ *
3570
+ * // Output (single line):
3571
+ * // {"level":"info","message":"User login","userId":"123","method":"oauth","timestamp":"2025-10-20T15:30:00Z","correlationId":"req_abc123"}
3572
+ * ```
3573
+ *
3574
+ * @example With Error Object
3575
+ * ```typescript
3576
+ * const error = new Error('Database connection failed');
3577
+ *
3578
+ * transport.write('error', 'Operation failed', {
3579
+ * error,
3580
+ * retryCount: 3
3581
+ * });
3582
+ *
3583
+ * // Output:
3584
+ * // {"level":"error","message":"Operation failed","error":{"message":"Database connection failed","name":"Error","stack":"Error: Database..."},"retryCount":3}
3585
+ * ```
3586
+ */
3587
+ declare class JSONTransport implements BlaizeLogTransport {
2311
3588
  /**
2312
- * Correlation ID configuration
2313
- * @since 0.4.0
3589
+ * Write a log entry as single-line JSON to stdout
3590
+ *
3591
+ * @param level - Log level
3592
+ * @param message - Log message
3593
+ * @param meta - Structured metadata
2314
3594
  */
2315
- correlation?: CorrelationOptions;
3595
+ write(level: LogLevel, message: string, meta: LogMetadata): void;
2316
3596
  /**
2317
- * CORS configuration
2318
- *
2319
- * - `true`: Enable CORS with development defaults (allow all origins)
2320
- * - `false`: Disable CORS (no headers set)
2321
- * - `CorsOptions`: Custom CORS configuration
2322
- *
2323
- * @default false (CORS disabled)
2324
- * @since 0.5.0
2325
- *
2326
- * @example
2327
- * ```typescript
2328
- * // Enable with dev defaults
2329
- * const server = createServer({ cors: true });
3597
+ * Flush any buffered logs (optional)
2330
3598
  *
2331
- * // Custom configuration
2332
- * const server = createServer({
2333
- * cors: {
2334
- * origin: 'https://example.com',
2335
- * credentials: true,
2336
- * maxAge: 86400
2337
- * }
2338
- * });
3599
+ * Currently a no-op since we write directly to stdout.
3600
+ * Can be implemented for batching in the future if needed.
2339
3601
  *
2340
- * // Disable CORS
2341
- * const server = createServer({ cors: false });
2342
- * ```
3602
+ * @returns Promise that resolves immediately
2343
3603
  */
2344
- cors?: CorsOptions | boolean;
2345
- bodyLimits?: Partial<BodyLimits>;
3604
+ flush(): Promise<void>;
2346
3605
  }
3606
+
2347
3607
  /**
2348
- * Configuration for a BlaizeJS server
3608
+ * Null Transport for Testing
3609
+ *
3610
+ * Silent transport that discards all logs. Used in tests to suppress output.
3611
+ *
3612
+ * @packageDocumentation
2349
3613
  */
2350
- interface ServerOptions {
2351
- /** Port to listen on (default: 3000) */
2352
- port: number;
2353
- /** Host to bind to (default: localhost) */
2354
- host: string;
2355
- /** Directory containing route files (default: ./routes) */
2356
- routesDir: string;
2357
- /** HTTP/2 options */
2358
- http2?: {
2359
- /** Enable HTTP/2 (default: true) */
2360
- enabled?: boolean | undefined;
2361
- /** Path to key file for HTTPS/HTTP2 */
2362
- keyFile?: string | undefined;
2363
- /** Path to certificate file for HTTPS/HTTP2 */
2364
- certFile?: string | undefined;
2365
- };
2366
- /** Global middleware to apply to all routes */
2367
- middleware?: Middleware[];
2368
- /** Plugins to register */
2369
- plugins?: Plugin[];
2370
- /**
2371
- * Correlation ID configuration
2372
- * @since 0.4.0
2373
- */
2374
- correlation?: CorrelationOptions;
2375
- /**
2376
- * CORS configuration
2377
- * @since 0.5.0
2378
- */
2379
- cors?: CorsOptions | boolean;
2380
- bodyLimits: BodyLimits;
2381
- }
3614
+
2382
3615
  /**
2383
- * BlaizeJS Server instance with generic type accumulation
3616
+ * Null transport for testing and silent logging
2384
3617
  *
2385
- * @template TState - The accumulated state type from middleware
2386
- * @template TServices - The accumulated services type from middleware and plugins
3618
+ * Discards all log entries without producing any output. Useful for:
3619
+ * - Unit tests that don't care about log output
3620
+ * - Benchmarks where logging overhead should be minimal
3621
+ * - Temporarily disabling logging without changing code
3622
+ *
3623
+ * Features:
3624
+ * - Zero overhead - no processing or I/O
3625
+ * - Stateless - safe for concurrent logging
3626
+ * - No output to stdout, stderr, or files
2387
3627
  *
3628
+ * @example In Tests
3629
+ * ```typescript
3630
+ * import { NullTransport } from './transports';
3631
+ * import { createLogger } from './Logger';
3632
+ *
3633
+ * describe('MyService', () => {
3634
+ * const logger = createLogger({
3635
+ * transport: new NullTransport() // Suppress logs in tests
3636
+ * });
3637
+ *
3638
+ * test('performs operation', () => {
3639
+ * const service = new MyService(logger);
3640
+ * service.doWork(); // No log output
3641
+ * });
3642
+ * });
3643
+ * ```
3644
+ *
3645
+ * @example Temporary Disable
3646
+ * ```typescript
3647
+ * // Temporarily disable logging without changing business logic
3648
+ * const logger = createLogger({
3649
+ * transport: new NullTransport()
3650
+ * });
3651
+ *
3652
+ * logger.info('This message is discarded');
3653
+ * logger.error('This error is discarded');
3654
+ * ```
2388
3655
  */
2389
- interface Server<TState, TServices> {
2390
- /** The underlying HTTP or HTTP/2 server */
2391
- server: http.Server | http2.Http2Server | undefined;
2392
- /** The port the server is configured to listen on */
2393
- port: number;
2394
- /** CORS configuration for this server */
2395
- corsOptions?: CorsOptions | boolean;
2396
- /** Body size limits for incoming requests */
2397
- bodyLimits: BodyLimits;
2398
- /** The host the server is bound to */
2399
- host: string;
2400
- events: EventEmitter;
2401
- /** Direct access to registered plugins */
2402
- plugins: Plugin[];
2403
- /** Direct access to registered plugins */
2404
- middleware: Middleware[];
2405
- /** Internal property for signal hanlders */
2406
- _signalHandlers?: {
2407
- unregister: () => void;
2408
- };
2409
- /** Start the server and listen for connections */
2410
- listen: (port?: number, host?: string) => Promise<Server<TState, TServices>>;
2411
- /** Stop the server */
2412
- close: (stopOptions?: StopOptions) => Promise<void>;
2413
- /**
2414
- * Add global middleware to the server
2415
- *
2416
- * @param middleware - Single middleware or array of middleware to add
2417
- * @returns New Server instance with accumulated types from the middleware
2418
- *
2419
- * @example
2420
- * ```typescript
2421
- * // Single middleware
2422
- * const serverWithAuth = server.use(authMiddleware);
2423
- * // serverWithAuth has type Server<{user: User}, {auth: AuthService}>
2424
- *
2425
- * // Array of middleware
2426
- * const serverWithMiddleware = server.use([authMiddleware, loggerMiddleware]);
2427
- * // serverWithMiddleware has type Server<{user, requestId}, {auth, logger}>
2428
- * ```
2429
- */
2430
- use<MS, MSvc>(middleware: Middleware<MS, MSvc>): Server<TState & MS, TServices & MSvc>;
2431
- use<MW extends readonly Middleware<any, any>[]>(middleware: MW): Server<TState & UnionToIntersection<ExtractMiddlewareState<MW[number]>>, TServices & UnionToIntersection<ExtractMiddlewareServices<MW[number]>>>;
3656
+ declare class NullTransport implements BlaizeLogTransport {
2432
3657
  /**
2433
- * Register a plugin with the server
2434
- *
2435
- * @param plugin - Single plugin or array of plugins to register
2436
- * @returns Promise resolving to new Server instance with accumulated types
2437
- *
2438
- * @example
2439
- * ```typescript
2440
- * // Single plugin
2441
- * const serverWithDb = await server.register(databasePlugin);
2442
- * // serverWithDb has type Server<{}, {db: DatabaseService}>
3658
+ * Discard a log entry (no-op)
2443
3659
  *
2444
- * // Array of plugins
2445
- * const serverWithPlugins = await server.register([dbPlugin, cachePlugin]);
2446
- * // serverWithPlugins has type Server<{}, {db, cache}>
2447
- * ```
3660
+ * @param _level - Log level (unused)
3661
+ * @param _message - Log message (unused)
3662
+ * @param _meta - Structured metadata (unused)
2448
3663
  */
2449
- register<PS, PSvc>(plugin: Plugin<PS, PSvc>): Promise<Server<TState & PS, TServices & PSvc>>;
2450
- register<P extends readonly Plugin<any, any>[]>(plugin: P): Promise<Server<TState & UnionToIntersection<ExtractPluginState<P[number]>>, TServices & UnionToIntersection<ExtractPluginServices<P[number]>>>>;
2451
- /** Access to the routing system */
2452
- router: Router;
2453
- /** Context storage system */
2454
- context: AsyncLocalStorage<Context>;
2455
- pluginManager: PluginLifecycleManager;
3664
+ write(_level: LogLevel, _message: string, _meta: LogMetadata): void;
3665
+ /**
3666
+ * Flush any buffered logs (no-op)
3667
+ *
3668
+ * Since no logs are written, there's nothing to flush.
3669
+ *
3670
+ * @returns Promise that resolves immediately
3671
+ */
3672
+ flush(): Promise<void>;
2456
3673
  }
2457
- type RequestHandler = (req: http.IncomingMessage | http2.Http2ServerRequest, res: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
2458
3674
 
2459
3675
  /**
2460
- * BlaizeJS Plugin Module
3676
+ * Core Logger Implementation
2461
3677
  *
2462
- * Provides the plugin system for extending framework functionality.
3678
+ * Production-ready structured logger with level filtering, metadata redaction,
3679
+ * child loggers, and zero-overhead filtering for disabled log levels.
3680
+ *
3681
+ * @packageDocumentation
2463
3682
  */
2464
3683
 
2465
3684
  /**
2466
- * Plugin options
2467
- */
2468
- interface PluginOptions<_T = any> {
2469
- /** Plugin configuration */
2470
- [key: string]: any;
2471
- }
2472
- /**
2473
- * Plugin lifecycle hooks with full type safety
3685
+ * Core Logger class implementing ILogger interface
2474
3686
  *
2475
- * Plugins execute in this order:
2476
- * 1. register() - Add middleware, routes
2477
- * 2. initialize() - Create resources
2478
- * 3. onServerStart() - Start background work
2479
- * 4. onServerStop() - Stop background work
2480
- * 5. terminate() - Cleanup resources
3687
+ * Thread-safe via immutable inherited metadata. Supports zero-overhead
3688
+ * filtering - logs below the configured level return immediately with
3689
+ * no processing overhead.
3690
+ *
3691
+ * @example Basic Usage
3692
+ * ```typescript
3693
+ * const logger = new Logger({
3694
+ * level: 'info',
3695
+ * transport: new ConsoleTransport(),
3696
+ * redactKeys: ['password', 'apiKey'],
3697
+ * includeTimestamp: true
3698
+ * });
3699
+ *
3700
+ * logger.info('User login', { userId: '123', method: 'oauth' });
3701
+ * ```
3702
+ *
3703
+ * @example Child Logger
3704
+ * ```typescript
3705
+ * const parentLogger = createLogger({ level: 'info' });
3706
+ * const childLogger = parentLogger.child({ component: 'auth' });
3707
+ *
3708
+ * childLogger.info('Token verified');
3709
+ * // Output includes inherited metadata: { component: 'auth', ... }
3710
+ * ```
2481
3711
  */
2482
- interface PluginHooks<TState = {}, TServices = {}> {
3712
+ declare class Logger implements BlaizeLogger {
3713
+ private readonly config;
3714
+ private readonly inheritedMeta;
3715
+ private readonly minLevelPriority;
2483
3716
  /**
2484
- * Called when plugin is registered to server
2485
- *
2486
- * Use this hook to:
2487
- * - Add middleware via server.use()
2488
- * - Add routes via server.router.addRoute()
2489
- * - Subscribe to server events
3717
+ * Create a new Logger instance
2490
3718
  *
2491
- * @param server - BlaizeJS server instance
2492
- * @example
2493
- * ```typescript
2494
- * register: async (server) => {
2495
- * server.use(createMiddleware({
2496
- * handler: async (ctx, next) => {
2497
- * ctx.services.db = db;
2498
- * await next();
2499
- * },
2500
- * }));
2501
- * }
2502
- * ```
3719
+ * @param config - Resolved logger configuration
3720
+ * @param inheritedMeta - Metadata inherited from parent logger (optional)
2503
3721
  */
2504
- register?: (server: Server<TState, TServices>) => void | Promise<void>;
3722
+ constructor(config: ResolvedLoggerConfig, inheritedMeta?: LogMetadata);
2505
3723
  /**
2506
- * Called during server initialization
2507
- *
2508
- * Use this hook to:
2509
- * - Create database connections
2510
- * - Initialize services
2511
- * - Allocate resources
3724
+ * Log a debug message
2512
3725
  *
2513
- * @example
2514
- * ```typescript
2515
- * initialize: async () => {
2516
- * db = await Database.connect(config);
2517
- * }
2518
- * ```
3726
+ * @param message - The log message
3727
+ * @param meta - Optional metadata to attach
2519
3728
  */
2520
- initialize?: (server: Server<TState, TServices>) => void | Promise<void>;
3729
+ debug(message: string, meta?: LogMetadata): void;
2521
3730
  /**
2522
- * Called when server starts listening
2523
- *
2524
- * Use this hook to:
2525
- * - Start background workers
2526
- * - Start cron jobs
2527
- * - Begin health checks
3731
+ * Log an info message
2528
3732
  *
2529
- * @example
2530
- * ```typescript
2531
- * onServerStart: async () => {
2532
- * worker = new BackgroundWorker();
2533
- * await worker.start();
2534
- * }
2535
- * ```
3733
+ * @param message - The log message
3734
+ * @param meta - Optional metadata to attach
2536
3735
  */
2537
- onServerStart?: (server: Http2Server | Server$1) => void | Promise<void>;
3736
+ info(message: string, meta?: LogMetadata): void;
2538
3737
  /**
2539
- * Called when server stops listening
2540
- *
2541
- * Use this hook to:
2542
- * - Stop background workers
2543
- * - Flush buffers
2544
- * - Complete in-flight work
3738
+ * Log a warning message
2545
3739
  *
2546
- * @example
2547
- * ```typescript
2548
- * onServerStop: async () => {
2549
- * await worker.stop({ graceful: true });
2550
- * }
2551
- * ```
3740
+ * @param message - The log message
3741
+ * @param meta - Optional metadata to attach
2552
3742
  */
2553
- onServerStop?: (server: Http2Server | Server$1) => void | Promise<void>;
3743
+ warn(message: string, meta?: LogMetadata): void;
2554
3744
  /**
2555
- * Called during server termination
2556
- *
2557
- * Use this hook to:
2558
- * - Close database connections
2559
- * - Release file handles
2560
- * - Free memory
3745
+ * Log an error message
2561
3746
  *
2562
- * @example
2563
- * ```typescript
2564
- * terminate: async () => {
2565
- * await db?.close();
2566
- * }
2567
- * ```
2568
- */
2569
- terminate?: (server: Server<TState, TServices>) => void | Promise<void>;
2570
- }
2571
- /**
2572
- * Options for creating a plugin with createPlugin()
2573
- *
2574
- * @template TConfig - Plugin configuration shape
2575
- * @template TState - State added to context
2576
- * @template TServices - Services added to context
2577
- */
2578
- interface CreatePluginOptions<TConfig, TState = {}, TServices = {}> {
2579
- /**
2580
- * Plugin name (e.g., '@blaizejs/metrics')
2581
- * Must be unique within a server instance
3747
+ * @param message - The log message
3748
+ * @param meta - Optional metadata to attach
2582
3749
  */
2583
- name: string;
2584
- /**
2585
- * Semantic version (e.g., '1.0.0')
2586
- * Used for compatibility checks
2587
- */
2588
- version: string;
3750
+ error(message: string, meta?: LogMetadata): void;
2589
3751
  /**
2590
- * Default configuration values
2591
- * Merged with user config when plugin is created
3752
+ * Create a child logger with additional metadata
3753
+ *
3754
+ * Child loggers inherit all parent metadata and add their own.
3755
+ * Child metadata overrides parent metadata for the same keys.
3756
+ *
3757
+ * @param meta - Additional metadata for the child logger
3758
+ * @returns A new logger instance with merged metadata
2592
3759
  *
2593
3760
  * @example
2594
3761
  * ```typescript
2595
- * defaultConfig: {
2596
- * enabled: true,
2597
- * timeout: 30000,
2598
- * }
3762
+ * const parent = createLogger({ level: 'info' });
3763
+ * const child = parent.child({ component: 'database' });
3764
+ *
3765
+ * child.info('Query executed');
3766
+ * // Output includes: { component: 'database', ...parent metadata }
2599
3767
  * ```
2600
3768
  */
2601
- defaultConfig?: TConfig;
3769
+ child(meta: LogMetadata): BlaizeLogger;
2602
3770
  /**
2603
- * Setup function that returns lifecycle hooks
3771
+ * Flush any buffered logs and wait for completion
2604
3772
  *
2605
- * Receives merged config (defaultConfig + userConfig).
2606
- * Returns partial hook object - all hooks optional.
3773
+ * Delegates to the transport's flush method if it exists.
3774
+ * Use this during graceful shutdown to ensure all logs are written.
2607
3775
  *
2608
- * @param config - Merged configuration
2609
- * @returns Partial plugin hooks
3776
+ * @returns Promise that resolves when all logs are flushed
2610
3777
  *
2611
3778
  * @example
2612
3779
  * ```typescript
2613
- * setup: (config) => {
2614
- * let db: Database;
2615
- *
2616
- * return {
2617
- * initialize: async () => {
2618
- * db = await Database.connect(config);
2619
- * },
2620
- * terminate: async () => {
2621
- * await db?.close();
2622
- * },
2623
- * };
2624
- * }
3780
+ * process.on('SIGTERM', async () => {
3781
+ * await logger.flush();
3782
+ * process.exit(0);
3783
+ * });
2625
3784
  * ```
2626
3785
  */
2627
- setup: (config: TConfig) => Partial<PluginHooks<TState, TServices>>;
2628
- }
2629
- /**
2630
- * Plugin interface
2631
- */
2632
- interface Plugin<TState = {}, TServices = {}> extends PluginHooks<TState, TServices> {
2633
- /** Plugin name */
2634
- name: string;
2635
- /** Plugin version */
2636
- version: string;
3786
+ flush(): Promise<void>;
2637
3787
  /**
2638
- * Called when plugin is registered to server
3788
+ * Internal log method that handles all log levels
2639
3789
  *
2640
- * This hook is always present - createPlugin provides a default empty async function
2641
- * if not specified by the plugin author.
3790
+ * Fast-path: Returns immediately if log level is filtered.
3791
+ * This ensures zero overhead for disabled log levels.
2642
3792
  *
2643
- * @override Makes register required (not optional like in PluginHooks)
3793
+ * @param level - The log level
3794
+ * @param message - The log message
3795
+ * @param meta - Optional metadata to attach
2644
3796
  */
2645
- register: (server: Server<TState, TServices>) => void | Promise<void>;
3797
+ private log;
2646
3798
  /**
2647
- * Type carriers for compile-time type information
2648
- * These are never used at runtime but allow TypeScript to track types
3799
+ * Check if a log level should be output
3800
+ *
3801
+ * @param level - The log level to check
3802
+ * @returns true if the level should be logged
2649
3803
  */
2650
- _state?: TState;
2651
- _services?: TServices;
2652
- }
2653
- /**
2654
- * Plugin factory function
2655
- */
2656
- type PluginFactory<TConfig = any, TState = {}, TServices = {}> = (options?: Partial<TConfig>) => Plugin<TState, TServices>;
2657
- interface PluginLifecycleManager {
2658
- initializePlugins(server: Server<any, any>): Promise<void>;
2659
- terminatePlugins(server: Server<any, any>): Promise<void>;
2660
- onServerStart(server: Server<any, any>, httpServer: any): Promise<void>;
2661
- onServerStop(server: Server<any, any>, httpServer: any): Promise<void>;
2662
- }
2663
- interface PluginLifecycleOptions {
2664
- /** Continue initialization even if a plugin fails */
2665
- continueOnError?: boolean;
2666
- /** Log plugin lifecycle events */
2667
- debug?: boolean;
2668
- /** Custom error handler for plugin failures */
2669
- onError?: (plugin: Plugin, phase: string, error: Error) => void;
3804
+ private shouldLog;
3805
+ /**
3806
+ * Redact sensitive keys from metadata
3807
+ *
3808
+ * Performs case-insensitive shallow redaction. Only top-level keys
3809
+ * are checked and redacted - nested objects are not traversed.
3810
+ *
3811
+ * Matching keys are replaced with the string '[REDACTED]'.
3812
+ *
3813
+ * @param meta - The metadata to redact
3814
+ * @returns New metadata object with sensitive values redacted
3815
+ */
3816
+ private redact;
2670
3817
  }
2671
-
2672
- /**
2673
- * Type composition utilities for extracting and composing middleware type contributions
2674
- * @module composition
2675
- * @since v0.4.0
2676
- */
2677
-
2678
- /**
2679
- * Extracts the State type contribution from a middleware
2680
- * @template T - The middleware type to extract from
2681
- * @returns The state type if present, empty object otherwise
2682
- */
2683
- type ExtractMiddlewareState<T> = T extends Middleware<infer S, any> ? S : {};
2684
- /**
2685
- * Extracts the State type contribution from a plugin
2686
- * @template T - The plugin type to extract from
2687
- * @returns The state type if present, empty object otherwise
2688
- */
2689
- type ExtractPluginState<T> = T extends Plugin<infer S, any> ? S : {};
2690
- /**
2691
- * Extracts the Services type contribution from a middleware
2692
- * @template T - The middleware type to extract from
2693
- * @returns The services type if present, empty object otherwise
2694
- */
2695
- type ExtractMiddlewareServices<T> = T extends Middleware<any, infer S> ? S : {};
2696
- /**
2697
- * Extracts the Services type contribution from a plugin
2698
- * @template T - The plugin type to extract from
2699
- * @returns The services type if present, empty object otherwise
2700
- */
2701
- type ExtractPluginServices<T> = T extends Plugin<any, infer S> ? S : {};
2702
3818
  /**
2703
- * Utility type to convert a union type to an intersection type
2704
- * This is the magic that allows us to compose multiple middleware contributions
2705
- *
2706
- * @example
2707
- * type U = { a: string } | { b: number }
2708
- * type I = UnionToIntersection<U> // { a: string } & { b: number }
3819
+ * Create a logger with default configuration
2709
3820
  *
2710
- */
2711
- type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
2712
- /**
2713
- * Composes state contributions from an array of middleware
2714
- * Merges all state types into a single intersection type
3821
+ * Resolves defaults based on environment:
3822
+ * - Development: debug level, ConsoleTransport
3823
+ * - Production: info level, JSONTransport
2715
3824
  *
2716
- * @template T - ReadonlyArray of Middleware
2717
- * @returns Intersection of all state contributions
3825
+ * Core transports (ConsoleTransport, JSONTransport) are lazy-loaded by
3826
+ * the logger itself. Custom transports should be provided by application code.
2718
3827
  *
2719
- * @example
2720
- * const middlewares = [authMiddleware, loggerMiddleware] as const;
2721
- * type ComposedState = ComposeStates<typeof middlewares>;
2722
- * // Result: { user: User } & { requestId: string }
2723
- */
2724
- type ComposeMiddlewareStates<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareState<T[number]>>;
2725
- /**
2726
- * Composes state contributions from an array of plugins
2727
- * Merges all state types into a single intersection type
3828
+ * @param config - Partial logger configuration (all fields optional)
3829
+ * @returns A new Logger instance
2728
3830
  *
2729
- * @template T - ReadonlyArray of Plugin
2730
- * @returns Intersection of all state contributions
3831
+ * @example Development Logger (Default)
3832
+ * ```typescript
3833
+ * const logger = createLogger();
3834
+ * // Uses: level='debug', ConsoleTransport, timestamp=true, no redaction
2731
3835
  *
2732
- * @example
2733
- * const plugins = [authPlugin, dbPlugin] as const;
2734
- * type ComposedState = ComposePluginStates<typeof plugins>;
2735
- * // Result: { config: AuthConfig } & { dbConnected: boolean }
3836
+ * logger.debug('Starting application');
3837
+ * ```
3838
+ *
3839
+ * @example Production Logger (Default)
3840
+ * ```typescript
3841
+ * process.env.NODE_ENV = 'production';
3842
+ *
3843
+ * const logger = createLogger({
3844
+ * redactKeys: ['password', 'apiKey', 'secret']
3845
+ * });
3846
+ * // Uses: level='info', JSONTransport, timestamp=true, redaction enabled
3847
+ * ```
3848
+ *
3849
+ * @example Custom Transport (Application Code)
3850
+ * ```typescript
3851
+ * import { CustomTransport } from './my-transports';
3852
+ *
3853
+ * const logger = createLogger({
3854
+ * level: 'warn',
3855
+ * transport: new CustomTransport(), // Application provides custom transport
3856
+ * redactKeys: ['ssn', 'creditCard'],
3857
+ * includeTimestamp: false
3858
+ * });
3859
+ * ```
2736
3860
  */
2737
- type ComposePluginStates<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginState<T[number]>>;
3861
+ declare function createLogger(config?: Partial<ResolvedLoggerConfig>): Logger;
3862
+
2738
3863
  /**
2739
- * Composes service contributions from an array of middleware
2740
- * Merges all service types into a single intersection type
3864
+ * Global logger singleton instance
2741
3865
  *
2742
- * @template T - ReadonlyArray of Middleware
2743
- * @returns Intersection of all service contributions
3866
+ * This instance is available before server creation and can be used
3867
+ * anywhere in your application. When the server starts, it will be
3868
+ * configured with the server's logging options.
2744
3869
  *
2745
3870
  * @example
2746
- * const middlewares = [dbMiddleware, cacheMiddleware] as const;
2747
- * type ComposedServices = ComposeServices<typeof middlewares>;
2748
- * // Result: { db: Database } & { cache: Cache }
3871
+ * ```typescript
3872
+ * import { logger } from '@blaizejs/logger';
3873
+ *
3874
+ * logger.info('Application starting');
3875
+ * ```
2749
3876
  */
2750
- type ComposeMiddlewareServices<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareServices<T[number]>>;
3877
+ declare const logger: BlaizeLogger;
2751
3878
  /**
2752
- * Composes service contributions from an array of plugins
2753
- * Merges all service types into a single intersection type
3879
+ * Configure the global logger instance
2754
3880
  *
2755
- * @template T - ReadonlyArray of Plugin
2756
- * @returns Intersection of all service contributions
3881
+ * This function updates the global logger in-place so that all existing
3882
+ * imports automatically receive the new configuration. Called internally
3883
+ * by the server during creation.
3884
+ *
3885
+ * @param config - Partial logger configuration
2757
3886
  *
2758
3887
  * @example
2759
- * const plugins = [dbPlugin, cachePlugin] as const;
2760
- * type ComposedServices = ComposePluginServices<typeof plugins>;
2761
- * // Result: { db: Database } & { cache: Cache }
2762
- */
2763
- type ComposePluginServices<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginServices<T[number]>>;
2764
- /**
2765
- * Safe version of ExtractState that handles edge cases
2766
- * @template T - The middleware type to extract from
2767
- * @returns The state type, handling never/any/unknown gracefully
2768
- */
2769
- type SafeExtractMiddlewareState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<infer S, any> ? unknown extends S ? {} : S : {};
2770
- /**
2771
- * Safe version of ExtractPluginState that handles edge cases
2772
- * @template T - The plugin type to extract from
2773
- * @returns The state type, handling never/any/unknown gracefully
2774
- */
2775
- type SafeExtractPluginState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<infer S, any> ? unknown extends S ? {} : S : {};
2776
- /**
2777
- * Safe version of ExtractServices that handles edge cases
2778
- * @template T - The middleware type to extract from
2779
- * @returns The services type, handling never/any/unknown gracefully
2780
- */
2781
- type SafeExtractMiddlewareServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<any, infer S> ? unknown extends S ? {} : S : {};
2782
- /**
2783
- * Safe version of ExtractPluginServices that handles edge cases
2784
- * @template T - The plugin type to extract from
2785
- * @returns The services type, handling never/any/unknown gracefully
2786
- */
2787
- type SafeExtractPluginServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<any, infer S> ? unknown extends S ? {} : S : {};
2788
- /**
2789
- * Composes state with better edge case handling
2790
- * @template T - ReadonlyArray of Middleware
2791
- * @returns Safely composed state types
2792
- */
2793
- type SafeComposeMiddlewareStates<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Middleware ? Rest extends ReadonlyArray<Middleware> ? SafeExtractMiddlewareState<First> & SafeComposeMiddlewareStates<Rest> : SafeExtractMiddlewareState<First> : {} : UnionToIntersection<SafeExtractMiddlewareState<T[number]>>;
2794
- /**
2795
- * Composes plugin state with better edge case handling
2796
- * @template T - ReadonlyArray of Plugin
2797
- * @returns Safely composed state types
2798
- */
2799
- type SafeComposePluginStates<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Plugin<any, any> ? Rest extends ReadonlyArray<Plugin<any, any>> ? SafeExtractPluginState<First> & SafeComposePluginStates<Rest> : SafeExtractPluginState<First> : {} : UnionToIntersection<SafeExtractPluginState<T[number]>>;
2800
- /**
2801
- * Composes services with better edge case handling
2802
- * @template T - ReadonlyArray of Middleware
2803
- * @returns Safely composed service types
3888
+ * ```typescript
3889
+ * import { configureGlobalLogger } from '@blaizejs/logger';
3890
+ *
3891
+ * configureGlobalLogger({
3892
+ * level: 'warn',
3893
+ * redactKeys: ['password', 'apiKey']
3894
+ * });
3895
+ * ```
2804
3896
  */
2805
- type SafeComposeMiddlewareServices<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Middleware ? Rest extends ReadonlyArray<Middleware> ? SafeExtractMiddlewareServices<First> & SafeComposeMiddlewareServices<Rest> : SafeExtractMiddlewareServices<First> : {} : UnionToIntersection<SafeExtractMiddlewareServices<T[number]>>;
3897
+ declare function configureGlobalLogger(config: Partial<LoggerConfig>): void;
3898
+
2806
3899
  /**
2807
- * Composes plugin services with better edge case handling
2808
- * @template T - ReadonlyArray of Plugin
2809
- * @returns Safely composed service types
3900
+ * Compose multiple middleware functions into a single middleware function
2810
3901
  */
2811
- type SafeComposePluginServices<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends Plugin<any, any> ? Rest extends ReadonlyArray<Plugin<any, any>> ? SafeExtractPluginServices<First> & SafeComposePluginServices<Rest> : SafeExtractPluginServices<First> : {} : UnionToIntersection<SafeExtractPluginServices<T[number]>>;
3902
+ declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
3903
+
2812
3904
  /**
2813
- * Utility to merge two state types
2814
- * Handles conflicts by using the rightmost (latest) type
3905
+ * Create CORS middleware with the specified options
2815
3906
  *
2816
- * @template A - First state type
2817
- * @template B - Second state type
2818
- * @returns Merged state with B taking precedence
2819
- */
2820
- type MergeStates<A, B> = Omit<A, keyof B> & B;
2821
- /**
2822
- * Utility to merge two service types
2823
- * Handles conflicts by using the rightmost (latest) type
3907
+ * @param userOptions - CORS configuration options or boolean
3908
+ * @returns Middleware function that handles CORS
2824
3909
  *
2825
- * @template A - First services type
2826
- * @template B - Second services type
2827
- * @returns Merged services with B taking precedence
2828
- */
2829
- type MergeServices<A, B> = Omit<A, keyof B> & B;
2830
- /**
2831
- * Extract both state and services from a middleware at once
2832
- * @template T - The middleware type
2833
- * @returns Object with state and services types
2834
- */
2835
- type ExtractMiddlewareTypes<T> = {
2836
- state: ExtractMiddlewareState<T>;
2837
- services: ExtractMiddlewareServices<T>;
2838
- };
2839
- /**
2840
- * Extract both state and services from a plugin at once
2841
- * @template T - The plugin type
2842
- * @returns Object with state and services types
2843
- */
2844
- type ExtractPluginTypes<T> = {
2845
- state: ExtractPluginState<T>;
2846
- services: ExtractPluginServices<T>;
2847
- };
2848
- /**
2849
- * Compose both state and services from middleware array at once
2850
- * @template T - ReadonlyArray of Middleware
2851
- * @returns Object with composed state and services
2852
- */
2853
- type ComposeMiddlewareTypes<T extends ReadonlyArray<Middleware>> = {
2854
- state: ComposeMiddlewareStates<T>;
2855
- services: ComposeMiddlewareServices<T>;
2856
- };
2857
- /**
2858
- * Compose both state and services from plugin array at once
2859
- * @template T - ReadonlyArray of Plugin
2860
- * @returns Object with composed state and services
2861
- */
2862
- type ComposePluginTypes<T extends ReadonlyArray<Plugin<any, any>>> = {
2863
- state: ComposePluginStates<T>;
2864
- services: ComposePluginServices<T>;
2865
- };
2866
- /**
2867
- * Type guard to check if a value is a Middleware
2868
- * @param value - Value to check
2869
- * @returns True if value is a Middleware
3910
+ * @example
3911
+ * ```typescript
3912
+ * import { cors } from '@blaize-core/middleware/cors';
3913
+ *
3914
+ * // Development mode - allow all origins
3915
+ * server.use(cors(true));
3916
+ *
3917
+ * // Production - specific origin
3918
+ * server.use(cors({
3919
+ * origin: 'https://app.example.com',
3920
+ * credentials: true,
3921
+ * maxAge: 86400
3922
+ * }));
3923
+ *
3924
+ * // Multiple origins with regex
3925
+ * server.use(cors({
3926
+ * origin: [
3927
+ * 'https://app.example.com',
3928
+ * /^https:\/\/.*\.example\.com$/
3929
+ * ]
3930
+ * }));
3931
+ *
3932
+ * // Dynamic origin validation
3933
+ * server.use(cors({
3934
+ * origin: async (origin, ctx) => {
3935
+ * return await checkOriginAllowed(origin, ctx.state.user);
3936
+ * }
3937
+ * }));
3938
+ * ```
2870
3939
  */
2871
- declare function isMiddleware(value: unknown): value is Middleware;
3940
+ declare function cors(userOptions?: CorsOptions | boolean): Middleware;
3941
+
2872
3942
  /**
2873
- * Type guard to check if a value is a Plugin
2874
- * @param value - Value to check
2875
- * @returns True if value is a Plugin
3943
+ * Create a middleware
2876
3944
  */
2877
- declare function isPlugin(value: unknown): value is Plugin;
3945
+ declare function create$1<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
2878
3946
  /**
2879
- * Type helper for middleware arrays
2880
- * Ensures proper readonly array typing for composition
3947
+ * Create a middleware that only contributes state (no services)
3948
+ * Convenience helper for state-only middleware
3949
+ *
3950
+ * @template T - Type of state to contribute
3951
+ * @param handler - Middleware function that adds state
3952
+ * @returns Middleware that contributes state only
2881
3953
  *
2882
- * @example
2883
- * const middlewares = asMiddlewareArray([auth, logger, cache]);
2884
- * type State = ComposeStates<typeof middlewares>;
2885
3954
  */
2886
- declare function asMiddlewareArray<T extends ReadonlyArray<Middleware>>(middlewares: T): T;
3955
+ declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
2887
3956
  /**
2888
- * Type helper for plugin arrays
2889
- * Ensures proper readonly array typing for composition
3957
+ * Create a middleware that only contributes services (no state)
3958
+ * Convenience helper for service-only middleware
3959
+ *
3960
+ * @template T - Type of services to contribute
3961
+ * @param handler - Middleware function that adds services
3962
+ * @returns Middleware that contributes services only
2890
3963
  *
2891
- * @example
2892
- * const plugins = asPluginArray([dbPlugin, cachePlugin]);
2893
- * type Services = ComposePluginServices<typeof plugins>;
2894
3964
  */
2895
- declare function asPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(plugins: T): T;
3965
+ declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
3966
+
2896
3967
  /**
2897
- * Create a typed middleware array with inferred types
2898
- * Useful for getting proper const assertions
3968
+ * Request Logger Middleware
2899
3969
  *
2900
- * @example
2901
- * const middlewares = createMiddlewareArray(auth, logger, cache);
2902
- * type State = ComposeStates<typeof middlewares>;
3970
+ * Creates a child logger with request context and optionally logs request lifecycle events.
3971
+ * This middleware ALWAYS runs FIRST in the middleware chain to ensure all logs have request context.
3972
+ *
3973
+ * @packageDocumentation
2903
3974
  */
2904
- declare function createMiddlewareArray<T extends ReadonlyArray<Middleware>>(...middlewares: T): T;
3975
+
2905
3976
  /**
2906
- * Create a typed plugin array with inferred types
2907
- * Useful for getting proper const assertions
3977
+ * Request logger middleware factory
2908
3978
  *
2909
- * @example
2910
- * const plugins = createPluginArray(dbPlugin, cachePlugin);
2911
- * type Services = ComposePluginServices<typeof plugins>;
3979
+ * Creates middleware that:
3980
+ * 1. ALWAYS creates a child logger with request context (correlationId, method, path, ip)
3981
+ * 2. Replaces ctx.services.log with the child logger
3982
+ * 3. Optionally logs request lifecycle events if requestLogging is true
3983
+ *
3984
+ * The child logger ensures that all logs during the request lifecycle automatically
3985
+ * include request context, even if requestLogging is false.
3986
+ *
3987
+ * @param options - Request logger options (headers, query, etc.)
3988
+ * @returns Middleware function
3989
+ *
3990
+ * @example Basic Usage (with lifecycle logging)
3991
+ * ```typescript
3992
+ * import { createServer } from 'blaizejs';
3993
+ * import { requestLoggerMiddleware } from './logger/middleware';
3994
+ *
3995
+ * const server = createServer({
3996
+ * port: 3000,
3997
+ * logging: {
3998
+ * level: 'info',
3999
+ * requestLogging: true, // Enable lifecycle logs
4000
+ * requestLoggerOptions: {
4001
+ * includeHeaders: true,
4002
+ * includeQuery: true
4003
+ * }
4004
+ * }
4005
+ * });
4006
+ * ```
4007
+ *
4008
+ * @example Without Lifecycle Logging
4009
+ * ```typescript
4010
+ * const server = createServer({
4011
+ * logging: {
4012
+ * level: 'info',
4013
+ * requestLogging: false // No automatic logs, but ctx.services.log still has request context
4014
+ * }
4015
+ * });
4016
+ *
4017
+ * // In route handler:
4018
+ * export const GET = appRoute.get({
4019
+ * handler: async (ctx) => {
4020
+ * // ctx.services.log still includes correlationId, method, path automatically
4021
+ * ctx.services.log.info('Custom log message');
4022
+ * return { data: 'response' };
4023
+ * }
4024
+ * });
4025
+ * ```
4026
+ *
4027
+ * @example With Header Filtering
4028
+ * ```typescript
4029
+ * const middleware = requestLoggerMiddleware({
4030
+ * includeHeaders: true,
4031
+ * headerWhitelist: ['content-type', 'user-agent', 'accept']
4032
+ * }, true);
4033
+ *
4034
+ * // Logs will include only whitelisted headers
4035
+ * // Sensitive headers (authorization, cookie) are ALWAYS redacted
4036
+ * ```
2912
4037
  */
2913
- declare function createPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(...plugins: T): T;
4038
+ declare function requestLoggerMiddleware(options?: RequestLoggerOptions): Middleware;
2914
4039
 
2915
4040
  /**
2916
4041
  * Create a type-safe plugin with full IntelliSense support
@@ -3143,7 +4268,7 @@ declare function createRouteFactory<TState extends State = State, TServices exte
3143
4268
  options?: Record<string, unknown>;
3144
4269
  }) => {
3145
4270
  GET: {
3146
- handler: (ctx: any, params: any) => Promise<void>;
4271
+ handler: (ctx: any, params: any, logger: BlaizeLogger) => Promise<void>;
3147
4272
  schema?: {
3148
4273
  params?: (P extends never ? undefined : P) | undefined;
3149
4274
  query?: (Q extends never ? undefined : Q) | undefined;
@@ -3151,6 +4276,13 @@ declare function createRouteFactory<TState extends State = State, TServices exte
3151
4276
  middleware?: Middleware[];
3152
4277
  options?: Record<string, unknown>;
3153
4278
  };
4279
+ SSE: {
4280
+ schema: {
4281
+ params?: (P extends never ? undefined : P) | undefined;
4282
+ query?: (Q extends never ? undefined : Q) | undefined;
4283
+ events?: (E extends never ? undefined : E) | undefined;
4284
+ };
4285
+ };
3154
4286
  path: string;
3155
4287
  };
3156
4288
  };
@@ -3556,7 +4688,7 @@ declare class ServiceNotAvailableError extends BlaizeError<ServiceNotAvailableDe
3556
4688
  constructor(title: string, details?: ServiceNotAvailableDetails | undefined, correlationId?: string | undefined);
3557
4689
  }
3558
4690
 
3559
- declare const VERSION = "0.1.0";
4691
+ declare const VERSION: string;
3560
4692
  declare const ServerAPI: {
3561
4693
  createServer: typeof create;
3562
4694
  inferContext: typeof inferContext;
@@ -3582,6 +4714,7 @@ declare const MiddlewareAPI: {
3582
4714
  createStateMiddleware: typeof stateMiddleware;
3583
4715
  compose: typeof compose;
3584
4716
  cors: typeof cors;
4717
+ requestLoggerMiddleware: typeof requestLoggerMiddleware;
3585
4718
  };
3586
4719
  declare const PluginsAPI: {
3587
4720
  createPlugin: typeof createPlugin;
@@ -3594,6 +4727,9 @@ declare const Blaize: {
3594
4727
  createStateMiddleware: typeof stateMiddleware;
3595
4728
  createPlugin: typeof createPlugin;
3596
4729
  getCorrelationId: typeof getCorrelationId;
4730
+ configureGlobalLogger: typeof configureGlobalLogger;
4731
+ createLogger: typeof createLogger;
4732
+ logger: BlaizeLogger;
3597
4733
  Server: {
3598
4734
  createServer: typeof create;
3599
4735
  inferContext: typeof inferContext;
@@ -3619,6 +4755,7 @@ declare const Blaize: {
3619
4755
  createStateMiddleware: typeof stateMiddleware;
3620
4756
  compose: typeof compose;
3621
4757
  cors: typeof cors;
4758
+ requestLoggerMiddleware: typeof requestLoggerMiddleware;
3622
4759
  };
3623
4760
  Plugins: {
3624
4761
  createPlugin: typeof createPlugin;
@@ -3626,4 +4763,4 @@ declare const Blaize: {
3626
4763
  VERSION: string;
3627
4764
  };
3628
4765
 
3629
- export { Blaize, BlaizeError, type BlaizeErrorResponse, type BodyLimits, type BufferedEvent, type BuildRoutesRegistry, type BuildSSEArgs, type CacheConfig, type CacheEntry, type ClientConfig, type CloseEvent, type ComposeMiddlewareServices, type ComposeMiddlewareStates, type ComposeMiddlewareTypes, type ComposePluginServices, type ComposePluginStates, type ComposePluginTypes, ConflictError, type ConflictErrorDetails, type ConnectionEntry, type ConnectionRegistry, type Context, type ContextOptions, type ContextRequest, type ContextResponse, type CorrelationOptions, type CorsHttpMethod, type CorsOptions, type CorsOrigin, type CorsOriginCacheConfig, type CorsOriginCacheEntry, type CorsPreflightInfo, type CorsStats, type CorsValidationResult, type CreateClient, type CreateContextFn, type CreateDeleteRoute, type CreateEnhancedClient, type CreateGetRoute, type CreateHeadRoute, type CreateOptionsRoute, type CreatePatchRoute, type CreatePluginOptions, type CreatePostRoute, type CreatePutRoute, type CreateSSEMethod, type CreateSSERoute, type ErrorHandlerOptions, ErrorSeverity, type ErrorTransformContext, ErrorType, type EventHandlers, type ExtractMethod, type ExtractMiddlewareServices, type ExtractMiddlewareState, type ExtractMiddlewareTypes, type ExtractPluginServices, type ExtractPluginState, type ExtractPluginTypes, type ExtractSSEEvents, type ExtractSSEParams, type ExtractSSEQuery, type ExtractSSERoutes, type FileCache, type FindRouteFilesOptions, ForbiddenError, type ForbiddenErrorDetails, type GetContextFn, type HasSSEMethod, type Http2Options, type HttpMethod, type Infer, type InferContext, type InternalRequestArgs, InternalServerError, type InternalServerErrorDetails, type Matcher, type MergeServices, type MergeStates, type Middleware, MiddlewareAPI, type MiddlewareFunction, type MiddlewareOptions, type MultipartData, type MultipartError, type MultipartLimits, type NetworkErrorContext, type NextFunction, NotFoundError, type NotFoundErrorDetails, type ParseErrorContext, type ParseOptions, type ParseResult, type ParsedRoute, type ParserState, PayloadTooLargeError, type PayloadTooLargeErrorDetails, type Plugin, type PluginFactory, type PluginHooks, type PluginLifecycleManager, type PluginLifecycleOptions, type PluginOptions, PluginsAPI, type ProcessResponseOptions, type ProcessingConfig, type QueryParams, RateLimitError, type RateLimitErrorDetails, type ReconnectStrategy, type RegistryResult, type ReloadMetrics, type RequestHandler, type RequestOptions, type RequestParams, RequestTimeoutError, type Result, type Route, type RouteDefinition, type RouteEntry, type RouteHandler, type RouteMatch, type RouteMethodOptions, type RouteNode, type RouteOptions, type RouteRegistry, type RouteSchema, type Router, RouterAPI, type RouterOptions, type SSEBufferOverflowErrorDetails, type SSEBufferStrategy, type SSEClient, type SSEClientMetrics, type SSEClientOptions, type SSEConnectionErrorContext, type SSEConnectionErrorDetails, type SSEConnectionFactory, type SSEConnectionState, type SSEEvent, type SSEEventHandler, type SSEEventListener, type SSEHeartbeatErrorContext, type SSEMetrics, type SSEOptions, type SSERouteHandler, type SSERouteSchema, type SSESerializedEvent, type SSEStream, type SSEStreamClosedErrorDetails, type SSEStreamErrorContext, type SSEStreamExtended, type SSEStreamManager, type SafeComposeMiddlewareServices, type SafeComposeMiddlewareStates, type SafeComposePluginServices, type SafeComposePluginStates, type SafeExtractMiddlewareServices, type SafeExtractMiddlewareState, type SafeExtractPluginServices, type SafeExtractPluginState, type Server, ServerAPI, type ServerOptions, type ServerOptionsInput, type ServiceNotAvailableDetails, ServiceNotAvailableError, type Services, type StandardErrorResponse, type StartOptions, type State, type StopOptions, type StreamMetrics, type StreamOptions, type TimeoutErrorContext, type TypedSSEStream, UnauthorizedError, type UnauthorizedErrorDetails, type UnifiedRequest, type UnifiedResponse, type UnionToIntersection, type UnknownFunction, type UnknownServer, UnprocessableEntityError, UnsupportedMediaTypeError, type UnsupportedMediaTypeErrorDetails, type UploadProgress, type UploadedFile, VERSION, type ValidationConfig, ValidationError, type ValidationErrorDetails, type ValidationFieldError, type WatchOptions, asMiddlewareArray, asPluginArray, buildUrl, compilePathPattern, compose, cors, createDeleteRoute, createGetRoute, createHeadRoute, createMatcher, create$1 as createMiddleware, createMiddlewareArray, createOptionsRoute, createPatchRoute, createPlugin, createPluginArray, createPostRoute, createPutRoute, createRouteFactory, create as createServer, serviceMiddleware as createServiceMiddleware, stateMiddleware as createStateMiddleware, extractParams, getCorrelationId, inferContext, isMiddleware, isPlugin, paramsToQuery };
4766
+ export { Blaize, BlaizeError, type BlaizeErrorResponse, type BlaizeLogTransport, type BlaizeLogger, type BodyLimits, type BufferedEvent, type BuildRoutesRegistry, type BuildSSEArgs, type CacheConfig, type CacheEntry, type ClientConfig, type CloseEvent, type ComposeMiddlewareServices, type ComposeMiddlewareStates, type ComposeMiddlewareTypes, type ComposePluginServices, type ComposePluginStates, type ComposePluginTypes, ConflictError, type ConflictErrorDetails, type ConnectionEntry, type ConnectionRegistry, ConsoleTransport, type Context, type ContextOptions, type ContextRequest, type ContextResponse, type CorrelationOptions, type CorsHttpMethod, type CorsOptions, type CorsOrigin, type CorsOriginCacheConfig, type CorsOriginCacheEntry, type CorsPreflightInfo, type CorsStats, type CorsValidationResult, type CreateClient, type CreateContextFn, type CreateDeleteRoute, type CreateEnhancedClient, type CreateGetRoute, type CreateHeadRoute, type CreateOptionsRoute, type CreatePatchRoute, type CreatePluginOptions, type CreatePostRoute, type CreatePutRoute, type CreateSSEMethod, type CreateSSERoute, type ErrorHandlerOptions, ErrorSeverity, type ErrorTransformContext, ErrorType, type EventHandlers, type ExtractMethod, type ExtractMiddlewareServices, type ExtractMiddlewareState, type ExtractMiddlewareTypes, type ExtractPluginServices, type ExtractPluginState, type ExtractPluginTypes, type ExtractSSEEvents, type ExtractSSEParams, type ExtractSSEQuery, type ExtractSSERoutes, type FileCache, type FindRouteFilesOptions, ForbiddenError, type ForbiddenErrorDetails, type GetContextFn, type HasSSEMethod, type Http2Options, type HttpMethod, type Infer, type InferContext, type InternalRequestArgs, InternalServerError, type InternalServerErrorDetails, JSONTransport, type LogLevel, type LogMetadata, Logger, type LoggerConfig, type Matcher, type MergeServices, type MergeStates, type Middleware, MiddlewareAPI, type MiddlewareFunction, type MiddlewareOptions, type MultipartData, type MultipartError, type MultipartLimits, type NetworkErrorContext, type NextFunction, NotFoundError, type NotFoundErrorDetails, NullTransport, type ParseErrorContext, type ParseOptions, type ParseResult, type ParsedRoute, type ParserState, PayloadTooLargeError, type PayloadTooLargeErrorDetails, type Plugin, type PluginFactory, type PluginHooks, type PluginLifecycleManager, type PluginLifecycleOptions, type PluginOptions, PluginsAPI, type ProcessResponseOptions, type ProcessingConfig, type QueryParams, RateLimitError, type RateLimitErrorDetails, type ReconnectStrategy, type RegistryResult, type ReloadMetrics, type RequestHandler, type RequestLoggerOptions, type RequestOptions, type RequestParams, RequestTimeoutError, type ResolvedLoggerConfig, type Result, type Route, type RouteDefinition, type RouteEntry, type RouteHandler, type RouteMatch, type RouteMethodOptions, type RouteNode, type RouteOptions, type RouteRegistry, type RouteSchema, type Router, RouterAPI, type RouterOptions, type SSEBufferOverflowErrorDetails, type SSEBufferStrategy, type SSEClient, type SSEClientMetrics, type SSEClientOptions, type SSEConnectionErrorContext, type SSEConnectionErrorDetails, type SSEConnectionFactory, type SSEConnectionState, type SSEEvent, type SSEEventHandler, type SSEEventListener, type SSEHeartbeatErrorContext, type SSEMetrics, type SSEOptions, type SSERouteHandler, type SSERouteSchema, type SSESerializedEvent, type SSEStream, type SSEStreamClosedErrorDetails, type SSEStreamErrorContext, type SSEStreamExtended, type SSEStreamManager, type SafeComposeMiddlewareServices, type SafeComposeMiddlewareStates, type SafeComposePluginServices, type SafeComposePluginStates, type SafeExtractMiddlewareServices, type SafeExtractMiddlewareState, type SafeExtractPluginServices, type SafeExtractPluginState, type SerializedError, type Server, ServerAPI, type ServerOptions, type ServerOptionsInput, type ServiceNotAvailableDetails, ServiceNotAvailableError, type Services, type StandardErrorResponse, type StartOptions, type State, type StopOptions, type StreamMetrics, type StreamOptions, type TimeoutErrorContext, type TypedSSEStream, UnauthorizedError, type UnauthorizedErrorDetails, type UnifiedRequest, type UnifiedResponse, type UnionToIntersection, type UnknownFunction, type UnknownServer, UnprocessableEntityError, UnsupportedMediaTypeError, type UnsupportedMediaTypeErrorDetails, type UploadProgress, type UploadedFile, VERSION, type ValidationConfig, ValidationError, type ValidationErrorDetails, type ValidationFieldError, type WatchOptions, asMiddlewareArray, asPluginArray, buildUrl, compilePathPattern, compose, configureGlobalLogger, cors, createDeleteRoute, createGetRoute, createHeadRoute, createLogger, createMatcher, create$1 as createMiddleware, createMiddlewareArray, createOptionsRoute, createPatchRoute, createPlugin, createPluginArray, createPostRoute, createPutRoute, createRouteFactory, create as createServer, serviceMiddleware as createServiceMiddleware, stateMiddleware as createStateMiddleware, extractParams, getCorrelationId, inferContext, isMiddleware, isPlugin, logger, paramsToQuery, requestLoggerMiddleware };