blaizejs 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-5C4WI3A7.js → chunk-CM6LIHRF.js} +3 -3
- package/dist/{chunk-GNLJMVOB.js → chunk-FLI2OVQ5.js} +3 -3
- package/dist/{chunk-YE7LYWE6.js → chunk-HQRQVJL6.js} +3 -3
- package/dist/{chunk-WTCIDURS.js → chunk-J5FJFX2G.js} +3 -3
- package/dist/{chunk-EOCNAQ76.js → chunk-MZG6O7BX.js} +2 -2
- package/dist/{chunk-EOCNAQ76.js.map → chunk-MZG6O7BX.js.map} +1 -1
- package/dist/index.cjs +16 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2509 -1406
- package/dist/index.d.ts +2509 -1406
- package/dist/index.js +17 -15
- package/dist/index.js.map +1 -1
- package/dist/{internal-server-error-MFDGHZTW.js → internal-server-error-RRNSAEYK.js} +3 -3
- package/dist/{payload-too-large-error-JESAYGED.js → payload-too-large-error-SQMCGPZ7.js} +3 -3
- package/dist/{unsupported-media-type-error-ZDQCGXCO.js → unsupported-media-type-error-6T47SVVY.js} +3 -3
- package/dist/{validation-error-KGPRZ5X7.js → validation-error-DRCBJ7IF.js} +3 -3
- package/package.json +2 -2
- /package/dist/{chunk-5C4WI3A7.js.map → chunk-CM6LIHRF.js.map} +0 -0
- /package/dist/{chunk-GNLJMVOB.js.map → chunk-FLI2OVQ5.js.map} +0 -0
- /package/dist/{chunk-YE7LYWE6.js.map → chunk-HQRQVJL6.js.map} +0 -0
- /package/dist/{chunk-WTCIDURS.js.map → chunk-J5FJFX2G.js.map} +0 -0
- /package/dist/{internal-server-error-MFDGHZTW.js.map → internal-server-error-RRNSAEYK.js.map} +0 -0
- /package/dist/{payload-too-large-error-JESAYGED.js.map → payload-too-large-error-SQMCGPZ7.js.map} +0 -0
- /package/dist/{unsupported-media-type-error-ZDQCGXCO.js.map → unsupported-media-type-error-6T47SVVY.js.map} +0 -0
- /package/dist/{validation-error-KGPRZ5X7.js.map → validation-error-DRCBJ7IF.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,2039 @@ 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) => 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) => 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
|
+
path: string;
|
|
2243
|
+
};
|
|
2244
|
+
/**
|
|
2245
|
+
* Buffered event with metadata
|
|
2246
|
+
*/
|
|
2247
|
+
interface BufferedEvent {
|
|
2248
|
+
id: string;
|
|
2249
|
+
event: string;
|
|
2250
|
+
data: unknown;
|
|
2251
|
+
size: number;
|
|
2252
|
+
timestamp: number;
|
|
2253
|
+
correlationId: string;
|
|
2254
|
+
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Stream metrics for monitoring
|
|
2257
|
+
*/
|
|
2258
|
+
interface StreamMetrics {
|
|
2259
|
+
eventsSent: number;
|
|
2260
|
+
eventsDropped: number;
|
|
2261
|
+
bytesWritten: number;
|
|
2262
|
+
bufferHighWatermark: number;
|
|
2263
|
+
lastEventTime: number;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
/**
|
|
2267
|
+
* SSE Client Types for BlaizeJS
|
|
2268
|
+
* Location: packages/blaize-client/src/sse/types.ts
|
|
2269
|
+
*/
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* Event handlers map
|
|
2273
|
+
*/
|
|
2274
|
+
interface EventHandlers {
|
|
2275
|
+
[event: string]: Set<(data: any) => void>;
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* SSE connection configuration options
|
|
2279
|
+
*/
|
|
2280
|
+
interface SSEClientOptions {
|
|
2281
|
+
headers?: Record<string, string>;
|
|
2282
|
+
withCredentials?: boolean;
|
|
2283
|
+
reconnect?: {
|
|
2284
|
+
enabled: boolean;
|
|
2285
|
+
maxAttempts?: number;
|
|
2286
|
+
strategy?: ReconnectStrategy;
|
|
2287
|
+
initialDelay?: number;
|
|
2288
|
+
};
|
|
2289
|
+
bufferMissedEvents?: boolean;
|
|
2290
|
+
maxMissedEvents?: number;
|
|
2291
|
+
heartbeatTimeout?: number;
|
|
2292
|
+
parseJSON?: boolean;
|
|
2293
|
+
/**
|
|
2294
|
+
* Whether to wait for connection before resolving the promise.
|
|
2295
|
+
* If false, returns the client immediately without waiting.
|
|
2296
|
+
* Default: true
|
|
2297
|
+
*/
|
|
2298
|
+
waitForConnection?: boolean;
|
|
2299
|
+
/**
|
|
2300
|
+
* Optional timeout for initial connection in milliseconds.
|
|
2301
|
+
* If not set, no timeout is applied (relies on EventSource native timeout).
|
|
2302
|
+
* Only applies if waitForConnection is true.
|
|
2303
|
+
*/
|
|
2304
|
+
connectionTimeout?: number;
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* Metrics for SSE connection monitoring
|
|
2308
|
+
*/
|
|
2309
|
+
interface SSEClientMetrics {
|
|
2310
|
+
eventsReceived: number;
|
|
2311
|
+
bytesReceived: number;
|
|
2312
|
+
connectionDuration: number;
|
|
2313
|
+
reconnectAttempts: number;
|
|
2314
|
+
lastEventId?: string;
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Reconnection delay calculation strategy
|
|
2318
|
+
*/
|
|
2319
|
+
type ReconnectStrategy = (attempt: number) => number;
|
|
2320
|
+
/**
|
|
2321
|
+
* SSE Client interface with type-safe event handling
|
|
2322
|
+
*/
|
|
2323
|
+
interface SSEClient<TEvents extends Record<string, unknown> = Record<string, unknown>> {
|
|
2324
|
+
on<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
|
|
2325
|
+
on(event: 'error', handler: (error: BlaizeError) => void): void;
|
|
2326
|
+
on(event: 'open', handler: () => void): void;
|
|
2327
|
+
on(event: 'close', handler: (event: CloseEvent) => void): void;
|
|
2328
|
+
off<K extends keyof TEvents>(event: K & string, handler?: (data: TEvents[K]) => void): void;
|
|
2329
|
+
off(event: 'error', handler?: (error: BlaizeError) => void): void;
|
|
2330
|
+
off(event: 'open', handler?: () => void): void;
|
|
2331
|
+
off(event: 'close', handler?: (event: CloseEvent) => void): void;
|
|
2332
|
+
once<K extends keyof TEvents>(event: K & string, handler: (data: TEvents[K]) => void): void;
|
|
2333
|
+
once(event: 'error', handler: (error: BlaizeError) => void): void;
|
|
2334
|
+
once(event: 'open', handler: () => void): void;
|
|
2335
|
+
once(event: 'close', handler: (event: CloseEvent) => void): void;
|
|
2336
|
+
close(): void;
|
|
2337
|
+
readonly state: SSEConnectionState;
|
|
2338
|
+
readonly metrics: SSEClientMetrics;
|
|
2339
|
+
readonly lastEventId?: string;
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Close event for SSE connections
|
|
2343
|
+
*/
|
|
2344
|
+
interface CloseEvent {
|
|
2345
|
+
reconnect: boolean;
|
|
2346
|
+
reason?: string;
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Internal SSE connection factory
|
|
2350
|
+
* Returns a Promise that resolves to an SSEClient instance
|
|
2351
|
+
*/
|
|
2352
|
+
type SSEConnectionFactory<TEvents extends Record<string, unknown> = Record<string, unknown>> = (options?: SSEClientOptions) => Promise<SSEClient<TEvents>>;
|
|
2353
|
+
|
|
2354
|
+
type ExtractMethod<T> = T extends {
|
|
2355
|
+
GET: any;
|
|
2356
|
+
} ? 'GET' : T extends {
|
|
2357
|
+
POST: any;
|
|
2358
|
+
} ? 'POST' : T extends {
|
|
2359
|
+
PUT: any;
|
|
2360
|
+
} ? 'PUT' : T extends {
|
|
2361
|
+
DELETE: any;
|
|
2362
|
+
} ? 'DELETE' : T extends {
|
|
2363
|
+
PATCH: any;
|
|
2364
|
+
} ? 'PATCH' : T extends {
|
|
2365
|
+
HEAD: any;
|
|
2366
|
+
} ? 'HEAD' : T extends {
|
|
2367
|
+
OPTIONS: any;
|
|
2368
|
+
} ? 'OPTIONS' : never;
|
|
2369
|
+
type BuildRoutesRegistry<TRoutes extends Record<string, any>> = {
|
|
2370
|
+
[Method in ExtractMethod<TRoutes[keyof TRoutes]> as `$${Lowercase<Method>}`]: {
|
|
2371
|
+
[K in keyof TRoutes as ExtractMethod<TRoutes[K]> extends Method ? K : never]: TRoutes[K];
|
|
2372
|
+
};
|
|
2373
|
+
};
|
|
2374
|
+
type GetRouteMethodOptions<TRoute> = TRoute extends {
|
|
2375
|
+
GET: infer M;
|
|
2376
|
+
} ? M : TRoute extends {
|
|
2377
|
+
POST: infer M;
|
|
2378
|
+
} ? M : TRoute extends {
|
|
2379
|
+
PUT: infer M;
|
|
2380
|
+
} ? M : TRoute extends {
|
|
2381
|
+
DELETE: infer M;
|
|
2382
|
+
} ? M : TRoute extends {
|
|
2383
|
+
PATCH: infer M;
|
|
2384
|
+
} ? M : TRoute extends {
|
|
2385
|
+
HEAD: infer M;
|
|
2386
|
+
} ? M : TRoute extends {
|
|
2387
|
+
OPTIONS: infer M;
|
|
2388
|
+
} ? M : never;
|
|
2389
|
+
type IsNever$1<T> = [T] extends [never] ? true : false;
|
|
2390
|
+
type BuildArgsObject<P, Q, B> = (IsNever$1<P> extends true ? {} : {
|
|
2391
|
+
params: Infer<P>;
|
|
2392
|
+
}) & (IsNever$1<Q> extends true ? {} : {
|
|
2393
|
+
query: Infer<Q>;
|
|
2394
|
+
}) & (IsNever$1<B> extends true ? {} : {
|
|
2395
|
+
body: Infer<B>;
|
|
2396
|
+
});
|
|
2397
|
+
type IsEmptyObject<T> = keyof T extends never ? true : false;
|
|
2398
|
+
type BuildArgs<P, Q, B> = IsEmptyObject<BuildArgsObject<P, Q, B>> extends true ? void : BuildArgsObject<P, Q, B>;
|
|
2399
|
+
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;
|
|
2400
|
+
type CreateClient<TRoutes extends Record<string, Record<string, any>>> = {
|
|
2401
|
+
[Method in keyof TRoutes]: {
|
|
2402
|
+
[RouteName in keyof TRoutes[Method]]: CreateClientMethod<TRoutes[Method][RouteName]>;
|
|
2403
|
+
};
|
|
2404
|
+
};
|
|
2405
|
+
interface ClientConfig {
|
|
2406
|
+
baseUrl: string;
|
|
2407
|
+
defaultHeaders?: Record<string, string>;
|
|
2408
|
+
timeout?: number;
|
|
2409
|
+
sse?: SSEClientOptions;
|
|
2410
|
+
}
|
|
2411
|
+
interface InternalRequestArgs {
|
|
2412
|
+
params?: Record<string, any>;
|
|
2413
|
+
query?: Record<string, any>;
|
|
2414
|
+
body?: any;
|
|
2415
|
+
}
|
|
2416
|
+
interface RequestOptions {
|
|
2417
|
+
method: string;
|
|
2418
|
+
url: string;
|
|
2419
|
+
headers: Record<string, string>;
|
|
2420
|
+
body?: string;
|
|
2421
|
+
timeout: number;
|
|
2422
|
+
}
|
|
2423
|
+
/**
|
|
2424
|
+
* Detect if a route has SSE support
|
|
2425
|
+
* SSE routes have a special 'SSE' method key
|
|
2426
|
+
*/
|
|
2427
|
+
type HasSSEMethod<TRoute> = TRoute extends {
|
|
2428
|
+
SSE: any;
|
|
2429
|
+
} ? true : false;
|
|
2430
|
+
/**
|
|
2431
|
+
* Extract SSE event types from route schema
|
|
2432
|
+
*/
|
|
2433
|
+
type ExtractSSEEvents<TRoute> = TRoute extends {
|
|
2434
|
+
SSE: {
|
|
2435
|
+
events?: infer E;
|
|
2436
|
+
};
|
|
2437
|
+
} ? E extends z.ZodType ? z.infer<E> : Record<string, unknown> : Record<string, unknown>;
|
|
2438
|
+
/**
|
|
2439
|
+
* Extract SSE query parameters from route
|
|
2440
|
+
*/
|
|
2441
|
+
type ExtractSSEQuery<TRoute> = TRoute extends {
|
|
2442
|
+
SSE: {
|
|
2443
|
+
schema?: {
|
|
2444
|
+
query?: infer Q;
|
|
2445
|
+
};
|
|
2446
|
+
};
|
|
2447
|
+
} ? Q extends z.ZodType ? z.infer<Q> : Record<string, unknown> : never;
|
|
2448
|
+
/**
|
|
2449
|
+
* Extract SSE params from route
|
|
2450
|
+
*/
|
|
2451
|
+
type ExtractSSEParams<TRoute> = TRoute extends {
|
|
2452
|
+
SSE: {
|
|
2453
|
+
schema?: {
|
|
2454
|
+
params?: infer P;
|
|
2455
|
+
};
|
|
2456
|
+
};
|
|
2457
|
+
} ? P extends z.ZodType ? z.infer<P> : Record<string, string> : never;
|
|
2458
|
+
/**
|
|
2459
|
+
* Build SSE method arguments
|
|
2460
|
+
*/
|
|
2461
|
+
type BuildSSEArgs<TRoute> = ExtractSSEParams<TRoute> extends never ? ExtractSSEQuery<TRoute> extends never ? {
|
|
2462
|
+
options?: SSEClientOptions;
|
|
2463
|
+
} : {
|
|
2464
|
+
query: ExtractSSEQuery<TRoute>;
|
|
2465
|
+
options?: SSEClientOptions;
|
|
2466
|
+
} : ExtractSSEQuery<TRoute> extends never ? {
|
|
2467
|
+
params: ExtractSSEParams<TRoute>;
|
|
2468
|
+
options?: SSEClientOptions;
|
|
2469
|
+
} : {
|
|
2470
|
+
params: ExtractSSEParams<TRoute>;
|
|
2471
|
+
query: ExtractSSEQuery<TRoute>;
|
|
2472
|
+
options?: SSEClientOptions;
|
|
2473
|
+
};
|
|
2474
|
+
/**
|
|
2475
|
+
* Create SSE client method
|
|
2476
|
+
*/
|
|
2477
|
+
type CreateSSEMethod<TRoute> = HasSSEMethod<TRoute> extends true ? BuildSSEArgs<TRoute> extends {
|
|
2478
|
+
options?: SSEClientOptions;
|
|
2479
|
+
} ? (args?: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : (args: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : never;
|
|
2480
|
+
/**
|
|
2481
|
+
* Extract SSE routes from registry
|
|
2482
|
+
*/
|
|
2483
|
+
type ExtractSSERoutes<TRoutes extends Record<string, any>> = {
|
|
2484
|
+
[K in keyof TRoutes as HasSSEMethod<TRoutes[K]> extends true ? K : never]: TRoutes[K];
|
|
2485
|
+
};
|
|
2486
|
+
/**
|
|
2487
|
+
* Enhanced client with SSE support
|
|
2488
|
+
*/
|
|
2489
|
+
type CreateEnhancedClient<TRoutes extends Record<string, any>, TRegistry> = TRegistry & {
|
|
2490
|
+
$sse: {
|
|
2491
|
+
[K in keyof ExtractSSERoutes<TRoutes>]: CreateSSEMethod<TRoutes[K]>;
|
|
2492
|
+
};
|
|
2493
|
+
};
|
|
2494
|
+
|
|
2495
|
+
/**
|
|
2496
|
+
* CORS Types for BlaizeJS Framework
|
|
2497
|
+
*
|
|
2498
|
+
* Comprehensive type definitions for W3C-compliant CORS middleware
|
|
2499
|
+
* with support for string, regex, and async function origin validation.
|
|
2500
|
+
*
|
|
2501
|
+
* @module @blaizejs/types/cors
|
|
2502
|
+
*/
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* Origin configuration type supporting multiple validation methods
|
|
2506
|
+
*
|
|
2507
|
+
* @example
|
|
2508
|
+
* ```typescript
|
|
2509
|
+
* // String origin (exact match)
|
|
2510
|
+
* const origin: CorsOrigin = 'https://example.com';
|
|
2511
|
+
*
|
|
2512
|
+
* // RegExp pattern
|
|
2513
|
+
* const origin: CorsOrigin = /^https:\/\/.*\.example\.com$/;
|
|
2514
|
+
*
|
|
2515
|
+
* // Dynamic validation function
|
|
2516
|
+
* const origin: CorsOrigin = async (origin, ctx) => {
|
|
2517
|
+
* return await checkOriginAllowed(origin, ctx?.state.user);
|
|
2518
|
+
* };
|
|
2519
|
+
*
|
|
2520
|
+
* // Array of mixed types
|
|
2521
|
+
* const origin: CorsOrigin = [
|
|
2522
|
+
* 'https://localhost:3000',
|
|
2523
|
+
* /^https:\/\/.*\.example\.com$/,
|
|
2524
|
+
* (origin) => origin.endsWith('.trusted.com')
|
|
2525
|
+
* ];
|
|
2526
|
+
* ```
|
|
2527
|
+
*/
|
|
2528
|
+
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>)>;
|
|
2529
|
+
/**
|
|
2530
|
+
* HTTP methods that can be allowed in CORS
|
|
2531
|
+
* Based on W3C CORS specification
|
|
2532
|
+
*/
|
|
2533
|
+
type CorsHttpMethod = HttpMethod | 'CONNECT' | 'TRACE';
|
|
2534
|
+
/**
|
|
2535
|
+
* Main CORS configuration options
|
|
2536
|
+
*
|
|
2537
|
+
* @example
|
|
2538
|
+
* ```typescript
|
|
2539
|
+
* const corsOptions: CorsOptions = {
|
|
2540
|
+
* origin: 'https://example.com',
|
|
2541
|
+
* methods: ['GET', 'POST'],
|
|
2542
|
+
* credentials: true,
|
|
2543
|
+
* maxAge: 86400
|
|
2544
|
+
* };
|
|
2545
|
+
* ```
|
|
2546
|
+
*/
|
|
2547
|
+
interface CorsOptions {
|
|
2548
|
+
/**
|
|
2549
|
+
* Configures the Access-Control-Allow-Origin header
|
|
2550
|
+
*
|
|
2551
|
+
* Possible values:
|
|
2552
|
+
* - `true`: Allow all origins (sets to '*' unless credentials is true, then reflects origin)
|
|
2553
|
+
* - `false`: Disable CORS (no headers set)
|
|
2554
|
+
* - `string`: Specific origin to allow
|
|
2555
|
+
* - `RegExp`: Pattern to match origins
|
|
2556
|
+
* - `function`: Custom validation logic
|
|
2557
|
+
* - `array`: Multiple origin configurations
|
|
2558
|
+
*
|
|
2559
|
+
* @default false
|
|
2560
|
+
*/
|
|
2561
|
+
origin?: boolean | CorsOrigin;
|
|
2562
|
+
/**
|
|
2563
|
+
* Configures the Access-Control-Allow-Methods header
|
|
2564
|
+
*
|
|
2565
|
+
* @default ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
|
|
2566
|
+
* @example ['GET', 'POST']
|
|
2567
|
+
*/
|
|
2568
|
+
methods?: CorsHttpMethod[] | string;
|
|
2569
|
+
/**
|
|
2570
|
+
* Configures the Access-Control-Allow-Headers header
|
|
2571
|
+
*
|
|
2572
|
+
* Pass an array of allowed headers or a comma-delimited string.
|
|
2573
|
+
*
|
|
2574
|
+
* @default Request's Access-Control-Request-Headers header value
|
|
2575
|
+
* @example ['Content-Type', 'Authorization']
|
|
2576
|
+
*/
|
|
2577
|
+
allowedHeaders?: string[] | string;
|
|
2578
|
+
/**
|
|
2579
|
+
* Configures the Access-Control-Expose-Headers header
|
|
2580
|
+
*
|
|
2581
|
+
* Headers that the browser is allowed to access.
|
|
2582
|
+
*
|
|
2583
|
+
* @default []
|
|
2584
|
+
* @example ['Content-Range', 'X-Content-Range']
|
|
2585
|
+
*/
|
|
2586
|
+
exposedHeaders?: string[] | string;
|
|
2587
|
+
/**
|
|
2588
|
+
* Configures the Access-Control-Allow-Credentials header
|
|
2589
|
+
*
|
|
2590
|
+
* Set to true to allow credentials (cookies, authorization headers, TLS client certificates).
|
|
2591
|
+
* Note: Cannot be used with origin: '*' for security reasons.
|
|
2592
|
+
*
|
|
2593
|
+
* @default false
|
|
2594
|
+
*/
|
|
2595
|
+
credentials?: boolean;
|
|
2596
|
+
/**
|
|
2597
|
+
* Configures the Access-Control-Max-Age header in seconds
|
|
2598
|
+
*
|
|
2599
|
+
* Indicates how long browsers can cache preflight response.
|
|
2600
|
+
* Set to -1 to disable caching.
|
|
2601
|
+
*
|
|
2602
|
+
* @default undefined (browser decides)
|
|
2603
|
+
* @example 86400 // 24 hours
|
|
2604
|
+
*/
|
|
2605
|
+
maxAge?: number;
|
|
2606
|
+
/**
|
|
2607
|
+
* Whether to pass the CORS preflight response to the next handler
|
|
2608
|
+
*
|
|
2609
|
+
* When false, the preflight response is sent immediately.
|
|
2610
|
+
* When true, control passes to the next middleware/handler.
|
|
2611
|
+
*
|
|
2612
|
+
* @default false
|
|
2613
|
+
*/
|
|
2614
|
+
preflightContinue?: boolean;
|
|
2615
|
+
/**
|
|
2616
|
+
* HTTP status code for successful OPTIONS requests
|
|
2617
|
+
*
|
|
2618
|
+
* Some legacy browsers require 200, while 204 is more correct.
|
|
2619
|
+
*
|
|
2620
|
+
* @default 204
|
|
2621
|
+
*/
|
|
2622
|
+
optionsSuccessStatus?: number;
|
|
2623
|
+
}
|
|
2624
|
+
/**
|
|
2625
|
+
* Internal CORS validation result
|
|
2626
|
+
* Used by middleware implementation
|
|
2627
|
+
*/
|
|
2628
|
+
interface CorsValidationResult {
|
|
2629
|
+
/**
|
|
2630
|
+
* Whether the origin is allowed
|
|
2631
|
+
*/
|
|
2632
|
+
allowed: boolean;
|
|
2633
|
+
/**
|
|
2634
|
+
* The origin value to set in the header
|
|
2635
|
+
* Can be '*', specific origin, or 'null'
|
|
2636
|
+
*/
|
|
2637
|
+
origin?: string;
|
|
2638
|
+
/**
|
|
2639
|
+
* Whether to add Vary: Origin header
|
|
2640
|
+
*/
|
|
2641
|
+
vary?: boolean;
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* CORS preflight request information
|
|
2645
|
+
* Extracted from OPTIONS request headers
|
|
2646
|
+
*/
|
|
2647
|
+
interface CorsPreflightInfo {
|
|
2648
|
+
/**
|
|
2649
|
+
* The origin making the request
|
|
2650
|
+
*/
|
|
2651
|
+
origin?: string;
|
|
2652
|
+
/**
|
|
2653
|
+
* The method that will be used in the actual request
|
|
2654
|
+
* From Access-Control-Request-Method header
|
|
2655
|
+
*/
|
|
2656
|
+
requestedMethod?: string;
|
|
2657
|
+
/**
|
|
2658
|
+
* The headers that will be sent in the actual request
|
|
2659
|
+
* From Access-Control-Request-Headers header
|
|
2660
|
+
*/
|
|
2661
|
+
requestedHeaders?: string[];
|
|
2662
|
+
}
|
|
2663
|
+
/**
|
|
2664
|
+
* Cache entry for origin validation results
|
|
2665
|
+
* Used for performance optimization
|
|
2666
|
+
*/
|
|
2667
|
+
interface CorsOriginCacheEntry {
|
|
2668
|
+
/**
|
|
2669
|
+
* Whether the origin is allowed
|
|
2670
|
+
*/
|
|
2671
|
+
allowed: boolean;
|
|
2672
|
+
/**
|
|
2673
|
+
* When this cache entry expires (timestamp)
|
|
2674
|
+
*/
|
|
2675
|
+
expiresAt: number;
|
|
2676
|
+
/**
|
|
2677
|
+
* Optional user identifier for cache key
|
|
2678
|
+
*/
|
|
2679
|
+
userId?: string;
|
|
2680
|
+
}
|
|
2681
|
+
/**
|
|
2682
|
+
* Configuration for CORS origin validation cache
|
|
2683
|
+
*/
|
|
2684
|
+
interface CorsOriginCacheConfig {
|
|
2685
|
+
/**
|
|
2686
|
+
* Time-to-live for cache entries in milliseconds
|
|
2687
|
+
* @default 60000 (1 minute)
|
|
2688
|
+
*/
|
|
2689
|
+
ttl?: number;
|
|
2690
|
+
/**
|
|
2691
|
+
* Maximum number of entries in the cache
|
|
2692
|
+
* @default 1000
|
|
2693
|
+
*/
|
|
2694
|
+
maxSize?: number;
|
|
2695
|
+
/**
|
|
2696
|
+
* Whether to include user ID in cache key
|
|
2697
|
+
* @default true
|
|
2698
|
+
*/
|
|
2699
|
+
includeUserId?: boolean;
|
|
2700
|
+
}
|
|
2701
|
+
/**
|
|
2702
|
+
* Statistics for CORS middleware performance monitoring
|
|
2703
|
+
*/
|
|
2704
|
+
interface CorsStats {
|
|
2705
|
+
/**
|
|
2706
|
+
* Total number of CORS requests processed
|
|
2707
|
+
*/
|
|
2708
|
+
totalRequests: number;
|
|
2709
|
+
/**
|
|
2710
|
+
* Number of preflight requests handled
|
|
2711
|
+
*/
|
|
2712
|
+
preflightRequests: number;
|
|
2713
|
+
/**
|
|
2714
|
+
* Number of allowed origins
|
|
2715
|
+
*/
|
|
2716
|
+
allowedOrigins: number;
|
|
2717
|
+
/**
|
|
2718
|
+
* Number of denied origins
|
|
2719
|
+
*/
|
|
2720
|
+
deniedOrigins: number;
|
|
2721
|
+
/**
|
|
2722
|
+
* Cache hit rate for origin validation
|
|
2723
|
+
*/
|
|
2724
|
+
cacheHitRate: number;
|
|
2725
|
+
/**
|
|
2726
|
+
* Average origin validation time in milliseconds
|
|
2727
|
+
*/
|
|
2728
|
+
avgValidationTime: number;
|
|
2729
|
+
}
|
|
2730
|
+
/**
|
|
2731
|
+
* Cache entry type
|
|
2732
|
+
*/
|
|
2733
|
+
interface CacheEntry {
|
|
2734
|
+
allowed: boolean;
|
|
2735
|
+
expiresAt: number;
|
|
2736
|
+
lastAccessed: number;
|
|
2737
|
+
}
|
|
2738
|
+
/**
|
|
2739
|
+
* Cache configuration
|
|
2740
|
+
*/
|
|
2741
|
+
interface CacheConfig {
|
|
2742
|
+
ttl: number;
|
|
2743
|
+
maxSize: number;
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
/**
|
|
2747
|
+
* BlaizeJS Server Module - Enhanced with Correlation Configuration
|
|
2748
|
+
*
|
|
2749
|
+
* Provides the core HTTP/2 server implementation with HTTP/1.1 fallback
|
|
2750
|
+
* and correlation ID tracking configuration.
|
|
2751
|
+
*/
|
|
2752
|
+
|
|
2753
|
+
type UnknownServer = Server<Record<string, unknown>, Record<string, unknown>>;
|
|
2754
|
+
interface Http2Options {
|
|
2755
|
+
enabled?: boolean | undefined;
|
|
2756
|
+
keyFile?: string | undefined;
|
|
2757
|
+
certFile?: string | undefined;
|
|
2758
|
+
}
|
|
2759
|
+
interface StartOptions {
|
|
2760
|
+
port?: number;
|
|
2761
|
+
host?: string;
|
|
2762
|
+
}
|
|
2763
|
+
interface StopOptions {
|
|
2764
|
+
timeout?: number;
|
|
2765
|
+
plugins?: Plugin[];
|
|
2766
|
+
onStopping?: () => Promise<void> | void;
|
|
2767
|
+
onStopped?: () => Promise<void> | void;
|
|
2768
|
+
}
|
|
2769
|
+
/**
|
|
2770
|
+
* Correlation ID configuration options
|
|
2771
|
+
*/
|
|
2772
|
+
interface CorrelationOptions {
|
|
2773
|
+
/**
|
|
2774
|
+
* The HTTP header name to use for correlation IDs
|
|
2775
|
+
* @default 'x-correlation-id'
|
|
2776
|
+
*/
|
|
2777
|
+
headerName?: string;
|
|
2778
|
+
/**
|
|
2779
|
+
* Custom correlation ID generator function
|
|
2780
|
+
* @default () => `req_${timestamp}_${random}`
|
|
2781
|
+
*/
|
|
2782
|
+
generator?: () => string;
|
|
2783
|
+
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Server options for configuring the BlaizeJS server
|
|
2786
|
+
*/
|
|
2787
|
+
interface ServerOptionsInput {
|
|
2788
|
+
/** Port to listen on (default: 3000) */
|
|
2789
|
+
port?: number;
|
|
2790
|
+
/** Host to bind to (default: localhost) */
|
|
2791
|
+
host?: string;
|
|
2792
|
+
/** Directory containing route files (default: ./routes) */
|
|
2793
|
+
routesDir?: string;
|
|
2794
|
+
/** HTTP/2 options */
|
|
2795
|
+
http2?: {
|
|
2796
|
+
/** Enable HTTP/2 (default: true) */
|
|
2797
|
+
enabled?: boolean | undefined;
|
|
2798
|
+
/** Path to key file for HTTPS/HTTP2 */
|
|
2799
|
+
keyFile?: string | undefined;
|
|
2800
|
+
/** Path to certificate file for HTTPS/HTTP2 */
|
|
2801
|
+
certFile?: string | undefined;
|
|
2802
|
+
};
|
|
2803
|
+
/** Global middleware to apply to all routes */
|
|
2804
|
+
middleware?: Middleware[];
|
|
2805
|
+
/** Plugins to register */
|
|
2806
|
+
plugins?: Plugin[];
|
|
2807
|
+
/**
|
|
2808
|
+
* Correlation ID configuration
|
|
2809
|
+
* @since 0.4.0
|
|
2810
|
+
*/
|
|
2811
|
+
correlation?: CorrelationOptions;
|
|
2812
|
+
/**
|
|
2813
|
+
* CORS configuration
|
|
2814
|
+
*
|
|
2815
|
+
* - `true`: Enable CORS with development defaults (allow all origins)
|
|
2816
|
+
* - `false`: Disable CORS (no headers set)
|
|
2817
|
+
* - `CorsOptions`: Custom CORS configuration
|
|
2818
|
+
*
|
|
2819
|
+
* @default false (CORS disabled)
|
|
2820
|
+
* @since 0.5.0
|
|
2821
|
+
*
|
|
2822
|
+
* @example
|
|
2823
|
+
* ```typescript
|
|
2824
|
+
* // Enable with dev defaults
|
|
2825
|
+
* const server = createServer({ cors: true });
|
|
2826
|
+
*
|
|
2827
|
+
* // Custom configuration
|
|
2828
|
+
* const server = createServer({
|
|
2829
|
+
* cors: {
|
|
2830
|
+
* origin: 'https://example.com',
|
|
2831
|
+
* credentials: true,
|
|
2832
|
+
* maxAge: 86400
|
|
2833
|
+
* }
|
|
2834
|
+
* });
|
|
2835
|
+
*
|
|
2836
|
+
* // Disable CORS
|
|
2837
|
+
* const server = createServer({ cors: false });
|
|
2838
|
+
* ```
|
|
2839
|
+
*/
|
|
2840
|
+
cors?: CorsOptions | boolean;
|
|
2841
|
+
bodyLimits?: Partial<BodyLimits>;
|
|
2842
|
+
/**
|
|
2843
|
+
* Logger configuration
|
|
2844
|
+
*
|
|
2845
|
+
* Controls logging behavior including log levels, transports,
|
|
2846
|
+
* redaction, and request lifecycle logging.
|
|
2847
|
+
*
|
|
2848
|
+
* @default Development: ConsoleTransport with debug level
|
|
2849
|
+
* @default Production: JSONTransport with info level
|
|
2850
|
+
* @since 0.4.0
|
|
2851
|
+
*
|
|
2852
|
+
* @example Development Configuration
|
|
2853
|
+
* ```typescript
|
|
2854
|
+
* import { createServer } from 'blaizejs';
|
|
2855
|
+
*
|
|
2856
|
+
* const server = createServer({
|
|
2857
|
+
* port: 3000,
|
|
2858
|
+
* logging: {
|
|
2859
|
+
* level: 'debug',
|
|
2860
|
+
* includeTimestamp: true,
|
|
2861
|
+
* requestLogging: true
|
|
2862
|
+
* }
|
|
2863
|
+
* });
|
|
2864
|
+
* ```
|
|
2865
|
+
*
|
|
2866
|
+
* @example Production Configuration
|
|
2867
|
+
* ```typescript
|
|
2868
|
+
* import { createServer, JSONTransport } from 'blaizejs';
|
|
2869
|
+
*
|
|
2870
|
+
* const server = createServer({
|
|
2871
|
+
* port: 3000,
|
|
2872
|
+
* logging: {
|
|
2873
|
+
* level: 'info',
|
|
2874
|
+
* transport: new JSONTransport(),
|
|
2875
|
+
* redactKeys: ['password', 'apiKey', 'secret'],
|
|
2876
|
+
* requestLogging: true
|
|
2877
|
+
* }
|
|
2878
|
+
* });
|
|
2879
|
+
* ```
|
|
2880
|
+
*/
|
|
2881
|
+
logging?: LoggerConfig;
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* Configuration for a BlaizeJS server
|
|
2885
|
+
*/
|
|
2886
|
+
interface ServerOptions {
|
|
2887
|
+
/** Port to listen on (default: 3000) */
|
|
2888
|
+
port: number;
|
|
2889
|
+
/** Host to bind to (default: localhost) */
|
|
2890
|
+
host: string;
|
|
2891
|
+
/** Directory containing route files (default: ./routes) */
|
|
2892
|
+
routesDir: string;
|
|
2893
|
+
/** HTTP/2 options */
|
|
2894
|
+
http2?: {
|
|
2895
|
+
/** Enable HTTP/2 (default: true) */
|
|
2896
|
+
enabled?: boolean | undefined;
|
|
2897
|
+
/** Path to key file for HTTPS/HTTP2 */
|
|
2898
|
+
keyFile?: string | undefined;
|
|
2899
|
+
/** Path to certificate file for HTTPS/HTTP2 */
|
|
2900
|
+
certFile?: string | undefined;
|
|
2901
|
+
};
|
|
2902
|
+
/** Global middleware to apply to all routes */
|
|
2903
|
+
middleware?: Middleware[];
|
|
2904
|
+
/** Plugins to register */
|
|
2905
|
+
plugins?: Plugin[];
|
|
2906
|
+
/**
|
|
2907
|
+
* Correlation ID configuration
|
|
2908
|
+
* @since 0.4.0
|
|
2909
|
+
*/
|
|
2910
|
+
correlation?: CorrelationOptions;
|
|
2911
|
+
/**
|
|
2912
|
+
* CORS configuration
|
|
2913
|
+
* @since 0.5.0
|
|
2914
|
+
*/
|
|
2915
|
+
cors?: CorsOptions | boolean;
|
|
2916
|
+
/** Body size limits for incoming requests */
|
|
2917
|
+
bodyLimits: BodyLimits;
|
|
2918
|
+
/** Logger configuration */
|
|
2919
|
+
logging?: LoggerConfig;
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* BlaizeJS Server instance with generic type accumulation
|
|
2923
|
+
*
|
|
2924
|
+
* @template TState - The accumulated state type from middleware
|
|
2925
|
+
* @template TServices - The accumulated services type from middleware and plugins
|
|
2926
|
+
*
|
|
2927
|
+
*/
|
|
2928
|
+
interface Server<TState, TServices> {
|
|
2929
|
+
/** The underlying HTTP or HTTP/2 server */
|
|
2930
|
+
server: http.Server | http2.Http2Server | undefined;
|
|
2931
|
+
/** The port the server is configured to listen on */
|
|
2932
|
+
port: number;
|
|
2933
|
+
/** CORS configuration for this server */
|
|
2934
|
+
corsOptions?: CorsOptions | boolean;
|
|
2935
|
+
/** Body size limits for incoming requests */
|
|
2936
|
+
bodyLimits: BodyLimits;
|
|
2937
|
+
/** The host the server is bound to */
|
|
2938
|
+
host: string;
|
|
2939
|
+
events: EventEmitter;
|
|
2940
|
+
/** Direct access to registered plugins */
|
|
2941
|
+
plugins: Plugin[];
|
|
2942
|
+
/** Direct access to registered plugins */
|
|
2943
|
+
middleware: Middleware[];
|
|
2944
|
+
/** Internal property for signal handlers */
|
|
2945
|
+
_signalHandlers?: {
|
|
2946
|
+
unregister: () => void;
|
|
2947
|
+
};
|
|
2948
|
+
/** Internal logger instance (for server use only) */
|
|
2949
|
+
_logger: BlaizeLogger;
|
|
2950
|
+
/** Start the server and listen for connections */
|
|
2951
|
+
listen: (port?: number, host?: string) => Promise<Server<TState, TServices>>;
|
|
2952
|
+
/** Stop the server */
|
|
2953
|
+
close: (stopOptions?: StopOptions) => Promise<void>;
|
|
2954
|
+
/**
|
|
2955
|
+
* Add global middleware to the server
|
|
2956
|
+
*
|
|
2957
|
+
* @param middleware - Single middleware or array of middleware to add
|
|
2958
|
+
* @returns New Server instance with accumulated types from the middleware
|
|
2959
|
+
*
|
|
2960
|
+
* @example
|
|
2961
|
+
* ```typescript
|
|
2962
|
+
* // Single middleware
|
|
2963
|
+
* const serverWithAuth = server.use(authMiddleware);
|
|
2964
|
+
* // serverWithAuth has type Server<{user: User}, {auth: AuthService}>
|
|
2965
|
+
*
|
|
2966
|
+
* // Array of middleware
|
|
2967
|
+
* const serverWithMiddleware = server.use([authMiddleware, loggerMiddleware]);
|
|
2968
|
+
* // serverWithMiddleware has type Server<{user, requestId}, {auth, logger}>
|
|
2969
|
+
* ```
|
|
2970
|
+
*/
|
|
2971
|
+
use<MS, MSvc>(middleware: Middleware<MS, MSvc>): Server<TState & MS, TServices & MSvc>;
|
|
2972
|
+
use<MW extends readonly Middleware<any, any>[]>(middleware: MW): Server<TState & UnionToIntersection<ExtractMiddlewareState<MW[number]>>, TServices & UnionToIntersection<ExtractMiddlewareServices<MW[number]>>>;
|
|
2973
|
+
/**
|
|
2974
|
+
* Register a plugin with the server
|
|
2975
|
+
*
|
|
2976
|
+
* @param plugin - Single plugin or array of plugins to register
|
|
2977
|
+
* @returns Promise resolving to new Server instance with accumulated types
|
|
2978
|
+
*
|
|
2979
|
+
* @example
|
|
2980
|
+
* ```typescript
|
|
2981
|
+
* // Single plugin
|
|
2982
|
+
* const serverWithDb = await server.register(databasePlugin);
|
|
2983
|
+
* // serverWithDb has type Server<{}, {db: DatabaseService}>
|
|
2984
|
+
*
|
|
2985
|
+
* // Array of plugins
|
|
2986
|
+
* const serverWithPlugins = await server.register([dbPlugin, cachePlugin]);
|
|
2987
|
+
* // serverWithPlugins has type Server<{}, {db, cache}>
|
|
2988
|
+
* ```
|
|
2989
|
+
*/
|
|
2990
|
+
register<PS, PSvc>(plugin: Plugin<PS, PSvc>): Promise<Server<TState & PS, TServices & PSvc>>;
|
|
2991
|
+
register<P extends readonly Plugin<any, any>[]>(plugin: P): Promise<Server<TState & UnionToIntersection<ExtractPluginState<P[number]>>, TServices & UnionToIntersection<ExtractPluginServices<P[number]>>>>;
|
|
2992
|
+
/** Access to the routing system */
|
|
2993
|
+
router: Router;
|
|
2994
|
+
/** Context storage system */
|
|
2995
|
+
context: AsyncLocalStorage<Context>;
|
|
2996
|
+
pluginManager: PluginLifecycleManager;
|
|
2997
|
+
}
|
|
2998
|
+
type RequestHandler = (req: http.IncomingMessage | http2.Http2ServerRequest, res: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
|
|
2999
|
+
|
|
3000
|
+
/**
|
|
3001
|
+
* BlaizeJS Plugin Module
|
|
3002
|
+
*
|
|
3003
|
+
* Provides the plugin system for extending framework functionality.
|
|
1735
3004
|
*/
|
|
1736
|
-
|
|
3005
|
+
|
|
1737
3006
|
/**
|
|
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
|
-
* });
|
|
3007
|
+
* Plugin options
|
|
3008
|
+
*/
|
|
3009
|
+
interface PluginOptions<_T = any> {
|
|
3010
|
+
/** Plugin configuration */
|
|
3011
|
+
[key: string]: any;
|
|
3012
|
+
}
|
|
3013
|
+
/**
|
|
3014
|
+
* Plugin lifecycle hooks with full type safety
|
|
1754
3015
|
*
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
3016
|
+
* Plugins execute in this order:
|
|
3017
|
+
* 1. register() - Add middleware, routes
|
|
3018
|
+
* 2. initialize() - Create resources
|
|
3019
|
+
* 3. onServerStart() - Start background work
|
|
3020
|
+
* 4. onServerStop() - Stop background work
|
|
3021
|
+
* 5. terminate() - Cleanup resources
|
|
1758
3022
|
*/
|
|
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;
|
|
3023
|
+
interface PluginHooks<TState = {}, TServices = {}> {
|
|
1772
3024
|
/**
|
|
1773
|
-
*
|
|
3025
|
+
* Called when plugin is registered to server
|
|
3026
|
+
*
|
|
3027
|
+
* Use this hook to:
|
|
3028
|
+
* - Add middleware via server.use()
|
|
3029
|
+
* - Add routes via server.router.addRoute()
|
|
3030
|
+
* - Subscribe to server events
|
|
3031
|
+
*
|
|
3032
|
+
* @param server - BlaizeJS server instance
|
|
3033
|
+
* @example
|
|
3034
|
+
* ```typescript
|
|
3035
|
+
* register: async (server) => {
|
|
3036
|
+
* server.use(createMiddleware({
|
|
3037
|
+
* handler: async (ctx, next) => {
|
|
3038
|
+
* ctx.services.db = db;
|
|
3039
|
+
* await next();
|
|
3040
|
+
* },
|
|
3041
|
+
* }));
|
|
3042
|
+
* }
|
|
3043
|
+
* ```
|
|
1774
3044
|
*/
|
|
1775
|
-
|
|
3045
|
+
register?: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1776
3046
|
/**
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
3047
|
+
* Called during server initialization
|
|
3048
|
+
*
|
|
3049
|
+
* Use this hook to:
|
|
3050
|
+
* - Create database connections
|
|
3051
|
+
* - Initialize services
|
|
3052
|
+
* - Allocate resources
|
|
3053
|
+
*
|
|
3054
|
+
* @example
|
|
3055
|
+
* ```typescript
|
|
3056
|
+
* initialize: async () => {
|
|
3057
|
+
* db = await Database.connect(config);
|
|
3058
|
+
* }
|
|
3059
|
+
* ```
|
|
1779
3060
|
*/
|
|
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;
|
|
3061
|
+
initialize?: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1794
3062
|
/**
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
3063
|
+
* Called when server starts listening
|
|
3064
|
+
*
|
|
3065
|
+
* Use this hook to:
|
|
3066
|
+
* - Start background workers
|
|
3067
|
+
* - Start cron jobs
|
|
3068
|
+
* - Begin health checks
|
|
3069
|
+
*
|
|
3070
|
+
* @example
|
|
3071
|
+
* ```typescript
|
|
3072
|
+
* onServerStart: async () => {
|
|
3073
|
+
* worker = new BackgroundWorker();
|
|
3074
|
+
* await worker.start();
|
|
3075
|
+
* }
|
|
3076
|
+
* ```
|
|
1797
3077
|
*/
|
|
1798
|
-
|
|
3078
|
+
onServerStart?: (server: Http2Server | Server$1) => void | Promise<void>;
|
|
1799
3079
|
/**
|
|
1800
|
-
*
|
|
1801
|
-
*
|
|
3080
|
+
* Called when server stops listening
|
|
3081
|
+
*
|
|
3082
|
+
* Use this hook to:
|
|
3083
|
+
* - Stop background workers
|
|
3084
|
+
* - Flush buffers
|
|
3085
|
+
* - Complete in-flight work
|
|
3086
|
+
*
|
|
3087
|
+
* @example
|
|
3088
|
+
* ```typescript
|
|
3089
|
+
* onServerStop: async () => {
|
|
3090
|
+
* await worker.stop({ graceful: true });
|
|
3091
|
+
* }
|
|
3092
|
+
* ```
|
|
1802
3093
|
*/
|
|
1803
|
-
|
|
3094
|
+
onServerStop?: (server: Http2Server | Server$1) => void | Promise<void>;
|
|
1804
3095
|
/**
|
|
1805
|
-
*
|
|
3096
|
+
* Called during server termination
|
|
3097
|
+
*
|
|
3098
|
+
* Use this hook to:
|
|
3099
|
+
* - Close database connections
|
|
3100
|
+
* - Release file handles
|
|
3101
|
+
* - Free memory
|
|
3102
|
+
*
|
|
3103
|
+
* @example
|
|
3104
|
+
* ```typescript
|
|
3105
|
+
* terminate: async () => {
|
|
3106
|
+
* await db?.close();
|
|
3107
|
+
* }
|
|
3108
|
+
* ```
|
|
1806
3109
|
*/
|
|
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;
|
|
3110
|
+
terminate?: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1857
3111
|
}
|
|
1858
3112
|
/**
|
|
1859
|
-
*
|
|
3113
|
+
* Options for creating a plugin with createPlugin()
|
|
3114
|
+
*
|
|
3115
|
+
* @template TConfig - Plugin configuration shape
|
|
3116
|
+
* @template TState - State added to context
|
|
3117
|
+
* @template TServices - Services added to context
|
|
1860
3118
|
*/
|
|
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;
|
|
3119
|
+
interface CreatePluginOptions<TConfig, TState = {}, TServices = {}> {
|
|
1868
3120
|
/**
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
3121
|
+
* Plugin name (e.g., '@blaizejs/metrics')
|
|
3122
|
+
* Must be unique within a server instance
|
|
1871
3123
|
*/
|
|
1872
|
-
|
|
3124
|
+
name: string;
|
|
1873
3125
|
/**
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
1876
|
-
* @param event - Event name
|
|
1877
|
-
* @param data - Event data
|
|
3126
|
+
* Semantic version (e.g., '1.0.0')
|
|
3127
|
+
* Used for compatibility checks
|
|
1878
3128
|
*/
|
|
1879
|
-
|
|
3129
|
+
version: string;
|
|
1880
3130
|
/**
|
|
1881
|
-
*
|
|
1882
|
-
*
|
|
1883
|
-
*
|
|
1884
|
-
* @
|
|
1885
|
-
*
|
|
3131
|
+
* Default configuration values
|
|
3132
|
+
* Merged with user config when plugin is created
|
|
3133
|
+
*
|
|
3134
|
+
* @example
|
|
3135
|
+
* ```typescript
|
|
3136
|
+
* defaultConfig: {
|
|
3137
|
+
* enabled: true,
|
|
3138
|
+
* timeout: 30000,
|
|
3139
|
+
* }
|
|
3140
|
+
* ```
|
|
1886
3141
|
*/
|
|
1887
|
-
|
|
3142
|
+
defaultConfig?: TConfig;
|
|
1888
3143
|
/**
|
|
1889
|
-
*
|
|
1890
|
-
*
|
|
3144
|
+
* Setup function that returns lifecycle hooks
|
|
3145
|
+
*
|
|
3146
|
+
* Receives merged config (defaultConfig + userConfig).
|
|
3147
|
+
* Returns partial hook object - all hooks optional.
|
|
3148
|
+
*
|
|
3149
|
+
* @param config - Merged configuration
|
|
3150
|
+
* @returns Partial plugin hooks
|
|
3151
|
+
*
|
|
3152
|
+
* @example
|
|
3153
|
+
* ```typescript
|
|
3154
|
+
* setup: (config) => {
|
|
3155
|
+
* let db: Database;
|
|
3156
|
+
*
|
|
3157
|
+
* return {
|
|
3158
|
+
* initialize: async () => {
|
|
3159
|
+
* db = await Database.connect(config);
|
|
3160
|
+
* },
|
|
3161
|
+
* terminate: async () => {
|
|
3162
|
+
* await db?.close();
|
|
3163
|
+
* },
|
|
3164
|
+
* };
|
|
3165
|
+
* }
|
|
3166
|
+
* ```
|
|
1891
3167
|
*/
|
|
1892
|
-
|
|
3168
|
+
setup: (config: TConfig, logger: BlaizeLogger) => Partial<PluginHooks<TState, TServices>>;
|
|
3169
|
+
}
|
|
3170
|
+
/**
|
|
3171
|
+
* Plugin interface
|
|
3172
|
+
*/
|
|
3173
|
+
interface Plugin<TState = {}, TServices = {}> extends PluginHooks<TState, TServices> {
|
|
3174
|
+
/** Plugin name */
|
|
3175
|
+
name: string;
|
|
3176
|
+
/** Plugin version */
|
|
3177
|
+
version: string;
|
|
1893
3178
|
/**
|
|
1894
|
-
*
|
|
3179
|
+
* Called when plugin is registered to server
|
|
3180
|
+
*
|
|
3181
|
+
* This hook is always present - createPlugin provides a default empty async function
|
|
3182
|
+
* if not specified by the plugin author.
|
|
3183
|
+
*
|
|
3184
|
+
* @override Makes register required (not optional like in PluginHooks)
|
|
1895
3185
|
*/
|
|
1896
|
-
|
|
3186
|
+
register: (server: Server<TState, TServices>) => void | Promise<void>;
|
|
1897
3187
|
/**
|
|
1898
|
-
*
|
|
3188
|
+
* Type carriers for compile-time type information
|
|
3189
|
+
* These are never used at runtime but allow TypeScript to track types
|
|
1899
3190
|
*/
|
|
1900
|
-
|
|
3191
|
+
_state?: TState;
|
|
3192
|
+
_services?: TServices;
|
|
1901
3193
|
}
|
|
1902
3194
|
/**
|
|
1903
|
-
*
|
|
3195
|
+
* Plugin factory function
|
|
1904
3196
|
*/
|
|
1905
|
-
type
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
}
|
|
3197
|
+
type PluginFactory<TConfig = any, TState = {}, TServices = {}> = (options?: Partial<TConfig>) => Plugin<TState, TServices>;
|
|
3198
|
+
interface PluginLifecycleManager {
|
|
3199
|
+
initializePlugins(server: Server<any, any>): Promise<void>;
|
|
3200
|
+
terminatePlugins(server: Server<any, any>): Promise<void>;
|
|
3201
|
+
onServerStart(server: Server<any, any>, httpServer: any): Promise<void>;
|
|
3202
|
+
onServerStop(server: Server<any, any>, httpServer: any): Promise<void>;
|
|
3203
|
+
}
|
|
3204
|
+
interface PluginLifecycleOptions {
|
|
3205
|
+
/** Continue initialization even if a plugin fails */
|
|
3206
|
+
continueOnError?: boolean;
|
|
3207
|
+
/** Custom error handler for plugin failures */
|
|
3208
|
+
onError?: (plugin: Plugin, phase: string, error: Error) => void;
|
|
3209
|
+
}
|
|
3210
|
+
|
|
1912
3211
|
/**
|
|
1913
|
-
*
|
|
3212
|
+
* Type composition utilities for extracting and composing middleware type contributions
|
|
3213
|
+
* @module composition
|
|
3214
|
+
* @since v0.4.0
|
|
1914
3215
|
*/
|
|
1915
|
-
|
|
1916
|
-
stream: SSEStream;
|
|
1917
|
-
connectedAt: number;
|
|
1918
|
-
lastActivity: number;
|
|
1919
|
-
clientIp?: string;
|
|
1920
|
-
userAgent?: string;
|
|
1921
|
-
}
|
|
3216
|
+
|
|
1922
3217
|
/**
|
|
1923
|
-
*
|
|
3218
|
+
* Extracts the State type contribution from a middleware
|
|
3219
|
+
* @template T - The middleware type to extract from
|
|
3220
|
+
* @returns The state type if present, empty object otherwise
|
|
1924
3221
|
*/
|
|
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
|
-
}
|
|
3222
|
+
type ExtractMiddlewareState<T> = T extends Middleware<infer S, any> ? S : {};
|
|
1946
3223
|
/**
|
|
1947
|
-
*
|
|
3224
|
+
* Extracts the State type contribution from a plugin
|
|
3225
|
+
* @template T - The plugin type to extract from
|
|
3226
|
+
* @returns The state type if present, empty object otherwise
|
|
1948
3227
|
*/
|
|
1949
|
-
|
|
1950
|
-
send<K extends keyof TEvents>(event: K & string, data: z.infer<TEvents[K]>): void;
|
|
1951
|
-
}
|
|
3228
|
+
type ExtractPluginState<T> = T extends Plugin<infer S, any> ? S : {};
|
|
1952
3229
|
/**
|
|
1953
|
-
*
|
|
3230
|
+
* Extracts the Services type contribution from a middleware
|
|
3231
|
+
* @template T - The middleware type to extract from
|
|
3232
|
+
* @returns The services type if present, empty object otherwise
|
|
1954
3233
|
*/
|
|
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
|
-
}
|
|
3234
|
+
type ExtractMiddlewareServices<T> = T extends Middleware<any, infer S> ? S : {};
|
|
1963
3235
|
/**
|
|
1964
|
-
*
|
|
1965
|
-
*
|
|
3236
|
+
* Extracts the Services type contribution from a plugin
|
|
3237
|
+
* @template T - The plugin type to extract from
|
|
3238
|
+
* @returns The services type if present, empty object otherwise
|
|
1966
3239
|
*/
|
|
1967
|
-
type
|
|
1968
|
-
params: TParams) => Promise<void> | void;
|
|
3240
|
+
type ExtractPluginServices<T> = T extends Plugin<any, infer S> ? S : {};
|
|
1969
3241
|
/**
|
|
1970
|
-
*
|
|
1971
|
-
*
|
|
3242
|
+
* Utility type to convert a union type to an intersection type
|
|
3243
|
+
* This is the magic that allows us to compose multiple middleware contributions
|
|
3244
|
+
*
|
|
3245
|
+
* @example
|
|
3246
|
+
* type U = { a: string } | { b: number }
|
|
3247
|
+
* type I = UnionToIntersection<U> // { a: string } & { b: number }
|
|
1972
3248
|
*
|
|
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
3249
|
*/
|
|
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
|
-
};
|
|
3250
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
1999
3251
|
/**
|
|
2000
|
-
*
|
|
3252
|
+
* Composes state contributions from an array of middleware
|
|
3253
|
+
* Merges all state types into a single intersection type
|
|
3254
|
+
*
|
|
3255
|
+
* @template T - ReadonlyArray of Middleware
|
|
3256
|
+
* @returns Intersection of all state contributions
|
|
3257
|
+
*
|
|
3258
|
+
* @example
|
|
3259
|
+
* const middlewares = [authMiddleware, loggerMiddleware] as const;
|
|
3260
|
+
* type ComposedState = ComposeStates<typeof middlewares>;
|
|
3261
|
+
* // Result: { user: User } & { requestId: string }
|
|
2001
3262
|
*/
|
|
2002
|
-
|
|
2003
|
-
id: string;
|
|
2004
|
-
event: string;
|
|
2005
|
-
data: unknown;
|
|
2006
|
-
size: number;
|
|
2007
|
-
timestamp: number;
|
|
2008
|
-
correlationId: string;
|
|
2009
|
-
}
|
|
3263
|
+
type ComposeMiddlewareStates<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareState<T[number]>>;
|
|
2010
3264
|
/**
|
|
2011
|
-
*
|
|
3265
|
+
* Composes state contributions from an array of plugins
|
|
3266
|
+
* Merges all state types into a single intersection type
|
|
3267
|
+
*
|
|
3268
|
+
* @template T - ReadonlyArray of Plugin
|
|
3269
|
+
* @returns Intersection of all state contributions
|
|
3270
|
+
*
|
|
3271
|
+
* @example
|
|
3272
|
+
* const plugins = [authPlugin, dbPlugin] as const;
|
|
3273
|
+
* type ComposedState = ComposePluginStates<typeof plugins>;
|
|
3274
|
+
* // Result: { config: AuthConfig } & { dbConnected: boolean }
|
|
2012
3275
|
*/
|
|
2013
|
-
|
|
2014
|
-
eventsSent: number;
|
|
2015
|
-
eventsDropped: number;
|
|
2016
|
-
bytesWritten: number;
|
|
2017
|
-
bufferHighWatermark: number;
|
|
2018
|
-
lastEventTime: number;
|
|
2019
|
-
}
|
|
2020
|
-
|
|
3276
|
+
type ComposePluginStates<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginState<T[number]>>;
|
|
2021
3277
|
/**
|
|
2022
|
-
*
|
|
2023
|
-
*
|
|
3278
|
+
* Composes service contributions from an array of middleware
|
|
3279
|
+
* Merges all service types into a single intersection type
|
|
3280
|
+
*
|
|
3281
|
+
* @template T - ReadonlyArray of Middleware
|
|
3282
|
+
* @returns Intersection of all service contributions
|
|
3283
|
+
*
|
|
3284
|
+
* @example
|
|
3285
|
+
* const middlewares = [dbMiddleware, cacheMiddleware] as const;
|
|
3286
|
+
* type ComposedServices = ComposeServices<typeof middlewares>;
|
|
3287
|
+
* // Result: { db: Database } & { cache: Cache }
|
|
3288
|
+
*/
|
|
3289
|
+
type ComposeMiddlewareServices<T extends ReadonlyArray<Middleware>> = T extends readonly [] ? {} : UnionToIntersection<ExtractMiddlewareServices<T[number]>>;
|
|
3290
|
+
/**
|
|
3291
|
+
* Composes service contributions from an array of plugins
|
|
3292
|
+
* Merges all service types into a single intersection type
|
|
3293
|
+
*
|
|
3294
|
+
* @template T - ReadonlyArray of Plugin
|
|
3295
|
+
* @returns Intersection of all service contributions
|
|
3296
|
+
*
|
|
3297
|
+
* @example
|
|
3298
|
+
* const plugins = [dbPlugin, cachePlugin] as const;
|
|
3299
|
+
* type ComposedServices = ComposePluginServices<typeof plugins>;
|
|
3300
|
+
* // Result: { db: Database } & { cache: Cache }
|
|
3301
|
+
*/
|
|
3302
|
+
type ComposePluginServices<T extends ReadonlyArray<Plugin<any, any>>> = T extends readonly [] ? {} : UnionToIntersection<ExtractPluginServices<T[number]>>;
|
|
3303
|
+
/**
|
|
3304
|
+
* Safe version of ExtractState that handles edge cases
|
|
3305
|
+
* @template T - The middleware type to extract from
|
|
3306
|
+
* @returns The state type, handling never/any/unknown gracefully
|
|
3307
|
+
*/
|
|
3308
|
+
type SafeExtractMiddlewareState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<infer S, any> ? unknown extends S ? {} : S : {};
|
|
3309
|
+
/**
|
|
3310
|
+
* Safe version of ExtractPluginState that handles edge cases
|
|
3311
|
+
* @template T - The plugin type to extract from
|
|
3312
|
+
* @returns The state type, handling never/any/unknown gracefully
|
|
2024
3313
|
*/
|
|
2025
|
-
|
|
3314
|
+
type SafeExtractPluginState<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<infer S, any> ? unknown extends S ? {} : S : {};
|
|
2026
3315
|
/**
|
|
2027
|
-
*
|
|
3316
|
+
* Safe version of ExtractServices that handles edge cases
|
|
3317
|
+
* @template T - The middleware type to extract from
|
|
3318
|
+
* @returns The services type, handling never/any/unknown gracefully
|
|
2028
3319
|
*/
|
|
2029
|
-
|
|
2030
|
-
[event: string]: Set<(data: any) => void>;
|
|
2031
|
-
}
|
|
3320
|
+
type SafeExtractMiddlewareServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Middleware<any, infer S> ? unknown extends S ? {} : S : {};
|
|
2032
3321
|
/**
|
|
2033
|
-
*
|
|
3322
|
+
* Safe version of ExtractPluginServices that handles edge cases
|
|
3323
|
+
* @template T - The plugin type to extract from
|
|
3324
|
+
* @returns The services type, handling never/any/unknown gracefully
|
|
2034
3325
|
*/
|
|
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
|
-
}
|
|
3326
|
+
type SafeExtractPluginServices<T> = IsNever<T> extends true ? {} : IsAny<T> extends true ? {} : T extends Plugin<any, infer S> ? unknown extends S ? {} : S : {};
|
|
2061
3327
|
/**
|
|
2062
|
-
*
|
|
3328
|
+
* Composes state with better edge case handling
|
|
3329
|
+
* @template T - ReadonlyArray of Middleware
|
|
3330
|
+
* @returns Safely composed state types
|
|
2063
3331
|
*/
|
|
2064
|
-
|
|
2065
|
-
eventsReceived: number;
|
|
2066
|
-
bytesReceived: number;
|
|
2067
|
-
connectionDuration: number;
|
|
2068
|
-
reconnectAttempts: number;
|
|
2069
|
-
lastEventId?: string;
|
|
2070
|
-
}
|
|
3332
|
+
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]>>;
|
|
2071
3333
|
/**
|
|
2072
|
-
*
|
|
3334
|
+
* Composes plugin state with better edge case handling
|
|
3335
|
+
* @template T - ReadonlyArray of Plugin
|
|
3336
|
+
* @returns Safely composed state types
|
|
2073
3337
|
*/
|
|
2074
|
-
type
|
|
3338
|
+
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]>>;
|
|
2075
3339
|
/**
|
|
2076
|
-
*
|
|
3340
|
+
* Composes services with better edge case handling
|
|
3341
|
+
* @template T - ReadonlyArray of Middleware
|
|
3342
|
+
* @returns Safely composed service types
|
|
2077
3343
|
*/
|
|
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
|
-
}
|
|
3344
|
+
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]>>;
|
|
2096
3345
|
/**
|
|
2097
|
-
*
|
|
3346
|
+
* Composes plugin services with better edge case handling
|
|
3347
|
+
* @template T - ReadonlyArray of Plugin
|
|
3348
|
+
* @returns Safely composed service types
|
|
2098
3349
|
*/
|
|
2099
|
-
|
|
2100
|
-
reconnect: boolean;
|
|
2101
|
-
reason?: string;
|
|
2102
|
-
}
|
|
3350
|
+
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]>>;
|
|
2103
3351
|
/**
|
|
2104
|
-
*
|
|
2105
|
-
*
|
|
3352
|
+
* Utility to merge two state types
|
|
3353
|
+
* Handles conflicts by using the rightmost (latest) type
|
|
3354
|
+
*
|
|
3355
|
+
* @template A - First state type
|
|
3356
|
+
* @template B - Second state type
|
|
3357
|
+
* @returns Merged state with B taking precedence
|
|
2106
3358
|
*/
|
|
2107
|
-
type
|
|
2108
|
-
|
|
2109
|
-
type ExtractMethod<T> = T extends {
|
|
2110
|
-
GET: any;
|
|
2111
|
-
} ? 'GET' : T extends {
|
|
2112
|
-
POST: any;
|
|
2113
|
-
} ? 'POST' : T extends {
|
|
2114
|
-
PUT: any;
|
|
2115
|
-
} ? 'PUT' : T extends {
|
|
2116
|
-
DELETE: any;
|
|
2117
|
-
} ? 'DELETE' : T extends {
|
|
2118
|
-
PATCH: any;
|
|
2119
|
-
} ? 'PATCH' : T extends {
|
|
2120
|
-
HEAD: any;
|
|
2121
|
-
} ? 'HEAD' : T extends {
|
|
2122
|
-
OPTIONS: any;
|
|
2123
|
-
} ? 'OPTIONS' : never;
|
|
2124
|
-
type BuildRoutesRegistry<TRoutes extends Record<string, any>> = {
|
|
2125
|
-
[Method in ExtractMethod<TRoutes[keyof TRoutes]> as `$${Lowercase<Method>}`]: {
|
|
2126
|
-
[K in keyof TRoutes as ExtractMethod<TRoutes[K]> extends Method ? K : never]: TRoutes[K];
|
|
2127
|
-
};
|
|
2128
|
-
};
|
|
2129
|
-
type GetRouteMethodOptions<TRoute> = TRoute extends {
|
|
2130
|
-
GET: infer M;
|
|
2131
|
-
} ? M : TRoute extends {
|
|
2132
|
-
POST: infer M;
|
|
2133
|
-
} ? M : TRoute extends {
|
|
2134
|
-
PUT: infer M;
|
|
2135
|
-
} ? M : TRoute extends {
|
|
2136
|
-
DELETE: infer M;
|
|
2137
|
-
} ? M : TRoute extends {
|
|
2138
|
-
PATCH: infer M;
|
|
2139
|
-
} ? M : TRoute extends {
|
|
2140
|
-
HEAD: infer M;
|
|
2141
|
-
} ? M : TRoute extends {
|
|
2142
|
-
OPTIONS: infer M;
|
|
2143
|
-
} ? M : never;
|
|
2144
|
-
type IsNever$1<T> = [T] extends [never] ? true : false;
|
|
2145
|
-
type BuildArgsObject<P, Q, B> = (IsNever$1<P> extends true ? {} : {
|
|
2146
|
-
params: Infer<P>;
|
|
2147
|
-
}) & (IsNever$1<Q> extends true ? {} : {
|
|
2148
|
-
query: Infer<Q>;
|
|
2149
|
-
}) & (IsNever$1<B> extends true ? {} : {
|
|
2150
|
-
body: Infer<B>;
|
|
2151
|
-
});
|
|
2152
|
-
type IsEmptyObject<T> = keyof T extends never ? true : false;
|
|
2153
|
-
type BuildArgs<P, Q, B> = IsEmptyObject<BuildArgsObject<P, Q, B>> extends true ? void : BuildArgsObject<P, Q, B>;
|
|
2154
|
-
type CreateClientMethod<TRoute> = GetRouteMethodOptions<TRoute> extends RouteMethodOptions<infer P, infer Q, infer B, infer R> ? BuildArgs<P, Q, B> extends void ? () => Promise<R extends z.ZodType ? Infer<R> : unknown> : (args: BuildArgs<P, Q, B>) => Promise<R extends z.ZodType ? Infer<R> : unknown> : never;
|
|
2155
|
-
type CreateClient<TRoutes extends Record<string, Record<string, any>>> = {
|
|
2156
|
-
[Method in keyof TRoutes]: {
|
|
2157
|
-
[RouteName in keyof TRoutes[Method]]: CreateClientMethod<TRoutes[Method][RouteName]>;
|
|
2158
|
-
};
|
|
2159
|
-
};
|
|
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
|
-
}
|
|
3359
|
+
type MergeStates<A, B> = Omit<A, keyof B> & B;
|
|
2178
3360
|
/**
|
|
2179
|
-
*
|
|
2180
|
-
*
|
|
3361
|
+
* Utility to merge two service types
|
|
3362
|
+
* Handles conflicts by using the rightmost (latest) type
|
|
3363
|
+
*
|
|
3364
|
+
* @template A - First services type
|
|
3365
|
+
* @template B - Second services type
|
|
3366
|
+
* @returns Merged services with B taking precedence
|
|
2181
3367
|
*/
|
|
2182
|
-
type
|
|
2183
|
-
SSE: any;
|
|
2184
|
-
} ? true : false;
|
|
3368
|
+
type MergeServices<A, B> = Omit<A, keyof B> & B;
|
|
2185
3369
|
/**
|
|
2186
|
-
* Extract
|
|
3370
|
+
* Extract both state and services from a middleware at once
|
|
3371
|
+
* @template T - The middleware type
|
|
3372
|
+
* @returns Object with state and services types
|
|
2187
3373
|
*/
|
|
2188
|
-
type
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
} ? E extends z.ZodType ? z.infer<E> : Record<string, unknown> : Record<string, unknown>;
|
|
3374
|
+
type ExtractMiddlewareTypes<T> = {
|
|
3375
|
+
state: ExtractMiddlewareState<T>;
|
|
3376
|
+
services: ExtractMiddlewareServices<T>;
|
|
3377
|
+
};
|
|
2193
3378
|
/**
|
|
2194
|
-
* Extract
|
|
3379
|
+
* Extract both state and services from a plugin at once
|
|
3380
|
+
* @template T - The plugin type
|
|
3381
|
+
* @returns Object with state and services types
|
|
2195
3382
|
*/
|
|
2196
|
-
type
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
};
|
|
2201
|
-
};
|
|
2202
|
-
} ? Q extends z.ZodType ? z.infer<Q> : Record<string, unknown> : never;
|
|
3383
|
+
type ExtractPluginTypes<T> = {
|
|
3384
|
+
state: ExtractPluginState<T>;
|
|
3385
|
+
services: ExtractPluginServices<T>;
|
|
3386
|
+
};
|
|
2203
3387
|
/**
|
|
2204
|
-
*
|
|
3388
|
+
* Compose both state and services from middleware array at once
|
|
3389
|
+
* @template T - ReadonlyArray of Middleware
|
|
3390
|
+
* @returns Object with composed state and services
|
|
2205
3391
|
*/
|
|
2206
|
-
type
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
};
|
|
2211
|
-
};
|
|
2212
|
-
} ? P extends z.ZodType ? z.infer<P> : Record<string, string> : never;
|
|
3392
|
+
type ComposeMiddlewareTypes<T extends ReadonlyArray<Middleware>> = {
|
|
3393
|
+
state: ComposeMiddlewareStates<T>;
|
|
3394
|
+
services: ComposeMiddlewareServices<T>;
|
|
3395
|
+
};
|
|
2213
3396
|
/**
|
|
2214
|
-
*
|
|
3397
|
+
* Compose both state and services from plugin array at once
|
|
3398
|
+
* @template T - ReadonlyArray of Plugin
|
|
3399
|
+
* @returns Object with composed state and services
|
|
2215
3400
|
*/
|
|
2216
|
-
type
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
query: ExtractSSEQuery<TRoute>;
|
|
2220
|
-
options?: SSEClientOptions;
|
|
2221
|
-
} : ExtractSSEQuery<TRoute> extends never ? {
|
|
2222
|
-
params: ExtractSSEParams<TRoute>;
|
|
2223
|
-
options?: SSEClientOptions;
|
|
2224
|
-
} : {
|
|
2225
|
-
params: ExtractSSEParams<TRoute>;
|
|
2226
|
-
query: ExtractSSEQuery<TRoute>;
|
|
2227
|
-
options?: SSEClientOptions;
|
|
3401
|
+
type ComposePluginTypes<T extends ReadonlyArray<Plugin<any, any>>> = {
|
|
3402
|
+
state: ComposePluginStates<T>;
|
|
3403
|
+
services: ComposePluginServices<T>;
|
|
2228
3404
|
};
|
|
2229
3405
|
/**
|
|
2230
|
-
*
|
|
3406
|
+
* Type guard to check if a value is a Middleware
|
|
3407
|
+
* @param value - Value to check
|
|
3408
|
+
* @returns True if value is a Middleware
|
|
3409
|
+
*/
|
|
3410
|
+
declare function isMiddleware(value: unknown): value is Middleware;
|
|
3411
|
+
/**
|
|
3412
|
+
* Type guard to check if a value is a Plugin
|
|
3413
|
+
* @param value - Value to check
|
|
3414
|
+
* @returns True if value is a Plugin
|
|
3415
|
+
*/
|
|
3416
|
+
declare function isPlugin(value: unknown): value is Plugin;
|
|
3417
|
+
/**
|
|
3418
|
+
* Type helper for middleware arrays
|
|
3419
|
+
* Ensures proper readonly array typing for composition
|
|
3420
|
+
*
|
|
3421
|
+
* @example
|
|
3422
|
+
* const middlewares = asMiddlewareArray([auth, logger, cache]);
|
|
3423
|
+
* type State = ComposeStates<typeof middlewares>;
|
|
2231
3424
|
*/
|
|
2232
|
-
|
|
2233
|
-
options?: SSEClientOptions;
|
|
2234
|
-
} ? (args?: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : (args: BuildSSEArgs<TRoute>) => Promise<SSEClient<ExtractSSEEvents<TRoute>>> : never;
|
|
3425
|
+
declare function asMiddlewareArray<T extends ReadonlyArray<Middleware>>(middlewares: T): T;
|
|
2235
3426
|
/**
|
|
2236
|
-
*
|
|
3427
|
+
* Type helper for plugin arrays
|
|
3428
|
+
* Ensures proper readonly array typing for composition
|
|
3429
|
+
*
|
|
3430
|
+
* @example
|
|
3431
|
+
* const plugins = asPluginArray([dbPlugin, cachePlugin]);
|
|
3432
|
+
* type Services = ComposePluginServices<typeof plugins>;
|
|
2237
3433
|
*/
|
|
2238
|
-
|
|
2239
|
-
[K in keyof TRoutes as HasSSEMethod<TRoutes[K]> extends true ? K : never]: TRoutes[K];
|
|
2240
|
-
};
|
|
3434
|
+
declare function asPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(plugins: T): T;
|
|
2241
3435
|
/**
|
|
2242
|
-
*
|
|
3436
|
+
* Create a typed middleware array with inferred types
|
|
3437
|
+
* Useful for getting proper const assertions
|
|
3438
|
+
*
|
|
3439
|
+
* @example
|
|
3440
|
+
* const middlewares = createMiddlewareArray(auth, logger, cache);
|
|
3441
|
+
* type State = ComposeStates<typeof middlewares>;
|
|
2243
3442
|
*/
|
|
2244
|
-
|
|
2245
|
-
$sse: {
|
|
2246
|
-
[K in keyof ExtractSSERoutes<TRoutes>]: CreateSSEMethod<TRoutes[K]>;
|
|
2247
|
-
};
|
|
2248
|
-
};
|
|
2249
|
-
|
|
3443
|
+
declare function createMiddlewareArray<T extends ReadonlyArray<Middleware>>(...middlewares: T): T;
|
|
2250
3444
|
/**
|
|
2251
|
-
*
|
|
3445
|
+
* Create a typed plugin array with inferred types
|
|
3446
|
+
* Useful for getting proper const assertions
|
|
2252
3447
|
*
|
|
2253
|
-
*
|
|
2254
|
-
*
|
|
3448
|
+
* @example
|
|
3449
|
+
* const plugins = createPluginArray(dbPlugin, cachePlugin);
|
|
3450
|
+
* type Services = ComposePluginServices<typeof plugins>;
|
|
2255
3451
|
*/
|
|
3452
|
+
declare function createPluginArray<T extends ReadonlyArray<Plugin<any, any>>>(...plugins: T): T;
|
|
2256
3453
|
|
|
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
3454
|
/**
|
|
2274
|
-
*
|
|
3455
|
+
* Console Transport for Development
|
|
3456
|
+
*
|
|
3457
|
+
* Pretty-prints logs with colors for human-readable development output.
|
|
3458
|
+
* Uses Node.js built-in util.inspect for metadata formatting.
|
|
3459
|
+
*
|
|
3460
|
+
* @packageDocumentation
|
|
2275
3461
|
*/
|
|
2276
|
-
|
|
2277
|
-
/**
|
|
2278
|
-
* The HTTP header name to use for correlation IDs
|
|
2279
|
-
* @default 'x-correlation-id'
|
|
2280
|
-
*/
|
|
2281
|
-
headerName?: string;
|
|
2282
|
-
/**
|
|
2283
|
-
* Custom correlation ID generator function
|
|
2284
|
-
* @default () => `req_${timestamp}_${random}`
|
|
2285
|
-
*/
|
|
2286
|
-
generator?: () => string;
|
|
2287
|
-
}
|
|
3462
|
+
|
|
2288
3463
|
/**
|
|
2289
|
-
*
|
|
3464
|
+
* Console transport for development logging
|
|
3465
|
+
*
|
|
3466
|
+
* Outputs colorized, human-readable logs to the console.
|
|
3467
|
+
* Uses console.log/warn/error appropriately based on log level.
|
|
3468
|
+
*
|
|
3469
|
+
* Features:
|
|
3470
|
+
* - Colorized log levels (debug=gray, info=blue, warn=yellow, error=red)
|
|
3471
|
+
* - Pretty-printed metadata with util.inspect
|
|
3472
|
+
* - Error objects automatically serialized with stack traces
|
|
3473
|
+
* - Stateless - safe for concurrent logging
|
|
3474
|
+
*
|
|
3475
|
+
* @example
|
|
3476
|
+
* ```typescript
|
|
3477
|
+
* import { ConsoleTransport } from './transports';
|
|
3478
|
+
*
|
|
3479
|
+
* const transport = new ConsoleTransport();
|
|
3480
|
+
*
|
|
3481
|
+
* transport.write('info', 'User login', {
|
|
3482
|
+
* userId: '123',
|
|
3483
|
+
* method: 'oauth',
|
|
3484
|
+
* timestamp: '2025-10-20T15:30:00Z'
|
|
3485
|
+
* });
|
|
3486
|
+
*
|
|
3487
|
+
* // Output:
|
|
3488
|
+
* // [INFO] User login
|
|
3489
|
+
* // {
|
|
3490
|
+
* // userId: '123',
|
|
3491
|
+
* // method: 'oauth',
|
|
3492
|
+
* // timestamp: '2025-10-20T15:30:00Z'
|
|
3493
|
+
* // }
|
|
3494
|
+
* ```
|
|
2290
3495
|
*/
|
|
2291
|
-
|
|
2292
|
-
/** Port to listen on (default: 3000) */
|
|
2293
|
-
port?: number;
|
|
2294
|
-
/** Host to bind to (default: localhost) */
|
|
2295
|
-
host?: string;
|
|
2296
|
-
/** Directory containing route files (default: ./routes) */
|
|
2297
|
-
routesDir?: string;
|
|
2298
|
-
/** HTTP/2 options */
|
|
2299
|
-
http2?: {
|
|
2300
|
-
/** Enable HTTP/2 (default: true) */
|
|
2301
|
-
enabled?: boolean | undefined;
|
|
2302
|
-
/** Path to key file for HTTPS/HTTP2 */
|
|
2303
|
-
keyFile?: string | undefined;
|
|
2304
|
-
/** Path to certificate file for HTTPS/HTTP2 */
|
|
2305
|
-
certFile?: string | undefined;
|
|
2306
|
-
};
|
|
2307
|
-
/** Global middleware to apply to all routes */
|
|
2308
|
-
middleware?: Middleware[];
|
|
2309
|
-
/** Plugins to register */
|
|
2310
|
-
plugins?: Plugin[];
|
|
2311
|
-
/**
|
|
2312
|
-
* Correlation ID configuration
|
|
2313
|
-
* @since 0.4.0
|
|
2314
|
-
*/
|
|
2315
|
-
correlation?: CorrelationOptions;
|
|
3496
|
+
declare class ConsoleTransport implements BlaizeLogTransport {
|
|
2316
3497
|
/**
|
|
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 });
|
|
3498
|
+
* Write a log entry to the console
|
|
2330
3499
|
*
|
|
2331
|
-
*
|
|
2332
|
-
*
|
|
2333
|
-
*
|
|
2334
|
-
* origin: 'https://example.com',
|
|
2335
|
-
* credentials: true,
|
|
2336
|
-
* maxAge: 86400
|
|
2337
|
-
* }
|
|
2338
|
-
* });
|
|
2339
|
-
*
|
|
2340
|
-
* // Disable CORS
|
|
2341
|
-
* const server = createServer({ cors: false });
|
|
2342
|
-
* ```
|
|
3500
|
+
* @param level - Log level
|
|
3501
|
+
* @param message - Log message
|
|
3502
|
+
* @param meta - Structured metadata
|
|
2343
3503
|
*/
|
|
2344
|
-
|
|
2345
|
-
bodyLimits?: Partial<BodyLimits>;
|
|
3504
|
+
write(level: LogLevel, message: string, meta: LogMetadata): void;
|
|
2346
3505
|
}
|
|
3506
|
+
|
|
2347
3507
|
/**
|
|
2348
|
-
*
|
|
3508
|
+
* JSON Transport for Production
|
|
3509
|
+
*
|
|
3510
|
+
* Outputs single-line JSON logs for log aggregators and monitoring systems.
|
|
3511
|
+
* Handles circular references and serializes Error objects.
|
|
3512
|
+
*
|
|
3513
|
+
* @packageDocumentation
|
|
2349
3514
|
*/
|
|
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
|
-
}
|
|
3515
|
+
|
|
2382
3516
|
/**
|
|
2383
|
-
*
|
|
3517
|
+
* JSON transport for production logging
|
|
2384
3518
|
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
3519
|
+
* Outputs single-line JSON to stdout for log aggregators (CloudWatch,
|
|
3520
|
+
* Datadog, Splunk, etc.). Handles circular references safely and
|
|
3521
|
+
* serializes Error objects with stack traces.
|
|
3522
|
+
*
|
|
3523
|
+
* Features:
|
|
3524
|
+
* - Single-line JSON output (no pretty-printing)
|
|
3525
|
+
* - Circular reference handling via replacer function
|
|
3526
|
+
* - Error objects serialized with message, name, and stack
|
|
3527
|
+
* - Stateless - safe for concurrent logging
|
|
3528
|
+
* - All metadata flattened into top-level JSON object
|
|
3529
|
+
*
|
|
3530
|
+
* @example
|
|
3531
|
+
* ```typescript
|
|
3532
|
+
* import { JSONTransport } from './transports';
|
|
3533
|
+
*
|
|
3534
|
+
* const transport = new JSONTransport();
|
|
3535
|
+
*
|
|
3536
|
+
* transport.write('info', 'User login', {
|
|
3537
|
+
* userId: '123',
|
|
3538
|
+
* method: 'oauth',
|
|
3539
|
+
* timestamp: '2025-10-20T15:30:00Z',
|
|
3540
|
+
* correlationId: 'req_abc123'
|
|
3541
|
+
* });
|
|
3542
|
+
*
|
|
3543
|
+
* // Output (single line):
|
|
3544
|
+
* // {"level":"info","message":"User login","userId":"123","method":"oauth","timestamp":"2025-10-20T15:30:00Z","correlationId":"req_abc123"}
|
|
3545
|
+
* ```
|
|
3546
|
+
*
|
|
3547
|
+
* @example With Error Object
|
|
3548
|
+
* ```typescript
|
|
3549
|
+
* const error = new Error('Database connection failed');
|
|
3550
|
+
*
|
|
3551
|
+
* transport.write('error', 'Operation failed', {
|
|
3552
|
+
* error,
|
|
3553
|
+
* retryCount: 3
|
|
3554
|
+
* });
|
|
2387
3555
|
*
|
|
3556
|
+
* // Output:
|
|
3557
|
+
* // {"level":"error","message":"Operation failed","error":{"message":"Database connection failed","name":"Error","stack":"Error: Database..."},"retryCount":3}
|
|
3558
|
+
* ```
|
|
2388
3559
|
*/
|
|
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>;
|
|
3560
|
+
declare class JSONTransport implements BlaizeLogTransport {
|
|
2413
3561
|
/**
|
|
2414
|
-
*
|
|
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}>
|
|
3562
|
+
* Write a log entry as single-line JSON to stdout
|
|
2424
3563
|
*
|
|
2425
|
-
*
|
|
2426
|
-
*
|
|
2427
|
-
*
|
|
2428
|
-
* ```
|
|
3564
|
+
* @param level - Log level
|
|
3565
|
+
* @param message - Log message
|
|
3566
|
+
* @param meta - Structured metadata
|
|
2429
3567
|
*/
|
|
2430
|
-
|
|
2431
|
-
use<MW extends readonly Middleware<any, any>[]>(middleware: MW): Server<TState & UnionToIntersection<ExtractMiddlewareState<MW[number]>>, TServices & UnionToIntersection<ExtractMiddlewareServices<MW[number]>>>;
|
|
3568
|
+
write(level: LogLevel, message: string, meta: LogMetadata): void;
|
|
2432
3569
|
/**
|
|
2433
|
-
*
|
|
3570
|
+
* Flush any buffered logs (optional)
|
|
2434
3571
|
*
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
2437
|
-
*
|
|
2438
|
-
* @example
|
|
2439
|
-
* ```typescript
|
|
2440
|
-
* // Single plugin
|
|
2441
|
-
* const serverWithDb = await server.register(databasePlugin);
|
|
2442
|
-
* // serverWithDb has type Server<{}, {db: DatabaseService}>
|
|
3572
|
+
* Currently a no-op since we write directly to stdout.
|
|
3573
|
+
* Can be implemented for batching in the future if needed.
|
|
2443
3574
|
*
|
|
2444
|
-
*
|
|
2445
|
-
* const serverWithPlugins = await server.register([dbPlugin, cachePlugin]);
|
|
2446
|
-
* // serverWithPlugins has type Server<{}, {db, cache}>
|
|
2447
|
-
* ```
|
|
3575
|
+
* @returns Promise that resolves immediately
|
|
2448
3576
|
*/
|
|
2449
|
-
|
|
2450
|
-
register<P extends readonly Plugin<any, any>[]>(plugin: P): Promise<Server<TState & UnionToIntersection<ExtractPluginState<P[number]>>, TServices & UnionToIntersection<ExtractPluginServices<P[number]>>>>;
|
|
2451
|
-
/** Access to the routing system */
|
|
2452
|
-
router: Router;
|
|
2453
|
-
/** Context storage system */
|
|
2454
|
-
context: AsyncLocalStorage<Context>;
|
|
2455
|
-
pluginManager: PluginLifecycleManager;
|
|
3577
|
+
flush(): Promise<void>;
|
|
2456
3578
|
}
|
|
2457
|
-
type RequestHandler = (req: http.IncomingMessage | http2.Http2ServerRequest, res: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
|
|
2458
3579
|
|
|
2459
3580
|
/**
|
|
2460
|
-
*
|
|
3581
|
+
* Null Transport for Testing
|
|
2461
3582
|
*
|
|
2462
|
-
*
|
|
3583
|
+
* Silent transport that discards all logs. Used in tests to suppress output.
|
|
3584
|
+
*
|
|
3585
|
+
* @packageDocumentation
|
|
2463
3586
|
*/
|
|
2464
3587
|
|
|
2465
3588
|
/**
|
|
2466
|
-
*
|
|
2467
|
-
*/
|
|
2468
|
-
interface PluginOptions<_T = any> {
|
|
2469
|
-
/** Plugin configuration */
|
|
2470
|
-
[key: string]: any;
|
|
2471
|
-
}
|
|
2472
|
-
/**
|
|
2473
|
-
* Plugin lifecycle hooks with full type safety
|
|
3589
|
+
* Null transport for testing and silent logging
|
|
2474
3590
|
*
|
|
2475
|
-
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2479
|
-
*
|
|
2480
|
-
*
|
|
3591
|
+
* Discards all log entries without producing any output. Useful for:
|
|
3592
|
+
* - Unit tests that don't care about log output
|
|
3593
|
+
* - Benchmarks where logging overhead should be minimal
|
|
3594
|
+
* - Temporarily disabling logging without changing code
|
|
3595
|
+
*
|
|
3596
|
+
* Features:
|
|
3597
|
+
* - Zero overhead - no processing or I/O
|
|
3598
|
+
* - Stateless - safe for concurrent logging
|
|
3599
|
+
* - No output to stdout, stderr, or files
|
|
3600
|
+
*
|
|
3601
|
+
* @example In Tests
|
|
3602
|
+
* ```typescript
|
|
3603
|
+
* import { NullTransport } from './transports';
|
|
3604
|
+
* import { createLogger } from './Logger';
|
|
3605
|
+
*
|
|
3606
|
+
* describe('MyService', () => {
|
|
3607
|
+
* const logger = createLogger({
|
|
3608
|
+
* transport: new NullTransport() // Suppress logs in tests
|
|
3609
|
+
* });
|
|
3610
|
+
*
|
|
3611
|
+
* test('performs operation', () => {
|
|
3612
|
+
* const service = new MyService(logger);
|
|
3613
|
+
* service.doWork(); // No log output
|
|
3614
|
+
* });
|
|
3615
|
+
* });
|
|
3616
|
+
* ```
|
|
3617
|
+
*
|
|
3618
|
+
* @example Temporary Disable
|
|
3619
|
+
* ```typescript
|
|
3620
|
+
* // Temporarily disable logging without changing business logic
|
|
3621
|
+
* const logger = createLogger({
|
|
3622
|
+
* transport: new NullTransport()
|
|
3623
|
+
* });
|
|
3624
|
+
*
|
|
3625
|
+
* logger.info('This message is discarded');
|
|
3626
|
+
* logger.error('This error is discarded');
|
|
3627
|
+
* ```
|
|
2481
3628
|
*/
|
|
2482
|
-
|
|
3629
|
+
declare class NullTransport implements BlaizeLogTransport {
|
|
2483
3630
|
/**
|
|
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
|
|
3631
|
+
* Discard a log entry (no-op)
|
|
2490
3632
|
*
|
|
2491
|
-
* @param
|
|
2492
|
-
* @
|
|
2493
|
-
*
|
|
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
|
-
* ```
|
|
3633
|
+
* @param _level - Log level (unused)
|
|
3634
|
+
* @param _message - Log message (unused)
|
|
3635
|
+
* @param _meta - Structured metadata (unused)
|
|
2503
3636
|
*/
|
|
2504
|
-
|
|
3637
|
+
write(_level: LogLevel, _message: string, _meta: LogMetadata): void;
|
|
2505
3638
|
/**
|
|
2506
|
-
*
|
|
3639
|
+
* Flush any buffered logs (no-op)
|
|
2507
3640
|
*
|
|
2508
|
-
*
|
|
2509
|
-
* - Create database connections
|
|
2510
|
-
* - Initialize services
|
|
2511
|
-
* - Allocate resources
|
|
3641
|
+
* Since no logs are written, there's nothing to flush.
|
|
2512
3642
|
*
|
|
2513
|
-
* @
|
|
2514
|
-
* ```typescript
|
|
2515
|
-
* initialize: async () => {
|
|
2516
|
-
* db = await Database.connect(config);
|
|
2517
|
-
* }
|
|
2518
|
-
* ```
|
|
3643
|
+
* @returns Promise that resolves immediately
|
|
2519
3644
|
*/
|
|
2520
|
-
|
|
3645
|
+
flush(): Promise<void>;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
/**
|
|
3649
|
+
* Core Logger Implementation
|
|
3650
|
+
*
|
|
3651
|
+
* Production-ready structured logger with level filtering, metadata redaction,
|
|
3652
|
+
* child loggers, and zero-overhead filtering for disabled log levels.
|
|
3653
|
+
*
|
|
3654
|
+
* @packageDocumentation
|
|
3655
|
+
*/
|
|
3656
|
+
|
|
3657
|
+
/**
|
|
3658
|
+
* Core Logger class implementing ILogger interface
|
|
3659
|
+
*
|
|
3660
|
+
* Thread-safe via immutable inherited metadata. Supports zero-overhead
|
|
3661
|
+
* filtering - logs below the configured level return immediately with
|
|
3662
|
+
* no processing overhead.
|
|
3663
|
+
*
|
|
3664
|
+
* @example Basic Usage
|
|
3665
|
+
* ```typescript
|
|
3666
|
+
* const logger = new Logger({
|
|
3667
|
+
* level: 'info',
|
|
3668
|
+
* transport: new ConsoleTransport(),
|
|
3669
|
+
* redactKeys: ['password', 'apiKey'],
|
|
3670
|
+
* includeTimestamp: true
|
|
3671
|
+
* });
|
|
3672
|
+
*
|
|
3673
|
+
* logger.info('User login', { userId: '123', method: 'oauth' });
|
|
3674
|
+
* ```
|
|
3675
|
+
*
|
|
3676
|
+
* @example Child Logger
|
|
3677
|
+
* ```typescript
|
|
3678
|
+
* const parentLogger = createLogger({ level: 'info' });
|
|
3679
|
+
* const childLogger = parentLogger.child({ component: 'auth' });
|
|
3680
|
+
*
|
|
3681
|
+
* childLogger.info('Token verified');
|
|
3682
|
+
* // Output includes inherited metadata: { component: 'auth', ... }
|
|
3683
|
+
* ```
|
|
3684
|
+
*/
|
|
3685
|
+
declare class Logger implements BlaizeLogger {
|
|
3686
|
+
private readonly config;
|
|
3687
|
+
private readonly inheritedMeta;
|
|
3688
|
+
private readonly minLevelPriority;
|
|
2521
3689
|
/**
|
|
2522
|
-
*
|
|
2523
|
-
*
|
|
2524
|
-
* Use this hook to:
|
|
2525
|
-
* - Start background workers
|
|
2526
|
-
* - Start cron jobs
|
|
2527
|
-
* - Begin health checks
|
|
3690
|
+
* Create a new Logger instance
|
|
2528
3691
|
*
|
|
2529
|
-
* @
|
|
2530
|
-
*
|
|
2531
|
-
* onServerStart: async () => {
|
|
2532
|
-
* worker = new BackgroundWorker();
|
|
2533
|
-
* await worker.start();
|
|
2534
|
-
* }
|
|
2535
|
-
* ```
|
|
3692
|
+
* @param config - Resolved logger configuration
|
|
3693
|
+
* @param inheritedMeta - Metadata inherited from parent logger (optional)
|
|
2536
3694
|
*/
|
|
2537
|
-
|
|
3695
|
+
constructor(config: ResolvedLoggerConfig, inheritedMeta?: LogMetadata);
|
|
2538
3696
|
/**
|
|
2539
|
-
*
|
|
2540
|
-
*
|
|
2541
|
-
* Use this hook to:
|
|
2542
|
-
* - Stop background workers
|
|
2543
|
-
* - Flush buffers
|
|
2544
|
-
* - Complete in-flight work
|
|
3697
|
+
* Log a debug message
|
|
2545
3698
|
*
|
|
2546
|
-
* @
|
|
2547
|
-
*
|
|
2548
|
-
* onServerStop: async () => {
|
|
2549
|
-
* await worker.stop({ graceful: true });
|
|
2550
|
-
* }
|
|
2551
|
-
* ```
|
|
3699
|
+
* @param message - The log message
|
|
3700
|
+
* @param meta - Optional metadata to attach
|
|
2552
3701
|
*/
|
|
2553
|
-
|
|
3702
|
+
debug(message: string, meta?: LogMetadata): void;
|
|
2554
3703
|
/**
|
|
2555
|
-
*
|
|
2556
|
-
*
|
|
2557
|
-
* Use this hook to:
|
|
2558
|
-
* - Close database connections
|
|
2559
|
-
* - Release file handles
|
|
2560
|
-
* - Free memory
|
|
3704
|
+
* Log an info message
|
|
2561
3705
|
*
|
|
2562
|
-
* @
|
|
2563
|
-
*
|
|
2564
|
-
* terminate: async () => {
|
|
2565
|
-
* await db?.close();
|
|
2566
|
-
* }
|
|
2567
|
-
* ```
|
|
3706
|
+
* @param message - The log message
|
|
3707
|
+
* @param meta - Optional metadata to attach
|
|
2568
3708
|
*/
|
|
2569
|
-
|
|
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 = {}> {
|
|
3709
|
+
info(message: string, meta?: LogMetadata): void;
|
|
2579
3710
|
/**
|
|
2580
|
-
*
|
|
2581
|
-
*
|
|
3711
|
+
* Log a warning message
|
|
3712
|
+
*
|
|
3713
|
+
* @param message - The log message
|
|
3714
|
+
* @param meta - Optional metadata to attach
|
|
2582
3715
|
*/
|
|
2583
|
-
|
|
3716
|
+
warn(message: string, meta?: LogMetadata): void;
|
|
2584
3717
|
/**
|
|
2585
|
-
*
|
|
2586
|
-
*
|
|
3718
|
+
* Log an error message
|
|
3719
|
+
*
|
|
3720
|
+
* @param message - The log message
|
|
3721
|
+
* @param meta - Optional metadata to attach
|
|
2587
3722
|
*/
|
|
2588
|
-
|
|
3723
|
+
error(message: string, meta?: LogMetadata): void;
|
|
2589
3724
|
/**
|
|
2590
|
-
*
|
|
2591
|
-
*
|
|
3725
|
+
* Create a child logger with additional metadata
|
|
3726
|
+
*
|
|
3727
|
+
* Child loggers inherit all parent metadata and add their own.
|
|
3728
|
+
* Child metadata overrides parent metadata for the same keys.
|
|
3729
|
+
*
|
|
3730
|
+
* @param meta - Additional metadata for the child logger
|
|
3731
|
+
* @returns A new logger instance with merged metadata
|
|
2592
3732
|
*
|
|
2593
3733
|
* @example
|
|
2594
3734
|
* ```typescript
|
|
2595
|
-
*
|
|
2596
|
-
*
|
|
2597
|
-
*
|
|
2598
|
-
*
|
|
3735
|
+
* const parent = createLogger({ level: 'info' });
|
|
3736
|
+
* const child = parent.child({ component: 'database' });
|
|
3737
|
+
*
|
|
3738
|
+
* child.info('Query executed');
|
|
3739
|
+
* // Output includes: { component: 'database', ...parent metadata }
|
|
2599
3740
|
* ```
|
|
2600
3741
|
*/
|
|
2601
|
-
|
|
3742
|
+
child(meta: LogMetadata): BlaizeLogger;
|
|
2602
3743
|
/**
|
|
2603
|
-
*
|
|
3744
|
+
* Flush any buffered logs and wait for completion
|
|
2604
3745
|
*
|
|
2605
|
-
*
|
|
2606
|
-
*
|
|
3746
|
+
* Delegates to the transport's flush method if it exists.
|
|
3747
|
+
* Use this during graceful shutdown to ensure all logs are written.
|
|
2607
3748
|
*
|
|
2608
|
-
* @
|
|
2609
|
-
* @returns Partial plugin hooks
|
|
3749
|
+
* @returns Promise that resolves when all logs are flushed
|
|
2610
3750
|
*
|
|
2611
3751
|
* @example
|
|
2612
3752
|
* ```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
|
-
* }
|
|
3753
|
+
* process.on('SIGTERM', async () => {
|
|
3754
|
+
* await logger.flush();
|
|
3755
|
+
* process.exit(0);
|
|
3756
|
+
* });
|
|
2625
3757
|
* ```
|
|
2626
3758
|
*/
|
|
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;
|
|
3759
|
+
flush(): Promise<void>;
|
|
2637
3760
|
/**
|
|
2638
|
-
*
|
|
3761
|
+
* Internal log method that handles all log levels
|
|
2639
3762
|
*
|
|
2640
|
-
*
|
|
2641
|
-
*
|
|
3763
|
+
* Fast-path: Returns immediately if log level is filtered.
|
|
3764
|
+
* This ensures zero overhead for disabled log levels.
|
|
2642
3765
|
*
|
|
2643
|
-
* @
|
|
3766
|
+
* @param level - The log level
|
|
3767
|
+
* @param message - The log message
|
|
3768
|
+
* @param meta - Optional metadata to attach
|
|
2644
3769
|
*/
|
|
2645
|
-
|
|
3770
|
+
private log;
|
|
2646
3771
|
/**
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
3772
|
+
* Check if a log level should be output
|
|
3773
|
+
*
|
|
3774
|
+
* @param level - The log level to check
|
|
3775
|
+
* @returns true if the level should be logged
|
|
2649
3776
|
*/
|
|
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;
|
|
3777
|
+
private shouldLog;
|
|
3778
|
+
/**
|
|
3779
|
+
* Redact sensitive keys from metadata
|
|
3780
|
+
*
|
|
3781
|
+
* Performs case-insensitive shallow redaction. Only top-level keys
|
|
3782
|
+
* are checked and redacted - nested objects are not traversed.
|
|
3783
|
+
*
|
|
3784
|
+
* Matching keys are replaced with the string '[REDACTED]'.
|
|
3785
|
+
*
|
|
3786
|
+
* @param meta - The metadata to redact
|
|
3787
|
+
* @returns New metadata object with sensitive values redacted
|
|
3788
|
+
*/
|
|
3789
|
+
private redact;
|
|
2670
3790
|
}
|
|
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
3791
|
/**
|
|
2703
|
-
*
|
|
2704
|
-
* This is the magic that allows us to compose multiple middleware contributions
|
|
3792
|
+
* Create a logger with default configuration
|
|
2705
3793
|
*
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
*
|
|
3794
|
+
* Resolves defaults based on environment:
|
|
3795
|
+
* - Development: debug level, ConsoleTransport
|
|
3796
|
+
* - Production: info level, JSONTransport
|
|
2709
3797
|
*
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
/**
|
|
2713
|
-
* Composes state contributions from an array of middleware
|
|
2714
|
-
* Merges all state types into a single intersection type
|
|
3798
|
+
* Core transports (ConsoleTransport, JSONTransport) are lazy-loaded by
|
|
3799
|
+
* the logger itself. Custom transports should be provided by application code.
|
|
2715
3800
|
*
|
|
2716
|
-
* @
|
|
2717
|
-
* @returns
|
|
3801
|
+
* @param config - Partial logger configuration (all fields optional)
|
|
3802
|
+
* @returns A new Logger instance
|
|
3803
|
+
*
|
|
3804
|
+
* @example Development Logger (Default)
|
|
3805
|
+
* ```typescript
|
|
3806
|
+
* const logger = createLogger();
|
|
3807
|
+
* // Uses: level='debug', ConsoleTransport, timestamp=true, no redaction
|
|
3808
|
+
*
|
|
3809
|
+
* logger.debug('Starting application');
|
|
3810
|
+
* ```
|
|
3811
|
+
*
|
|
3812
|
+
* @example Production Logger (Default)
|
|
3813
|
+
* ```typescript
|
|
3814
|
+
* process.env.NODE_ENV = 'production';
|
|
2718
3815
|
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
2721
|
-
*
|
|
2722
|
-
* //
|
|
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
|
|
3816
|
+
* const logger = createLogger({
|
|
3817
|
+
* redactKeys: ['password', 'apiKey', 'secret']
|
|
3818
|
+
* });
|
|
3819
|
+
* // Uses: level='info', JSONTransport, timestamp=true, redaction enabled
|
|
3820
|
+
* ```
|
|
2728
3821
|
*
|
|
2729
|
-
* @
|
|
2730
|
-
*
|
|
3822
|
+
* @example Custom Transport (Application Code)
|
|
3823
|
+
* ```typescript
|
|
3824
|
+
* import { CustomTransport } from './my-transports';
|
|
2731
3825
|
*
|
|
2732
|
-
*
|
|
2733
|
-
*
|
|
2734
|
-
*
|
|
2735
|
-
*
|
|
3826
|
+
* const logger = createLogger({
|
|
3827
|
+
* level: 'warn',
|
|
3828
|
+
* transport: new CustomTransport(), // Application provides custom transport
|
|
3829
|
+
* redactKeys: ['ssn', 'creditCard'],
|
|
3830
|
+
* includeTimestamp: false
|
|
3831
|
+
* });
|
|
3832
|
+
* ```
|
|
2736
3833
|
*/
|
|
2737
|
-
|
|
3834
|
+
declare function createLogger(config?: Partial<ResolvedLoggerConfig>): Logger;
|
|
3835
|
+
|
|
2738
3836
|
/**
|
|
2739
|
-
*
|
|
2740
|
-
* Merges all service types into a single intersection type
|
|
3837
|
+
* Global logger singleton instance
|
|
2741
3838
|
*
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
3839
|
+
* This instance is available before server creation and can be used
|
|
3840
|
+
* anywhere in your application. When the server starts, it will be
|
|
3841
|
+
* configured with the server's logging options.
|
|
2744
3842
|
*
|
|
2745
3843
|
* @example
|
|
2746
|
-
*
|
|
2747
|
-
*
|
|
2748
|
-
*
|
|
3844
|
+
* ```typescript
|
|
3845
|
+
* import { logger } from '@blaizejs/logger';
|
|
3846
|
+
*
|
|
3847
|
+
* logger.info('Application starting');
|
|
3848
|
+
* ```
|
|
2749
3849
|
*/
|
|
2750
|
-
|
|
3850
|
+
declare const logger: BlaizeLogger;
|
|
2751
3851
|
/**
|
|
2752
|
-
*
|
|
2753
|
-
* Merges all service types into a single intersection type
|
|
3852
|
+
* Configure the global logger instance
|
|
2754
3853
|
*
|
|
2755
|
-
*
|
|
2756
|
-
*
|
|
3854
|
+
* This function updates the global logger in-place so that all existing
|
|
3855
|
+
* imports automatically receive the new configuration. Called internally
|
|
3856
|
+
* by the server during creation.
|
|
3857
|
+
*
|
|
3858
|
+
* @param config - Partial logger configuration
|
|
2757
3859
|
*
|
|
2758
3860
|
* @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
|
|
3861
|
+
* ```typescript
|
|
3862
|
+
* import { configureGlobalLogger } from '@blaizejs/logger';
|
|
3863
|
+
*
|
|
3864
|
+
* configureGlobalLogger({
|
|
3865
|
+
* level: 'warn',
|
|
3866
|
+
* redactKeys: ['password', 'apiKey']
|
|
3867
|
+
* });
|
|
3868
|
+
* ```
|
|
2804
3869
|
*/
|
|
2805
|
-
|
|
3870
|
+
declare function configureGlobalLogger(config: Partial<LoggerConfig>): void;
|
|
3871
|
+
|
|
2806
3872
|
/**
|
|
2807
|
-
*
|
|
2808
|
-
* @template T - ReadonlyArray of Plugin
|
|
2809
|
-
* @returns Safely composed service types
|
|
3873
|
+
* Compose multiple middleware functions into a single middleware function
|
|
2810
3874
|
*/
|
|
2811
|
-
|
|
3875
|
+
declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
|
|
3876
|
+
|
|
2812
3877
|
/**
|
|
2813
|
-
*
|
|
2814
|
-
* Handles conflicts by using the rightmost (latest) type
|
|
3878
|
+
* Create CORS middleware with the specified options
|
|
2815
3879
|
*
|
|
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
|
|
3880
|
+
* @param userOptions - CORS configuration options or boolean
|
|
3881
|
+
* @returns Middleware function that handles CORS
|
|
2824
3882
|
*
|
|
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
|
|
3883
|
+
* @example
|
|
3884
|
+
* ```typescript
|
|
3885
|
+
* import { cors } from '@blaize-core/middleware/cors';
|
|
3886
|
+
*
|
|
3887
|
+
* // Development mode - allow all origins
|
|
3888
|
+
* server.use(cors(true));
|
|
3889
|
+
*
|
|
3890
|
+
* // Production - specific origin
|
|
3891
|
+
* server.use(cors({
|
|
3892
|
+
* origin: 'https://app.example.com',
|
|
3893
|
+
* credentials: true,
|
|
3894
|
+
* maxAge: 86400
|
|
3895
|
+
* }));
|
|
3896
|
+
*
|
|
3897
|
+
* // Multiple origins with regex
|
|
3898
|
+
* server.use(cors({
|
|
3899
|
+
* origin: [
|
|
3900
|
+
* 'https://app.example.com',
|
|
3901
|
+
* /^https:\/\/.*\.example\.com$/
|
|
3902
|
+
* ]
|
|
3903
|
+
* }));
|
|
3904
|
+
*
|
|
3905
|
+
* // Dynamic origin validation
|
|
3906
|
+
* server.use(cors({
|
|
3907
|
+
* origin: async (origin, ctx) => {
|
|
3908
|
+
* return await checkOriginAllowed(origin, ctx.state.user);
|
|
3909
|
+
* }
|
|
3910
|
+
* }));
|
|
3911
|
+
* ```
|
|
2870
3912
|
*/
|
|
2871
|
-
declare function
|
|
3913
|
+
declare function cors(userOptions?: CorsOptions | boolean): Middleware;
|
|
3914
|
+
|
|
2872
3915
|
/**
|
|
2873
|
-
*
|
|
2874
|
-
* @param value - Value to check
|
|
2875
|
-
* @returns True if value is a Plugin
|
|
3916
|
+
* Create a middleware
|
|
2876
3917
|
*/
|
|
2877
|
-
declare function
|
|
3918
|
+
declare function create$1<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
|
|
2878
3919
|
/**
|
|
2879
|
-
*
|
|
2880
|
-
*
|
|
3920
|
+
* Create a middleware that only contributes state (no services)
|
|
3921
|
+
* Convenience helper for state-only middleware
|
|
3922
|
+
*
|
|
3923
|
+
* @template T - Type of state to contribute
|
|
3924
|
+
* @param handler - Middleware function that adds state
|
|
3925
|
+
* @returns Middleware that contributes state only
|
|
2881
3926
|
*
|
|
2882
|
-
* @example
|
|
2883
|
-
* const middlewares = asMiddlewareArray([auth, logger, cache]);
|
|
2884
|
-
* type State = ComposeStates<typeof middlewares>;
|
|
2885
3927
|
*/
|
|
2886
|
-
declare function
|
|
3928
|
+
declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
|
|
2887
3929
|
/**
|
|
2888
|
-
*
|
|
2889
|
-
*
|
|
3930
|
+
* Create a middleware that only contributes services (no state)
|
|
3931
|
+
* Convenience helper for service-only middleware
|
|
3932
|
+
*
|
|
3933
|
+
* @template T - Type of services to contribute
|
|
3934
|
+
* @param handler - Middleware function that adds services
|
|
3935
|
+
* @returns Middleware that contributes services only
|
|
2890
3936
|
*
|
|
2891
|
-
* @example
|
|
2892
|
-
* const plugins = asPluginArray([dbPlugin, cachePlugin]);
|
|
2893
|
-
* type Services = ComposePluginServices<typeof plugins>;
|
|
2894
3937
|
*/
|
|
2895
|
-
declare function
|
|
3938
|
+
declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
|
|
3939
|
+
|
|
2896
3940
|
/**
|
|
2897
|
-
*
|
|
2898
|
-
* Useful for getting proper const assertions
|
|
3941
|
+
* Request Logger Middleware
|
|
2899
3942
|
*
|
|
2900
|
-
*
|
|
2901
|
-
*
|
|
2902
|
-
*
|
|
3943
|
+
* Creates a child logger with request context and optionally logs request lifecycle events.
|
|
3944
|
+
* This middleware ALWAYS runs FIRST in the middleware chain to ensure all logs have request context.
|
|
3945
|
+
*
|
|
3946
|
+
* @packageDocumentation
|
|
2903
3947
|
*/
|
|
2904
|
-
|
|
3948
|
+
|
|
2905
3949
|
/**
|
|
2906
|
-
*
|
|
2907
|
-
* Useful for getting proper const assertions
|
|
3950
|
+
* Request logger middleware factory
|
|
2908
3951
|
*
|
|
2909
|
-
*
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
3952
|
+
* Creates middleware that:
|
|
3953
|
+
* 1. ALWAYS creates a child logger with request context (correlationId, method, path, ip)
|
|
3954
|
+
* 2. Replaces ctx.services.log with the child logger
|
|
3955
|
+
* 3. Optionally logs request lifecycle events if requestLogging is true
|
|
3956
|
+
*
|
|
3957
|
+
* The child logger ensures that all logs during the request lifecycle automatically
|
|
3958
|
+
* include request context, even if requestLogging is false.
|
|
3959
|
+
*
|
|
3960
|
+
* @param options - Request logger options (headers, query, etc.)
|
|
3961
|
+
* @returns Middleware function
|
|
3962
|
+
*
|
|
3963
|
+
* @example Basic Usage (with lifecycle logging)
|
|
3964
|
+
* ```typescript
|
|
3965
|
+
* import { createServer } from 'blaizejs';
|
|
3966
|
+
* import { requestLoggerMiddleware } from './logger/middleware';
|
|
3967
|
+
*
|
|
3968
|
+
* const server = createServer({
|
|
3969
|
+
* port: 3000,
|
|
3970
|
+
* logging: {
|
|
3971
|
+
* level: 'info',
|
|
3972
|
+
* requestLogging: true, // Enable lifecycle logs
|
|
3973
|
+
* requestLoggerOptions: {
|
|
3974
|
+
* includeHeaders: true,
|
|
3975
|
+
* includeQuery: true
|
|
3976
|
+
* }
|
|
3977
|
+
* }
|
|
3978
|
+
* });
|
|
3979
|
+
* ```
|
|
3980
|
+
*
|
|
3981
|
+
* @example Without Lifecycle Logging
|
|
3982
|
+
* ```typescript
|
|
3983
|
+
* const server = createServer({
|
|
3984
|
+
* logging: {
|
|
3985
|
+
* level: 'info',
|
|
3986
|
+
* requestLogging: false // No automatic logs, but ctx.services.log still has request context
|
|
3987
|
+
* }
|
|
3988
|
+
* });
|
|
3989
|
+
*
|
|
3990
|
+
* // In route handler:
|
|
3991
|
+
* export const GET = appRoute.get({
|
|
3992
|
+
* handler: async (ctx) => {
|
|
3993
|
+
* // ctx.services.log still includes correlationId, method, path automatically
|
|
3994
|
+
* ctx.services.log.info('Custom log message');
|
|
3995
|
+
* return { data: 'response' };
|
|
3996
|
+
* }
|
|
3997
|
+
* });
|
|
3998
|
+
* ```
|
|
3999
|
+
*
|
|
4000
|
+
* @example With Header Filtering
|
|
4001
|
+
* ```typescript
|
|
4002
|
+
* const middleware = requestLoggerMiddleware({
|
|
4003
|
+
* includeHeaders: true,
|
|
4004
|
+
* headerWhitelist: ['content-type', 'user-agent', 'accept']
|
|
4005
|
+
* }, true);
|
|
4006
|
+
*
|
|
4007
|
+
* // Logs will include only whitelisted headers
|
|
4008
|
+
* // Sensitive headers (authorization, cookie) are ALWAYS redacted
|
|
4009
|
+
* ```
|
|
2912
4010
|
*/
|
|
2913
|
-
declare function
|
|
4011
|
+
declare function requestLoggerMiddleware(options?: RequestLoggerOptions): Middleware;
|
|
2914
4012
|
|
|
2915
4013
|
/**
|
|
2916
4014
|
* Create a type-safe plugin with full IntelliSense support
|
|
@@ -3582,6 +4680,7 @@ declare const MiddlewareAPI: {
|
|
|
3582
4680
|
createStateMiddleware: typeof stateMiddleware;
|
|
3583
4681
|
compose: typeof compose;
|
|
3584
4682
|
cors: typeof cors;
|
|
4683
|
+
requestLoggerMiddleware: typeof requestLoggerMiddleware;
|
|
3585
4684
|
};
|
|
3586
4685
|
declare const PluginsAPI: {
|
|
3587
4686
|
createPlugin: typeof createPlugin;
|
|
@@ -3594,6 +4693,9 @@ declare const Blaize: {
|
|
|
3594
4693
|
createStateMiddleware: typeof stateMiddleware;
|
|
3595
4694
|
createPlugin: typeof createPlugin;
|
|
3596
4695
|
getCorrelationId: typeof getCorrelationId;
|
|
4696
|
+
configureGlobalLogger: typeof configureGlobalLogger;
|
|
4697
|
+
createLogger: typeof createLogger;
|
|
4698
|
+
logger: BlaizeLogger;
|
|
3597
4699
|
Server: {
|
|
3598
4700
|
createServer: typeof create;
|
|
3599
4701
|
inferContext: typeof inferContext;
|
|
@@ -3619,6 +4721,7 @@ declare const Blaize: {
|
|
|
3619
4721
|
createStateMiddleware: typeof stateMiddleware;
|
|
3620
4722
|
compose: typeof compose;
|
|
3621
4723
|
cors: typeof cors;
|
|
4724
|
+
requestLoggerMiddleware: typeof requestLoggerMiddleware;
|
|
3622
4725
|
};
|
|
3623
4726
|
Plugins: {
|
|
3624
4727
|
createPlugin: typeof createPlugin;
|
|
@@ -3626,4 +4729,4 @@ declare const Blaize: {
|
|
|
3626
4729
|
VERSION: string;
|
|
3627
4730
|
};
|
|
3628
4731
|
|
|
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 };
|
|
4732
|
+
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 };
|