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.
- package/dist/{chunk-WTCIDURS.js → chunk-DCFSCRSA.js} +3 -3
- package/dist/{chunk-YE7LYWE6.js → chunk-EAXYRQ3P.js} +3 -3
- package/dist/{chunk-5C4WI3A7.js → chunk-FCV6YEV5.js} +3 -3
- package/dist/{chunk-EOCNAQ76.js → chunk-FZ7VQAU3.js} +2 -2
- package/dist/{chunk-EOCNAQ76.js.map → chunk-FZ7VQAU3.js.map} +1 -1
- package/dist/{chunk-GNLJMVOB.js → chunk-O2UQAGER.js} +3 -3
- package/dist/index.cjs +16 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2548 -1411
- package/dist/index.d.ts +2548 -1411
- package/dist/index.js +17 -15
- package/dist/index.js.map +1 -1
- package/dist/{internal-server-error-MFDGHZTW.js → internal-server-error-3NM7IWUS.js} +3 -3
- package/dist/{payload-too-large-error-JESAYGED.js → payload-too-large-error-WI42VGZU.js} +3 -3
- package/dist/{unsupported-media-type-error-ZDQCGXCO.js → unsupported-media-type-error-TA5IO6FC.js} +3 -3
- package/dist/{validation-error-KGPRZ5X7.js → validation-error-NO2FE2IP.js} +3 -3
- package/package.json +2 -2
- /package/dist/{chunk-WTCIDURS.js.map → chunk-DCFSCRSA.js.map} +0 -0
- /package/dist/{chunk-YE7LYWE6.js.map → chunk-EAXYRQ3P.js.map} +0 -0
- /package/dist/{chunk-5C4WI3A7.js.map → chunk-FCV6YEV5.js.map} +0 -0
- /package/dist/{chunk-GNLJMVOB.js.map → chunk-O2UQAGER.js.map} +0 -0
- /package/dist/{internal-server-error-MFDGHZTW.js.map → internal-server-error-3NM7IWUS.js.map} +0 -0
- /package/dist/{payload-too-large-error-JESAYGED.js.map → payload-too-large-error-WI42VGZU.js.map} +0 -0
- /package/dist/{unsupported-media-type-error-ZDQCGXCO.js.map → unsupported-media-type-error-TA5IO6FC.js.map} +0 -0
- /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
|
-
*
|
|
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
|
-
*
|
|
773
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
790
|
-
*
|
|
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
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
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
|
-
|
|
803
|
-
/**
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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
|
-
*
|
|
1370
|
+
* Context information for network-related errors
|
|
810
1371
|
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
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
|
|
822
|
-
/**
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
-
*
|
|
900
|
-
*
|
|
1399
|
+
* Context information for request timeout errors
|
|
1400
|
+
*
|
|
1401
|
+
* Specialized context for timeout-specific errors with timing information.
|
|
901
1402
|
*/
|
|
902
|
-
interface
|
|
903
|
-
/**
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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
|
-
*
|
|
919
|
-
*
|
|
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
|
|
922
|
-
/**
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
/**
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
*
|
|
939
|
-
*
|
|
940
|
-
|
|
941
|
-
|
|
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
|
-
|
|
3032
|
+
|
|
1737
3033
|
/**
|
|
1738
|
-
*
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
*
|
|
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
|
-
*
|
|
1756
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
3072
|
+
register?: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1776
3073
|
/**
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1796
|
-
*
|
|
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
|
-
|
|
3105
|
+
onServerStart?: (server: Http2Server | Server$1) => void | Promise<void>;
|
|
1799
3106
|
/**
|
|
1800
|
-
*
|
|
1801
|
-
*
|
|
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
|
-
|
|
3121
|
+
onServerStop?: (server: Http2Server | Server$1) => void | Promise<void>;
|
|
1804
3122
|
/**
|
|
1805
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
1870
|
-
*
|
|
3148
|
+
* Plugin name (e.g., '@blaizejs/metrics')
|
|
3149
|
+
* Must be unique within a server instance
|
|
1871
3150
|
*/
|
|
1872
|
-
|
|
3151
|
+
name: string;
|
|
1873
3152
|
/**
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
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
|
-
|
|
3156
|
+
version: string;
|
|
1880
3157
|
/**
|
|
1881
|
-
*
|
|
1882
|
-
*
|
|
1883
|
-
*
|
|
1884
|
-
* @
|
|
1885
|
-
*
|
|
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
|
-
|
|
3169
|
+
defaultConfig?: TConfig;
|
|
1888
3170
|
/**
|
|
1889
|
-
*
|
|
1890
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
3213
|
+
register: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1897
3214
|
/**
|
|
1898
|
-
*
|
|
3215
|
+
* Type carriers for compile-time type information
|
|
3216
|
+
* These are never used at runtime but allow TypeScript to track types
|
|
1899
3217
|
*/
|
|
1900
|
-
|
|
3218
|
+
_state?: TState;
|
|
3219
|
+
_services?: TServices;
|
|
1901
3220
|
}
|
|
1902
3221
|
/**
|
|
1903
|
-
*
|
|
3222
|
+
* Plugin factory function
|
|
1904
3223
|
*/
|
|
1905
|
-
type
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
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
|
-
*
|
|
3239
|
+
* Type composition utilities for extracting and composing middleware type contributions
|
|
3240
|
+
* @module composition
|
|
3241
|
+
* @since v0.4.0
|
|
1914
3242
|
*/
|
|
1915
|
-
|
|
1916
|
-
stream: SSEStream;
|
|
1917
|
-
connectedAt: number;
|
|
1918
|
-
lastActivity: number;
|
|
1919
|
-
clientIp?: string;
|
|
1920
|
-
userAgent?: string;
|
|
1921
|
-
}
|
|
3243
|
+
|
|
1922
3244
|
/**
|
|
1923
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1965
|
-
*
|
|
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
|
|
1968
|
-
params: TParams) => Promise<void> | void;
|
|
3267
|
+
type ExtractPluginServices<T> = T extends Plugin<any, infer S> ? S : {};
|
|
1969
3268
|
/**
|
|
1970
|
-
*
|
|
1971
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
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
|
-
*
|
|
2023
|
-
*
|
|
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
|
-
*
|
|
3355
|
+
* Composes state with better edge case handling
|
|
3356
|
+
* @template T - ReadonlyArray of Middleware
|
|
3357
|
+
* @returns Safely composed state types
|
|
2028
3358
|
*/
|
|
2029
|
-
|
|
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
|
-
*
|
|
3361
|
+
* Composes plugin state with better edge case handling
|
|
3362
|
+
* @template T - ReadonlyArray of Plugin
|
|
3363
|
+
* @returns Safely composed state types
|
|
2034
3364
|
*/
|
|
2035
|
-
|
|
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
|
-
*
|
|
3367
|
+
* Composes services with better edge case handling
|
|
3368
|
+
* @template T - ReadonlyArray of Middleware
|
|
3369
|
+
* @returns Safely composed service types
|
|
2063
3370
|
*/
|
|
2064
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
2100
|
-
reconnect: boolean;
|
|
2101
|
-
reason?: string;
|
|
2102
|
-
}
|
|
3395
|
+
type MergeServices<A, B> = Omit<A, keyof B> & B;
|
|
2103
3396
|
/**
|
|
2104
|
-
*
|
|
2105
|
-
*
|
|
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
|
|
2108
|
-
|
|
2109
|
-
|
|
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
|
-
*
|
|
2180
|
-
*
|
|
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
|
|
2183
|
-
|
|
2184
|
-
|
|
3410
|
+
type ExtractPluginTypes<T> = {
|
|
3411
|
+
state: ExtractPluginState<T>;
|
|
3412
|
+
services: ExtractPluginServices<T>;
|
|
3413
|
+
};
|
|
2185
3414
|
/**
|
|
2186
|
-
*
|
|
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
|
|
2189
|
-
|
|
2190
|
-
|
|
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
|
-
*
|
|
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
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
3482
|
+
* Console Transport for Development
|
|
2252
3483
|
*
|
|
2253
|
-
*
|
|
2254
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
2284
|
-
*
|
|
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
|
-
|
|
3531
|
+
write(level: LogLevel, message: string, meta: LogMetadata): void;
|
|
2287
3532
|
}
|
|
3533
|
+
|
|
2288
3534
|
/**
|
|
2289
|
-
*
|
|
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
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
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
|
-
*
|
|
2313
|
-
*
|
|
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
|
-
|
|
3595
|
+
write(level: LogLevel, message: string, meta: LogMetadata): void;
|
|
2316
3596
|
/**
|
|
2317
|
-
*
|
|
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
|
-
*
|
|
2332
|
-
*
|
|
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
|
-
*
|
|
2341
|
-
* const server = createServer({ cors: false });
|
|
2342
|
-
* ```
|
|
3602
|
+
* @returns Promise that resolves immediately
|
|
2343
3603
|
*/
|
|
2344
|
-
|
|
2345
|
-
bodyLimits?: Partial<BodyLimits>;
|
|
3604
|
+
flush(): Promise<void>;
|
|
2346
3605
|
}
|
|
3606
|
+
|
|
2347
3607
|
/**
|
|
2348
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
3616
|
+
* Null transport for testing and silent logging
|
|
2384
3617
|
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
2445
|
-
*
|
|
2446
|
-
*
|
|
2447
|
-
* ```
|
|
3660
|
+
* @param _level - Log level (unused)
|
|
3661
|
+
* @param _message - Log message (unused)
|
|
3662
|
+
* @param _meta - Structured metadata (unused)
|
|
2448
3663
|
*/
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
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
|
-
*
|
|
3676
|
+
* Core Logger Implementation
|
|
2461
3677
|
*
|
|
2462
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2479
|
-
*
|
|
2480
|
-
*
|
|
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
|
-
|
|
3712
|
+
declare class Logger implements BlaizeLogger {
|
|
3713
|
+
private readonly config;
|
|
3714
|
+
private readonly inheritedMeta;
|
|
3715
|
+
private readonly minLevelPriority;
|
|
2483
3716
|
/**
|
|
2484
|
-
*
|
|
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
|
|
2492
|
-
* @
|
|
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
|
-
|
|
3722
|
+
constructor(config: ResolvedLoggerConfig, inheritedMeta?: LogMetadata);
|
|
2505
3723
|
/**
|
|
2506
|
-
*
|
|
2507
|
-
*
|
|
2508
|
-
* Use this hook to:
|
|
2509
|
-
* - Create database connections
|
|
2510
|
-
* - Initialize services
|
|
2511
|
-
* - Allocate resources
|
|
3724
|
+
* Log a debug message
|
|
2512
3725
|
*
|
|
2513
|
-
* @
|
|
2514
|
-
*
|
|
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
|
-
|
|
3729
|
+
debug(message: string, meta?: LogMetadata): void;
|
|
2521
3730
|
/**
|
|
2522
|
-
*
|
|
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
|
-
* @
|
|
2530
|
-
*
|
|
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
|
-
|
|
3736
|
+
info(message: string, meta?: LogMetadata): void;
|
|
2538
3737
|
/**
|
|
2539
|
-
*
|
|
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
|
-
* @
|
|
2547
|
-
*
|
|
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
|
-
|
|
3743
|
+
warn(message: string, meta?: LogMetadata): void;
|
|
2554
3744
|
/**
|
|
2555
|
-
*
|
|
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
|
-
* @
|
|
2563
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
2591
|
-
*
|
|
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
|
-
*
|
|
2596
|
-
*
|
|
2597
|
-
*
|
|
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
|
-
|
|
3769
|
+
child(meta: LogMetadata): BlaizeLogger;
|
|
2602
3770
|
/**
|
|
2603
|
-
*
|
|
3771
|
+
* Flush any buffered logs and wait for completion
|
|
2604
3772
|
*
|
|
2605
|
-
*
|
|
2606
|
-
*
|
|
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
|
-
* @
|
|
2609
|
-
* @returns Partial plugin hooks
|
|
3776
|
+
* @returns Promise that resolves when all logs are flushed
|
|
2610
3777
|
*
|
|
2611
3778
|
* @example
|
|
2612
3779
|
* ```typescript
|
|
2613
|
-
*
|
|
2614
|
-
*
|
|
2615
|
-
*
|
|
2616
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
3788
|
+
* Internal log method that handles all log levels
|
|
2639
3789
|
*
|
|
2640
|
-
*
|
|
2641
|
-
*
|
|
3790
|
+
* Fast-path: Returns immediately if log level is filtered.
|
|
3791
|
+
* This ensures zero overhead for disabled log levels.
|
|
2642
3792
|
*
|
|
2643
|
-
* @
|
|
3793
|
+
* @param level - The log level
|
|
3794
|
+
* @param message - The log message
|
|
3795
|
+
* @param meta - Optional metadata to attach
|
|
2644
3796
|
*/
|
|
2645
|
-
|
|
3797
|
+
private log;
|
|
2646
3798
|
/**
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
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
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
2717
|
-
*
|
|
3825
|
+
* Core transports (ConsoleTransport, JSONTransport) are lazy-loaded by
|
|
3826
|
+
* the logger itself. Custom transports should be provided by application code.
|
|
2718
3827
|
*
|
|
2719
|
-
* @
|
|
2720
|
-
*
|
|
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
|
-
* @
|
|
2730
|
-
*
|
|
3831
|
+
* @example Development Logger (Default)
|
|
3832
|
+
* ```typescript
|
|
3833
|
+
* const logger = createLogger();
|
|
3834
|
+
* // Uses: level='debug', ConsoleTransport, timestamp=true, no redaction
|
|
2731
3835
|
*
|
|
2732
|
-
*
|
|
2733
|
-
*
|
|
2734
|
-
*
|
|
2735
|
-
*
|
|
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
|
-
|
|
3861
|
+
declare function createLogger(config?: Partial<ResolvedLoggerConfig>): Logger;
|
|
3862
|
+
|
|
2738
3863
|
/**
|
|
2739
|
-
*
|
|
2740
|
-
* Merges all service types into a single intersection type
|
|
3864
|
+
* Global logger singleton instance
|
|
2741
3865
|
*
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
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
|
-
*
|
|
2747
|
-
*
|
|
2748
|
-
*
|
|
3871
|
+
* ```typescript
|
|
3872
|
+
* import { logger } from '@blaizejs/logger';
|
|
3873
|
+
*
|
|
3874
|
+
* logger.info('Application starting');
|
|
3875
|
+
* ```
|
|
2749
3876
|
*/
|
|
2750
|
-
|
|
3877
|
+
declare const logger: BlaizeLogger;
|
|
2751
3878
|
/**
|
|
2752
|
-
*
|
|
2753
|
-
* Merges all service types into a single intersection type
|
|
3879
|
+
* Configure the global logger instance
|
|
2754
3880
|
*
|
|
2755
|
-
*
|
|
2756
|
-
*
|
|
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
|
-
*
|
|
2760
|
-
*
|
|
2761
|
-
*
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
*
|
|
2766
|
-
*
|
|
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
|
-
|
|
3897
|
+
declare function configureGlobalLogger(config: Partial<LoggerConfig>): void;
|
|
3898
|
+
|
|
2806
3899
|
/**
|
|
2807
|
-
*
|
|
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
|
-
|
|
3902
|
+
declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
|
|
3903
|
+
|
|
2812
3904
|
/**
|
|
2813
|
-
*
|
|
2814
|
-
* Handles conflicts by using the rightmost (latest) type
|
|
3905
|
+
* Create CORS middleware with the specified options
|
|
2815
3906
|
*
|
|
2816
|
-
* @
|
|
2817
|
-
* @
|
|
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
|
-
* @
|
|
2826
|
-
*
|
|
2827
|
-
*
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
*
|
|
2832
|
-
*
|
|
2833
|
-
*
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
*
|
|
2841
|
-
*
|
|
2842
|
-
*
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
*
|
|
2850
|
-
*
|
|
2851
|
-
*
|
|
2852
|
-
|
|
2853
|
-
|
|
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
|
|
3940
|
+
declare function cors(userOptions?: CorsOptions | boolean): Middleware;
|
|
3941
|
+
|
|
2872
3942
|
/**
|
|
2873
|
-
*
|
|
2874
|
-
* @param value - Value to check
|
|
2875
|
-
* @returns True if value is a Plugin
|
|
3943
|
+
* Create a middleware
|
|
2876
3944
|
*/
|
|
2877
|
-
declare function
|
|
3945
|
+
declare function create$1<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
|
|
2878
3946
|
/**
|
|
2879
|
-
*
|
|
2880
|
-
*
|
|
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
|
|
3955
|
+
declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
|
|
2887
3956
|
/**
|
|
2888
|
-
*
|
|
2889
|
-
*
|
|
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
|
|
3965
|
+
declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
|
|
3966
|
+
|
|
2896
3967
|
/**
|
|
2897
|
-
*
|
|
2898
|
-
* Useful for getting proper const assertions
|
|
3968
|
+
* Request Logger Middleware
|
|
2899
3969
|
*
|
|
2900
|
-
*
|
|
2901
|
-
*
|
|
2902
|
-
*
|
|
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
|
-
|
|
3975
|
+
|
|
2905
3976
|
/**
|
|
2906
|
-
*
|
|
2907
|
-
* Useful for getting proper const assertions
|
|
3977
|
+
* Request logger middleware factory
|
|
2908
3978
|
*
|
|
2909
|
-
*
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
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
|
|
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
|
|
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 };
|