blaizejs 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/{chunk-4QEX5ARZ.js → chunk-BOFAGA5B.js} +3 -3
  2. package/dist/chunk-JMYOXYX4.js +11 -0
  3. package/dist/{chunk-DN5WHXRA.js.map → chunk-JMYOXYX4.js.map} +1 -1
  4. package/dist/{chunk-RUCGYLJ6.js → chunk-NXPSLUP5.js} +3 -3
  5. package/dist/{chunk-EB3TZGU4.js → chunk-VVEKNV22.js} +3 -3
  6. package/dist/{chunk-QYXAQD7H.js → chunk-ZBJU7ZOM.js} +3 -3
  7. package/dist/index.cjs +14 -14
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +1411 -1437
  10. package/dist/index.d.ts +1411 -1437
  11. package/dist/index.js +14 -14
  12. package/dist/index.js.map +1 -1
  13. package/dist/{internal-server-error-I43ZDXIR.js → internal-server-error-MIWZOL6G.js} +3 -3
  14. package/dist/{payload-too-large-error-OQEOP3U2.js → payload-too-large-error-INCZ2WM7.js} +3 -3
  15. package/dist/{unsupported-media-type-error-7UF4VYIN.js → unsupported-media-type-error-BVGBPGOM.js} +3 -3
  16. package/dist/{validation-error-ZPBPCFKL.js → validation-error-BQK2BTX6.js} +3 -3
  17. package/package.json +1 -1
  18. package/dist/chunk-DN5WHXRA.js +0 -11
  19. /package/dist/{chunk-4QEX5ARZ.js.map → chunk-BOFAGA5B.js.map} +0 -0
  20. /package/dist/{chunk-RUCGYLJ6.js.map → chunk-NXPSLUP5.js.map} +0 -0
  21. /package/dist/{chunk-EB3TZGU4.js.map → chunk-VVEKNV22.js.map} +0 -0
  22. /package/dist/{chunk-QYXAQD7H.js.map → chunk-ZBJU7ZOM.js.map} +0 -0
  23. /package/dist/{internal-server-error-I43ZDXIR.js.map → internal-server-error-MIWZOL6G.js.map} +0 -0
  24. /package/dist/{payload-too-large-error-OQEOP3U2.js.map → payload-too-large-error-INCZ2WM7.js.map} +0 -0
  25. /package/dist/{unsupported-media-type-error-7UF4VYIN.js.map → unsupported-media-type-error-BVGBPGOM.js.map} +0 -0
  26. /package/dist/{validation-error-ZPBPCFKL.js.map → validation-error-BQK2BTX6.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -8,1697 +8,1671 @@ import { AsyncLocalStorage } from 'node:async_hooks';
8
8
  import { EventEmitter } from 'node:events';
9
9
 
10
10
  /**
11
- * Error type definitions and interfaces for the BlaizeJS framework
12
- *
13
- * This module contains all the type definitions used for error handling
14
- * across the BlaizeJS framework, including server-side errors, client-side
15
- * errors, and HTTP response formats.
11
+ * Represents an uploaded file in a multipart/form-data request
16
12
  */
13
+ interface UploadedFile {
14
+ /** Original filename provided by the client (may be undefined) */
15
+ readonly filename: string | undefined;
16
+ /** Form field name this file was uploaded under */
17
+ readonly fieldname: string;
18
+ /** MIME type of the uploaded file */
19
+ readonly mimetype: string;
20
+ /** Size of the file in bytes */
21
+ readonly size: number;
22
+ /** Stream containing the file data (always available) */
23
+ readonly stream: Readable;
24
+ /** Buffer containing file data (only available with 'memory' strategy) */
25
+ readonly buffer?: Buffer;
26
+ /** Path to temporary file (only available with 'temp' strategy) */
27
+ readonly tempPath?: string;
28
+ /** SHA-256 hash of file content (if computed) */
29
+ readonly hash?: string;
30
+ }
17
31
  /**
18
- * Structure of error responses sent over HTTP
19
- *
20
- * This interface defines the JSON format used for all error responses
21
- * from BlaizeJS servers. It matches the structure returned by BlaizeError.toJSON()
22
- *
23
- * @example
24
- * ```json
25
- * {
26
- * "type": "VALIDATION_ERROR",
27
- * "title": "Request validation failed",
28
- * "status": 400,
29
- * "correlationId": "req_abc123",
30
- * "timestamp": "2024-01-15T10:30:00.000Z",
31
- * "details": {
32
- * "fields": ["email", "password"]
33
- * }
34
- * }
35
- * ```
32
+ * Complete multipart/form-data parsed content
36
33
  */
37
- interface BlaizeErrorResponse {
38
- /** Error type from the ErrorType enum */
39
- type: ErrorType;
40
- /** Human-readable error message */
41
- title: string;
42
- /** HTTP status code */
43
- status: number;
44
- /** Correlation ID for request tracing */
45
- correlationId: string;
46
- /** ISO timestamp when error occurred */
47
- timestamp: string;
48
- /** Optional error-specific details */
49
- details?: unknown;
34
+ interface MultipartData {
35
+ /** Form fields (non-file inputs) */
36
+ readonly fields: Record<string, string | string[]>;
37
+ /** Uploaded files */
38
+ readonly files: Record<string, UploadedFile | UploadedFile[]>;
50
39
  }
51
40
  /**
52
- * Context information for network-related errors
53
- *
54
- * Used by client-side error classes to provide additional context
55
- * about network failures, timeouts, and connection issues.
41
+ * Options for parsing multipart/form-data
56
42
  */
57
- interface NetworkErrorContext {
58
- /** The URL that failed */
59
- url: string;
60
- /** HTTP method being attempted */
61
- method: string;
62
- /** Correlation ID for tracing */
63
- correlationId: string;
64
- /** Timeout value if applicable */
65
- timeout?: number;
66
- /** The original error that caused the network failure */
67
- originalError: Error;
68
- /** Additional network-specific details */
69
- networkDetails?: {
70
- /** Whether this was a connection timeout */
71
- isTimeout?: boolean;
72
- /** Whether this was a DNS resolution failure */
73
- isDnsFailure?: boolean;
74
- /** Whether this was a connection refused error */
75
- isConnectionRefused?: boolean;
76
- /** HTTP status code if received before failure */
77
- statusCode?: number;
78
- };
43
+ interface ParseOptions {
44
+ /** Maximum size for individual files in bytes (default: 10MB) */
45
+ readonly maxFileSize?: number;
46
+ /** Maximum number of files per request (default: 10) */
47
+ readonly maxFiles?: number;
48
+ /** Maximum size for form fields in bytes (default: 1MB) */
49
+ readonly maxFieldSize?: number;
50
+ /** Allowed MIME types (empty array = allow all) */
51
+ readonly allowedMimeTypes?: readonly string[];
52
+ /** Allowed file extensions (empty array = allow all) */
53
+ readonly allowedExtensions?: readonly string[];
54
+ /** Processing strategy for file data */
55
+ readonly strategy: 'memory' | 'stream' | 'temp';
56
+ /** Directory for temporary files (strategy: 'temp' only) */
57
+ readonly tempDir?: string;
58
+ /** Whether to compute SHA-256 hash of files */
59
+ readonly computeHash?: boolean;
79
60
  }
80
61
  /**
81
- * Context information for request timeout errors
82
- *
83
- * Specialized context for timeout-specific errors with timing information.
62
+ * Result of parsing multipart data with metadata
84
63
  */
85
- interface TimeoutErrorContext {
86
- /** The URL that timed out */
87
- url: string;
88
- /** HTTP method being attempted */
89
- method: string;
90
- /** Correlation ID for tracing */
91
- correlationId: string;
92
- /** Configured timeout value in milliseconds */
93
- timeoutMs: number;
94
- /** Actual duration before timeout in milliseconds */
95
- elapsedMs: number;
96
- /** Type of timeout (request, connection, etc.) */
97
- timeoutType: 'request' | 'connection' | 'response' | 'idle';
64
+ interface ParseResult {
65
+ /** Parsed multipart data */
66
+ readonly data: MultipartData;
67
+ /** Parsing metadata */
68
+ readonly metadata: {
69
+ /** Total time spent parsing (milliseconds) */
70
+ readonly parseTime: number;
71
+ /** Total size of all uploaded content */
72
+ readonly totalSize: number;
73
+ /** Number of files processed */
74
+ readonly fileCount: number;
75
+ /** Number of fields processed */
76
+ readonly fieldCount: number;
77
+ };
98
78
  }
99
79
  /**
100
- * Context information for response parsing errors
101
- *
102
- * Used when the client receives a response but cannot parse it properly.
80
+ * Error information for multipart parsing failures
103
81
  */
104
- interface ParseErrorContext {
105
- /** The URL that returned unparseable content */
106
- url: string;
107
- /** HTTP method used */
108
- method: string;
109
- /** Correlation ID for tracing */
110
- correlationId: string;
111
- /** HTTP status code received */
112
- statusCode: number;
113
- /** Content-Type header if available */
114
- contentType?: string;
115
- /** Expected response format */
116
- expectedFormat: 'json' | 'text' | 'binary';
117
- /** Sample of the actual response content (truncated for safety) */
118
- responseSample?: string;
119
- /** The original parsing error */
120
- originalError: Error;
82
+ interface MultipartError {
83
+ /** Error type/code */
84
+ readonly type: 'boundary_missing' | 'size_exceeded' | 'file_limit_exceeded' | 'mime_type_forbidden' | 'extension_forbidden' | 'parse_error' | 'stream_error' | 'temp_file_error';
85
+ /** Human-readable error message */
86
+ readonly message: string;
87
+ /** Additional context (field name, file name, etc.) */
88
+ readonly context?: Record<string, unknown>;
89
+ /** Original error if available */
90
+ readonly cause?: Error;
121
91
  }
122
92
  /**
123
- * Validation error field details
124
- *
125
- * Structure for field-level validation errors with multiple error messages
126
- * per field.
93
+ * Configuration for file upload validation
127
94
  */
128
- interface ValidationFieldError {
129
- /** Field name or path (e.g., "email", "user.profile.name") */
130
- field: string;
131
- /** Array of error messages for this field */
132
- messages: string[];
133
- /** The invalid value that caused the error */
134
- rejectedValue?: unknown;
135
- /** Expected type or format */
136
- expectedType?: string;
137
- }
138
- interface ServiceNotAvailableDetails {
139
- /** Service that's unavailable */
140
- service?: string;
141
- /** Seconds to wait before retry */
142
- retryAfter?: number;
143
- /** Why service is unavailable */
144
- reason?: 'maintenance' | 'overload' | 'circuit_breaker' | 'dependency_down';
145
- /** Additional context */
146
- [key: string]: unknown;
95
+ interface ValidationConfig {
96
+ /** File size constraints */
97
+ readonly size?: {
98
+ readonly min?: number;
99
+ readonly max?: number;
100
+ };
101
+ /** File count constraints */
102
+ readonly count?: {
103
+ readonly min?: number;
104
+ readonly max?: number;
105
+ };
106
+ /** MIME type constraints */
107
+ readonly mimeTypes?: {
108
+ readonly allowed?: readonly string[];
109
+ readonly forbidden?: readonly string[];
110
+ };
111
+ /** File extension constraints */
112
+ readonly extensions?: {
113
+ readonly allowed?: readonly string[];
114
+ readonly forbidden?: readonly string[];
115
+ };
116
+ /** Custom validation function */
117
+ readonly custom?: (file: UploadedFile) => Promise<boolean> | boolean;
147
118
  }
148
119
  /**
149
- * Validation error details structure
150
- *
151
- * Used by ValidationError to provide structured information about
152
- * what fields failed validation and why.
120
+ * File processing configuration
153
121
  */
154
- interface ValidationErrorDetails {
155
- /** Array of field-level errors */
156
- fields: ValidationFieldError[];
157
- /** Total number of validation errors */
158
- errorCount: number;
159
- /** The section that failed validation */
160
- section: 'params' | 'query' | 'body' | 'response';
161
- /** Schema name if available */
162
- schemaName?: string;
122
+ interface ProcessingConfig {
123
+ /** Whether to process files concurrently */
124
+ readonly concurrent?: boolean;
125
+ /** Maximum concurrent processing operations */
126
+ readonly maxConcurrency?: number;
127
+ /** Processing timeout in milliseconds */
128
+ readonly timeout?: number;
129
+ /** Whether to preserve original files during processing */
130
+ readonly preserveOriginal?: boolean;
163
131
  }
164
132
  /**
165
- * All available error types in the BlaizeJS framework
166
- *
167
- * This enum provides both compile-time type safety and runtime values
168
- * for error type identification across server and client packages.
169
- *
170
- * @example Type-safe error handling:
171
- * ```typescript
172
- * function handleError(errorType: ErrorType) {
173
- * switch (errorType) {
174
- * case ErrorType.VALIDATION_ERROR:
175
- * // Handle validation error
176
- * break;
177
- * case ErrorType.NOT_FOUND:
178
- * // Handle not found error
179
- * break;
180
- * // TypeScript ensures all cases are covered
181
- * }
182
- * }
183
- * ```
133
+ * Upload progress information (for future streaming uploads)
184
134
  */
185
- declare enum ErrorType {
186
- /** Request validation failed (400) */
187
- VALIDATION_ERROR = "VALIDATION_ERROR",
188
- /** Resource not found (404) */
189
- NOT_FOUND = "NOT_FOUND",
190
- /** Authentication required (401) */
191
- UNAUTHORIZED = "UNAUTHORIZED",
192
- /** Access forbidden (403) */
193
- FORBIDDEN = "FORBIDDEN",
194
- /** SSE Not Acceptable (406) */
195
- SSE_NOT_ACCEPTABLE = "SSE_NOT_ACCEPTABLE",
196
- /** Resource conflict (409) */
197
- CONFLICT = "CONFLICT",
198
- /** Rate limit exceeded (429) */
199
- RATE_LIMITED = "RATE_LIMITED",
200
- /** Internal server error (500) */
201
- INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR",
202
- /** File/Request Too Large (413) */
203
- PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
204
- /** Wrong Content Type (415) */
205
- UNSUPPORTED_MEDIA_TYPE = "UNSUPPORTED_MEDIA_TYPE",
206
- /** Upload Timeout (408) */
207
- UPLOAD_TIMEOUT = "UPLOAD_TIMEOUT",
208
- /** Valid Format Invalid Semantics (422) */
209
- UNPROCESSABLE_ENTITY = "UNPROCESSABLE_ENTITY",
210
- /** Network connectivity failure (0) */
211
- NETWORK_ERROR = "NETWORK_ERROR",
212
- /** Request or response timeout (0) */
213
- TIMEOUT_ERROR = "TIMEOUT_ERROR",
214
- /** Response parsing failure (0) */
215
- PARSE_ERROR = "PARSE_ERROR",
216
- /** Generic HTTP error (varies) */
217
- HTTP_ERROR = "HTTP_ERROR",
218
- /** SSE connection failed (502) */
219
- SSE_CONNECTION_ERROR = "SSE_CONNECTION_ERROR",
220
- /** SSE buffer overflow (503) */
221
- SSE_BUFFER_OVERFLOW = "SSE_BUFFER_OVERFLOW",
222
- /** SSE stream closed (410) */
223
- SSE_STREAM_CLOSED = "SSE_STREAM_CLOSED",
224
- /** Service temporarily unavailable (503) */
225
- SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"
226
- }
227
- /**
228
- * Error severity levels for logging and monitoring
229
- *
230
- * Provides a way to categorize errors by their impact and urgency.
231
- */
232
- declare enum ErrorSeverity {
233
- /** Low impact, often user errors */
234
- LOW = "low",
235
- /** Medium impact, application errors */
236
- MEDIUM = "medium",
237
- /** High impact, system errors */
238
- HIGH = "high",
239
- /** Critical impact, service disruption */
240
- CRITICAL = "critical"
135
+ interface UploadProgress {
136
+ /** Bytes uploaded so far */
137
+ readonly bytesUploaded: number;
138
+ /** Total bytes to upload */
139
+ readonly totalBytes: number;
140
+ /** Upload percentage (0-100) */
141
+ readonly percentage: number;
142
+ /** Upload speed in bytes per second */
143
+ readonly speed: number;
144
+ /** Estimated time remaining in milliseconds */
145
+ readonly eta: number;
241
146
  }
242
147
  /**
243
- * Abstract base class for all BlaizeJS errors
244
- *
245
- * This class provides the foundation for all error types in the BlaizeJS framework.
246
- * It extends JavaScript's built-in Error class and adds framework-specific properties
247
- * for consistent error handling across server and client.
248
- *
249
- * @example
250
- * ```typescript
251
- * import { ErrorType } from './types';
252
- *
253
- * class NotFoundError extends BlaizeError<{ resourceId: string }> {
254
- * constructor(message = 'Resource not found', details?: { resourceId: string }) {
255
- * super(ErrorType.NOT_FOUND, message, 404, getCurrentCorrelationId(), details);
256
- * }
257
- * }
258
- * ```
259
- *
260
- * @template TDetails - Type for error-specific details object
148
+ * Internal state for multipart parser state machine
261
149
  */
262
- declare abstract class BlaizeError<TDetails = unknown> extends Error {
263
- /**
264
- * Error type identifier from the ErrorType enum
265
- * Used for programmatic error handling and client-side error routing
266
- */
267
- readonly type: ErrorType;
268
- /**
269
- * Human-readable error title/message
270
- * Should be descriptive enough for debugging but safe for end users
271
- */
272
- readonly title: string;
273
- /**
274
- * HTTP status code associated with this error
275
- * Used by the error boundary to set appropriate response status
276
- */
277
- readonly status: number;
278
- /**
279
- * Correlation ID for request tracing
280
- * Links this error to the specific request that generated it
281
- */
282
- readonly correlationId: string;
283
- /**
284
- * Timestamp when the error occurred
285
- * Useful for debugging and log correlation
286
- */
287
- readonly timestamp: Date;
288
- /**
289
- * Additional error-specific details
290
- * Type-safe error context that varies by error type
291
- */
292
- readonly details?: TDetails | undefined;
150
+ interface ParserState {
151
+ boundary: Buffer;
152
+ options: Required<ParseOptions>;
153
+ fields: Map<string, string[]>;
154
+ files: Map<string, UploadedFile[]>;
155
+ buffer: Buffer;
156
+ stage: 'boundary' | 'headers' | 'content';
157
+ currentHeaders: string;
158
+ currentField: string | null;
159
+ currentFilename: string | undefined;
160
+ currentMimetype: string;
161
+ currentContentLength: number;
162
+ fileCount: number;
163
+ fieldCount: number;
164
+ currentBufferChunks: Buffer[];
165
+ currentStream: Readable | null;
166
+ currentTempPath: string | null;
167
+ currentWriteStream: WriteStream | null;
168
+ streamController: ReadableStreamDefaultController<Uint8Array> | null;
169
+ cleanupTasks: Array<() => Promise<void>>;
293
170
  /**
294
- * Creates a new BlaizeError instance
295
- *
296
- * @param type - Error type from the ErrorType enum
297
- * @param title - Human-readable error message
298
- * @param status - HTTP status code
299
- * @param correlationId - Request correlation ID for tracing
300
- * @param details - Optional error-specific details
171
+ * Whether we've found at least one valid boundary marker
301
172
  */
302
- protected constructor(type: ErrorType, title: string, status: number, correlationId: string, details?: TDetails | undefined);
173
+ hasFoundValidBoundary: boolean;
303
174
  /**
304
- * Serializes the error to a plain object suitable for HTTP responses
305
- *
306
- * @returns Object representation of the error
175
+ * Whether we've successfully processed at least one complete part (field or file)
307
176
  */
308
- toJSON(): {
309
- type: ErrorType;
310
- title: string;
311
- status: number;
312
- correlationId: string;
313
- timestamp: string;
314
- } | {
315
- details: TDetails & ({} | null);
316
- type: ErrorType;
317
- title: string;
318
- status: number;
319
- correlationId: string;
320
- timestamp: string;
321
- };
177
+ hasProcessedAnyPart: boolean;
322
178
  /**
323
- * Returns a string representation of the error
324
- * Includes correlation ID for easier debugging
179
+ * Whether parsing has reached the end boundary
325
180
  */
326
- toString(): string;
181
+ isFinished: boolean;
327
182
  }
183
+
328
184
  /**
329
- * Interface for payload too large error details
185
+ * Unified request type supporting both HTTP/1.1 and HTTP/2
330
186
  */
331
- interface PayloadTooLargeErrorDetails {
332
- fileCount?: number;
333
- maxFiles?: number;
334
- filename?: string;
335
- field?: string;
336
- contentType?: string;
337
- currentSize?: number;
338
- maxSize?: number;
339
- }
187
+ type UnifiedRequest = IncomingMessage | Http2ServerRequest;
340
188
  /**
341
- * Interface for unsupported media type error details
189
+ * Unified response type supporting both HTTP/1.1 and HTTP/2
342
190
  */
343
- interface UnsupportedMediaTypeErrorDetails {
344
- receivedMimeType?: string;
345
- allowedMimeTypes?: string[];
346
- filename?: string;
191
+ type UnifiedResponse = ServerResponse | Http2ServerResponse;
192
+ /**
193
+ * Request parameters extracted from URL path
194
+ */
195
+ interface RequestParams {
196
+ [key: string]: string;
347
197
  }
348
198
  /**
349
- * Interface for authentication error details
199
+ * Query parameters from URL
350
200
  */
351
- interface UnauthorizedErrorDetails {
352
- /** Reason for authentication failure */
353
- reason?: 'missing_token' | 'invalid_token' | 'expired_token' | 'malformed_token' | 'insufficient_scope' | string;
354
- /** Authentication scheme (Bearer, Basic, etc.) */
355
- authScheme?: string;
356
- /** Authentication realm */
357
- realm?: string;
358
- /** Detailed error description */
359
- error_description?: string;
360
- /** Required scopes or permissions */
361
- requiredScopes?: string[];
362
- /** Login URL for interactive authentication */
363
- loginUrl?: string;
364
- /** Additional context */
365
- [key: string]: unknown;
201
+ interface QueryParams {
202
+ [key: string]: string | string[] | undefined;
366
203
  }
367
204
  /**
368
- * Interface for authorization/permission error details
205
+ * Options for streaming responses
369
206
  */
370
- interface ForbiddenErrorDetails {
371
- /** Required permission or role */
372
- requiredPermission?: string;
373
- /** User's current permissions */
374
- userPermissions?: string[];
375
- /** Resource being accessed */
376
- resource?: string;
377
- /** Action being attempted */
378
- action?: string;
379
- /** Reason for access denial */
380
- reason?: 'insufficient_permissions' | 'account_suspended' | 'resource_locked' | 'origin_not_allowed' | string;
381
- /** Additional context */
382
- [key: string]: unknown;
207
+ interface StreamOptions {
208
+ contentType?: string;
209
+ status?: number;
210
+ headers?: Record<string, string>;
383
211
  }
384
212
  /**
385
- * Interface for resource conflict error details
213
+ * State container for storing request-scoped data
214
+ * Allows for proper typing with generics
386
215
  */
387
- interface ConflictErrorDetails {
388
- /** Type of conflict */
389
- conflictType?: 'duplicate_key' | 'version_mismatch' | 'concurrent_modification' | 'business_rule' | string;
390
- /** Field that caused the conflict */
391
- field?: string;
392
- /** Existing value that conflicts */
393
- existingValue?: unknown;
394
- /** Provided value that conflicts */
395
- providedValue?: unknown;
396
- /** Resource that has the conflicting value */
397
- conflictingResource?: string;
398
- /** Current version/etag of the resource */
399
- currentVersion?: string;
400
- /** Expected version/etag */
401
- expectedVersion?: string;
402
- /** Suggested resolution */
403
- resolution?: string;
404
- /** Additional context */
216
+ interface State {
405
217
  [key: string]: unknown;
406
218
  }
407
219
  /**
408
- * Interface for rate limiting error details
220
+ * Services container for storing injectable services/dependencies
221
+ * Allows middleware to contribute services that are accessible throughout the request lifecycle
409
222
  */
410
- interface RateLimitErrorDetails {
411
- /** Maximum requests allowed in the time window */
412
- limit?: number;
413
- /** Remaining requests in current window */
414
- remaining?: number;
415
- /** When the rate limit resets */
416
- resetTime?: Date;
417
- /** Seconds until the rate limit resets */
418
- retryAfter?: number;
419
- /** Time window for the rate limit */
420
- window?: string;
421
- /** Identifier used for rate limiting (IP, user ID, etc.) */
422
- identifier?: string;
423
- /** Type of rate limit hit */
424
- limitType?: 'global' | 'per_user' | 'per_ip' | 'per_endpoint' | string;
425
- /** Additional context */
223
+ interface Services {
426
224
  [key: string]: unknown;
427
225
  }
428
- /**
429
- * Interface for internal server error details
430
- */
431
- interface InternalServerErrorDetails {
432
- /** Original error message (for debugging) */
433
- originalError?: string;
434
- /** Stack trace (for debugging) */
435
- stackTrace?: string;
436
- /** Component where the error occurred */
437
- component?: string;
438
- /** Operation being performed */
439
- operation?: string;
440
- /** Internal error code */
441
- internalErrorCode?: string;
442
- /** When the error occurred */
443
- timestamp?: Date;
444
- /** Whether this error should be retryable */
445
- retryable?: boolean;
446
- /** Additional debugging context */
447
- [key: string]: unknown;
226
+ interface ContextResponse<S extends State = State> {
227
+ raw: UnifiedResponse;
228
+ sent: boolean;
229
+ statusCode: number;
230
+ status: (code: number) => ContextResponse<S>;
231
+ header: (name: string, value: string) => ContextResponse<S>;
232
+ headers: (headers: Record<string, string>) => ContextResponse<S>;
233
+ type: (contentType: string) => ContextResponse<S>;
234
+ json: (body: unknown, status?: number) => void;
235
+ text: (body: string, status?: number) => void;
236
+ html: (body: string, status?: number) => void;
237
+ redirect: (url: string, status?: number) => void;
238
+ stream: (readable: NodeJS.ReadableStream, options?: StreamOptions) => void;
239
+ }
240
+ interface ContextRequest<TBody = unknown> {
241
+ raw: UnifiedRequest;
242
+ method: string;
243
+ path: string;
244
+ url: URL | null;
245
+ query: QueryParams;
246
+ params: RequestParams;
247
+ protocol: string;
248
+ isHttp2: boolean;
249
+ body?: TBody;
250
+ /**
251
+ * Uploaded files from multipart/form-data requests
252
+ * Available when Content-Type is multipart/form-data
253
+ */
254
+ files?: Record<string, UploadedFile | UploadedFile[]>;
255
+ /**
256
+ * Complete multipart data (files + fields)
257
+ * Available when Content-Type is multipart/form-data
258
+ */
259
+ multipart?: MultipartData;
260
+ header: (name: string) => string | undefined;
261
+ headers: (names?: string[]) => Record<string, string | undefined>;
448
262
  }
449
263
  /**
450
- * Interface for NotFound error details
451
- * Provides context about the missing resource
264
+ * Context object representing a request/response cycle
265
+ * @template S - Type of the state object
266
+ * @template Svc - Type of the services object
267
+ * @template TBody - Type of the request body
268
+ * @template TQuery - Type of the query parameters
452
269
  */
453
- interface NotFoundErrorDetails {
454
- /** Type of resource that was not found */
455
- resourceType?: string;
456
- /** ID or identifier of the resource */
457
- resourceId?: string;
458
- /** Collection or table where the resource was searched */
459
- collection?: string;
460
- /** Search criteria that was used */
461
- query?: Record<string, unknown>;
462
- /** Search criteria that was used (for backward compatibility) */
463
- searchCriteria?: Record<string, unknown>;
464
- /** The path that was attempted */
465
- path?: string;
466
- /** HTTP method used (for API endpoints) */
467
- method?: string;
468
- /** The path that was attempted (for backward compatibility) */
469
- attemptedPath?: string;
470
- /** Parent resource information for nested resources */
471
- parentResource?: {
472
- type: string;
473
- id: string;
270
+ interface Context<S extends State = State, Svc extends Services = Services, TBody = unknown, TQuery = QueryParams> {
271
+ /**
272
+ * Request information
273
+ */
274
+ request: Omit<ContextRequest, 'body' | 'query'> & {
275
+ body: TBody;
276
+ query: TQuery;
474
277
  };
475
- /** Helpful suggestion for the user */
476
- suggestion?: string;
477
- /** Additional context */
478
- [key: string]: unknown;
278
+ /**
279
+ * Response handling
280
+ */
281
+ response: ContextResponse<S>;
282
+ /**
283
+ * Request-scoped state for storing data during the request lifecycle
284
+ */
285
+ state: S;
286
+ /**
287
+ * Services container for accessing injected services/dependencies
288
+ * Populated by middleware that contribute services
289
+ */
290
+ services: Svc;
479
291
  }
292
+ interface BodyLimits {
293
+ /** Maximum JSON body size in bytes (default: 512KB) */
294
+ json: number;
295
+ /** Maximum form data size in bytes (default: 1MB) */
296
+ form: number;
297
+ /** Maximum text body size in bytes (default: 5MB) */
298
+ text: number;
299
+ /** Maximum raw/binary body size in bytes (default: 10MB) */
300
+ raw: number;
301
+ /** Multipart/form-data limits */
302
+ multipart: MultipartLimits;
303
+ }
304
+ type MultipartLimits = {
305
+ maxFileSize?: number;
306
+ maxTotalSize?: number;
307
+ maxFiles?: number;
308
+ maxFieldSize?: number;
309
+ };
480
310
  /**
481
- * Interface for body parsing errors stored in context state
311
+ * Options for creating a context
482
312
  */
483
- interface BodyParseError {
313
+ interface ContextOptions {
314
+ /**
315
+ * Whether to parse the request body
316
+ */
317
+ parseBody?: boolean;
484
318
  /**
485
- * Type of parsing error that occurred
319
+ * Initial state to include in the context
320
+ *
486
321
  */
487
- readonly type: 'json_parse_error' | 'form_parse_error' | 'multipart_parse_error' | 'body_read_error';
322
+ initialState?: State;
488
323
  /**
489
- * Human-readable error message
324
+ * Initial services to include in the context
325
+ *
490
326
  */
491
- readonly message: string;
327
+ initialServices?: Services;
492
328
  /**
493
- * Original error object or details
329
+ * Limits for various body types to prevent abuse
494
330
  */
495
- readonly error: unknown;
331
+ bodyLimits: BodyLimits;
496
332
  }
497
333
  /**
498
- * Type guard to check if an object is a BodyParseError
334
+ * Function to get the current context from AsyncLocalStorage
499
335
  */
500
- declare function isBodyParseError(error: unknown): error is BodyParseError;
336
+ type GetContextFn = <S extends State = State, Svc extends Services = Services>() => Context<S, Svc> | undefined;
501
337
  /**
502
- * Context information for error transformation
338
+ * Factory function for creating a new context
503
339
  */
504
- interface ErrorTransformContext {
505
- url: string;
506
- method: string;
507
- correlationId: string;
508
- timeoutMs?: number;
509
- elapsedMs?: number;
510
- statusCode?: number;
511
- contentType?: string;
512
- responseSample?: string;
513
- [key: string]: unknown;
514
- }
340
+ type CreateContextFn = (req: UnifiedRequest, res: UnifiedResponse, options?: ContextOptions) => Promise<Context>;
515
341
  /**
516
- * SSE-specific error detail interfaces for BlaizeJS framework
342
+ * Type representing unknown function
517
343
  *
518
- * These interfaces define the structure of details for SSE errors.
519
- * The actual error classes are implemented in blaize-core.
344
+ * This is a generic function type that can accept any number of arguments
345
+ * and return any type of value. It is used for type inference in various
346
+ * contexts where the specific function signature is not known or not
347
+ * important.
520
348
  */
349
+ type UnknownFunction = (...args: unknown[]) => unknown;
350
+
521
351
  /**
522
- * Details for SSE connection errors
352
+ * Function to pass control to the next middleware
523
353
  */
524
- interface SSEConnectionErrorDetails {
525
- /** Client identifier if available */
526
- clientId?: string;
527
- /** Connection attempt number */
528
- attemptNumber?: number;
529
- /** Maximum retry attempts configured */
530
- maxRetries?: number;
531
- /** The underlying error that caused connection failure */
532
- cause?: string;
533
- /** Suggested resolution */
534
- suggestion?: string;
535
- }
354
+ type NextFunction = () => Promise<void> | void;
536
355
  /**
537
- * Details for SSE buffer overflow errors
356
+ * Middleware function signature
538
357
  */
539
- interface SSEBufferOverflowErrorDetails {
540
- /** Client identifier */
541
- clientId?: string;
542
- /** Current buffer size when overflow occurred */
543
- currentSize: number;
544
- /** Maximum buffer size configured */
545
- maxSize: number;
546
- /** Number of events dropped */
547
- eventsDropped?: number;
548
- /** Buffer strategy that was applied */
549
- strategy: 'drop-oldest' | 'drop-newest' | 'close';
550
- /** Event that triggered the overflow */
551
- triggeringEvent?: string;
358
+ type MiddlewareFunction = (ctx: Context, next: NextFunction) => Promise<void> | void;
359
+ /**
360
+ * Named middleware options
361
+ */
362
+ interface MiddlewareOptions {
363
+ /** Name of the middleware for debugging and logging */
364
+ name?: string;
365
+ /** The middleware handler function */
366
+ handler: MiddlewareFunction;
367
+ /** Skip function to conditionally bypass middleware */
368
+ skip?: ((ctx: Context<any, any>) => boolean) | undefined;
369
+ /** Enable debugging for this middleware */
370
+ debug?: boolean;
552
371
  }
553
372
  /**
554
- * Details for SSE stream closed errors
373
+ * Middleware type with generic parameters for type-safe state and service contributions
374
+ * @template TState - Type of state this middleware contributes to the context
375
+ * @template TServices - Type of services this middleware contributes to the context
555
376
  */
556
- interface SSEStreamClosedErrorDetails {
557
- /** Client identifier */
558
- clientId?: string;
559
- /** When the stream was closed */
560
- closedAt?: string;
561
- /** Reason for closure */
562
- closeReason?: 'client-disconnect' | 'server-close' | 'timeout' | 'error' | 'buffer-overflow';
563
- /** Whether reconnection is possible */
564
- canReconnect?: boolean;
565
- /** Suggested retry interval in milliseconds */
566
- retryAfter?: number;
377
+ interface Middleware<TState = {}, TServices = {}> {
378
+ name: string;
379
+ execute: MiddlewareFunction;
380
+ skip?: ((ctx: Context) => boolean) | undefined;
381
+ debug?: boolean | undefined;
382
+ _services?: TServices;
567
383
  }
384
+
568
385
  /**
569
- * Context for SSE connection errors
386
+ * Helper type to extract TypeScript type from Zod schema
570
387
  */
571
- interface SSEConnectionErrorContext {
572
- /** The SSE endpoint URL */
573
- url: string;
574
- /** Correlation ID for tracing */
575
- correlationId: string;
576
- /** Connection state when error occurred */
577
- state: 'connecting' | 'connected' | 'disconnected' | 'closed';
578
- /** Number of reconnection attempts made */
579
- reconnectAttempts?: number;
580
- /** The original error if available */
581
- originalError?: Error;
582
- /** Additional SSE-specific details */
583
- sseDetails?: {
584
- /** Whether credentials were included */
585
- withCredentials?: boolean;
586
- /** Last received event ID */
587
- lastEventId?: string;
588
- /** EventSource ready state */
589
- readyState?: number;
590
- };
591
- }
388
+ type Infer<T> = T extends z.ZodType ? z.output<T> : unknown;
592
389
  /**
593
- * Context for SSE stream errors (server-sent errors)
390
+ * HTTP methods supported by the router
594
391
  */
595
- interface SSEStreamErrorContext {
596
- /** The SSE endpoint URL */
597
- url: string;
598
- /** Correlation ID from server or client */
599
- correlationId: string;
600
- /** Error message from server */
601
- message: string;
602
- /** Error code if provided */
603
- code?: string;
604
- /** Error name/type from server */
605
- name?: string;
606
- /** Raw error data from server */
607
- rawData?: any;
608
- }
392
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
609
393
  /**
610
- * Context for SSE heartbeat timeout errors
394
+ * Schema for route validation with generic type parameters
611
395
  */
612
- interface SSEHeartbeatErrorContext {
613
- /** The SSE endpoint URL */
614
- url: string;
615
- /** Correlation ID for tracing */
616
- correlationId: string;
617
- /** Configured heartbeat timeout in ms */
618
- heartbeatTimeout: number;
619
- /** Time since last event in ms */
620
- timeSinceLastEvent?: number;
621
- /** Last event ID received */
622
- lastEventId?: string;
396
+ interface RouteSchema<P extends z.ZodType = z.ZodType<any>, // URL parameters schema
397
+ Q extends z.ZodType = z.ZodType<any>, // Query parameters schema
398
+ B extends z.ZodType = z.ZodType<any>, // Body schema
399
+ R extends z.ZodType = z.ZodType<any>, // Response schema
400
+ ED extends z.ZodType = z.ZodType<any>> {
401
+ /** Parameter schema for validation */
402
+ params?: P;
403
+ /** Query schema for validation */
404
+ query?: Q;
405
+ /** Body schema for validation */
406
+ body?: B;
407
+ /** Response schema for validation */
408
+ response?: R;
409
+ /** Error Response Details schema for validation */
410
+ errorResponseDetails?: ED;
623
411
  }
624
-
625
412
  /**
626
- * Represents an uploaded file in a multipart/form-data request
413
+ * Route handler function with strongly typed params and response
627
414
  */
628
- interface UploadedFile {
629
- /** Original filename provided by the client (may be undefined) */
630
- readonly filename: string | undefined;
631
- /** Form field name this file was uploaded under */
632
- readonly fieldname: string;
633
- /** MIME type of the uploaded file */
634
- readonly mimetype: string;
635
- /** Size of the file in bytes */
636
- readonly size: number;
637
- /** Stream containing the file data (always available) */
638
- readonly stream: Readable;
639
- /** Buffer containing file data (only available with 'memory' strategy) */
640
- readonly buffer?: Buffer;
641
- /** Path to temporary file (only available with 'temp' strategy) */
642
- readonly tempPath?: string;
643
- /** SHA-256 hash of file content (if computed) */
644
- readonly hash?: string;
415
+ 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;
417
+ /**
418
+ * Options for a route method with schema-based type inference
419
+ */
420
+ interface RouteMethodOptions<P extends z.ZodType = z.ZodType<any>, Q extends z.ZodType = z.ZodType<any>, B extends z.ZodType = z.ZodType<any>, R extends z.ZodType = z.ZodType<any>, ED extends z.ZodType = z.ZodType<any>> {
421
+ /** Schema for request/response validation */
422
+ schema?: RouteSchema<P, Q, B, R, ED>;
423
+ /** Handler function for the route */
424
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, R extends z.ZodType ? Infer<R> : unknown>;
425
+ /** Middleware to apply to this route */
426
+ middleware?: Middleware[];
427
+ /** Route-specific options */
428
+ options?: Record<string, unknown>;
645
429
  }
646
430
  /**
647
- * Complete multipart/form-data parsed content
431
+ * Route definition mapping HTTP methods to handlers
648
432
  */
649
- interface MultipartData {
650
- /** Form fields (non-file inputs) */
651
- readonly fields: Record<string, string | string[]>;
652
- /** Uploaded files */
653
- readonly files: Record<string, UploadedFile | UploadedFile[]>;
433
+ interface RouteDefinition {
434
+ GET?: RouteMethodOptions<any, any, never, any, any>;
435
+ POST?: RouteMethodOptions<any, any, any, any, any>;
436
+ PUT?: RouteMethodOptions<any, any, any, any, any>;
437
+ DELETE?: RouteMethodOptions<any, any, never, any, any>;
438
+ PATCH?: RouteMethodOptions<any, any, any, any, any>;
439
+ HEAD?: RouteMethodOptions<any, any, never, any, any>;
440
+ OPTIONS?: RouteMethodOptions<any, any, never, any, any>;
654
441
  }
655
442
  /**
656
- * Options for parsing multipart/form-data
443
+ * Route object with path
657
444
  */
658
- interface ParseOptions {
659
- /** Maximum size for individual files in bytes (default: 10MB) */
660
- readonly maxFileSize?: number;
661
- /** Maximum number of files per request (default: 10) */
662
- readonly maxFiles?: number;
663
- /** Maximum size for form fields in bytes (default: 1MB) */
664
- readonly maxFieldSize?: number;
665
- /** Allowed MIME types (empty array = allow all) */
666
- readonly allowedMimeTypes?: readonly string[];
667
- /** Allowed file extensions (empty array = allow all) */
668
- readonly allowedExtensions?: readonly string[];
669
- /** Processing strategy for file data */
670
- readonly strategy: 'memory' | 'stream' | 'temp';
671
- /** Directory for temporary files (strategy: 'temp' only) */
672
- readonly tempDir?: string;
673
- /** Whether to compute SHA-256 hash of files */
674
- readonly computeHash?: boolean;
445
+ interface Route extends RouteDefinition {
446
+ /** Path of the route */
447
+ path: string;
675
448
  }
676
449
  /**
677
- * Result of parsing multipart data with metadata
450
+ * Options for route creation
678
451
  */
679
- interface ParseResult {
680
- /** Parsed multipart data */
681
- readonly data: MultipartData;
682
- /** Parsing metadata */
683
- readonly metadata: {
684
- /** Total time spent parsing (milliseconds) */
685
- readonly parseTime: number;
686
- /** Total size of all uploaded content */
687
- readonly totalSize: number;
688
- /** Number of files processed */
689
- readonly fileCount: number;
690
- /** Number of fields processed */
691
- readonly fieldCount: number;
692
- };
452
+ interface RouteOptions {
453
+ /** Base path for the route */
454
+ basePath?: string;
693
455
  }
694
456
  /**
695
- * Error information for multipart parsing failures
457
+ * Result type for handling success and error responses
696
458
  */
697
- interface MultipartError {
698
- /** Error type/code */
699
- readonly type: 'boundary_missing' | 'size_exceeded' | 'file_limit_exceeded' | 'mime_type_forbidden' | 'extension_forbidden' | 'parse_error' | 'stream_error' | 'temp_file_error';
700
- /** Human-readable error message */
701
- readonly message: string;
702
- /** Additional context (field name, file name, etc.) */
703
- readonly context?: Record<string, unknown>;
704
- /** Original error if available */
705
- readonly cause?: Error;
459
+ type Result<T, E = {
460
+ error: string;
461
+ message: string;
462
+ details?: unknown;
463
+ }> = {
464
+ success: true;
465
+ data: T;
466
+ status?: number;
467
+ } | {
468
+ success: false;
469
+ error: E;
470
+ status?: number;
471
+ };
472
+ /**
473
+ * Router options
474
+ */
475
+ interface RouterOptions {
476
+ /** Directory containing route files */
477
+ routesDir: string;
478
+ /** Base path for all routes */
479
+ basePath?: string;
480
+ /** Watch for file changes in development */
481
+ watchMode?: boolean;
706
482
  }
707
483
  /**
708
- * Configuration for file upload validation
484
+ * Router interface
709
485
  */
710
- interface ValidationConfig {
711
- /** File size constraints */
712
- readonly size?: {
713
- readonly min?: number;
714
- readonly max?: number;
715
- };
716
- /** File count constraints */
717
- readonly count?: {
718
- readonly min?: number;
719
- readonly max?: number;
720
- };
721
- /** MIME type constraints */
722
- readonly mimeTypes?: {
723
- readonly allowed?: readonly string[];
724
- readonly forbidden?: readonly string[];
725
- };
726
- /** File extension constraints */
727
- readonly extensions?: {
728
- readonly allowed?: readonly string[];
729
- readonly forbidden?: readonly string[];
486
+ interface Router {
487
+ /** Handle an incoming request */
488
+ handleRequest: (ctx: Context) => Promise<void>;
489
+ /** Get all registered routes */
490
+ getRoutes: () => Route[];
491
+ /** Add a route programmatically */
492
+ addRoute: (route: Route) => void;
493
+ /** Add multiple routes programmatically with batch processing */
494
+ addRoutes: (routes: Route[]) => {
495
+ added: Route[];
496
+ removed: string[];
497
+ changed: Route[];
730
498
  };
731
- /** Custom validation function */
732
- readonly custom?: (file: UploadedFile) => Promise<boolean> | boolean;
499
+ /** Add a route directory for plugins */
500
+ addRouteDirectory(directory: string, options?: {
501
+ prefix?: string;
502
+ }): Promise<void>;
503
+ /** Get route conflicts */
504
+ getRouteConflicts(): Array<{
505
+ path: string;
506
+ sources: string[];
507
+ }>;
508
+ /** Close watchers and cleanup resources */
509
+ close?: () => Promise<void>;
733
510
  }
734
511
  /**
735
- * File processing configuration
512
+ * Route match result
736
513
  */
737
- interface ProcessingConfig {
738
- /** Whether to process files concurrently */
739
- readonly concurrent?: boolean;
740
- /** Maximum concurrent processing operations */
741
- readonly maxConcurrency?: number;
742
- /** Processing timeout in milliseconds */
743
- readonly timeout?: number;
744
- /** Whether to preserve original files during processing */
745
- readonly preserveOriginal?: boolean;
514
+ interface RouteMatch {
515
+ /** The matched route handler (null if method not allowed) */
516
+ route: RouteMethodOptions | null;
517
+ /** Extracted route parameters */
518
+ params: Record<string, string>;
519
+ /** Flag indicating if the path exists but method isn't allowed */
520
+ methodNotAllowed?: boolean;
521
+ /** List of allowed methods for this path (when method not allowed) */
522
+ allowedMethods?: HttpMethod[];
746
523
  }
747
524
  /**
748
- * Upload progress information (for future streaming uploads)
525
+ * Route matcher interface
749
526
  */
750
- interface UploadProgress {
751
- /** Bytes uploaded so far */
752
- readonly bytesUploaded: number;
753
- /** Total bytes to upload */
754
- readonly totalBytes: number;
755
- /** Upload percentage (0-100) */
756
- readonly percentage: number;
757
- /** Upload speed in bytes per second */
758
- readonly speed: number;
759
- /** Estimated time remaining in milliseconds */
760
- readonly eta: number;
527
+ interface Matcher {
528
+ /** Add a route to the matcher */
529
+ add: (path: string, method: HttpMethod, route: RouteMethodOptions) => void;
530
+ /** Match a URL path to a route */
531
+ match: (path: string, method: HttpMethod) => RouteMatch | null;
532
+ /** Get all registered routes */
533
+ getRoutes: () => {
534
+ path: string;
535
+ method: HttpMethod;
536
+ }[];
537
+ /** Find routes matching a specific path */
538
+ findRoutes: (path: string) => {
539
+ path: string;
540
+ method: HttpMethod;
541
+ params: Record<string, string>;
542
+ }[];
543
+ /** Remove a route from the matcher (optional for compatibility) */
544
+ remove: (path: string) => void;
545
+ /** Clear all routes from the matcher (optional for compatibility) */
546
+ clear: () => void;
761
547
  }
762
- /**
763
- * Internal state for multipart parser state machine
764
- */
765
- interface ParserState {
766
- boundary: Buffer;
767
- options: Required<ParseOptions>;
768
- fields: Map<string, string[]>;
769
- files: Map<string, UploadedFile[]>;
770
- buffer: Buffer;
771
- stage: 'boundary' | 'headers' | 'content';
772
- currentHeaders: string;
773
- currentField: string | null;
774
- currentFilename: string | undefined;
775
- currentMimetype: string;
776
- currentContentLength: number;
777
- fileCount: number;
778
- fieldCount: number;
779
- currentBufferChunks: Buffer[];
780
- currentStream: Readable | null;
781
- currentTempPath: string | null;
782
- currentWriteStream: WriteStream | null;
783
- streamController: ReadableStreamDefaultController<Uint8Array> | null;
784
- cleanupTasks: Array<() => Promise<void>>;
785
- /**
786
- * Whether we've found at least one valid boundary marker
787
- */
788
- hasFoundValidBoundary: boolean;
789
- /**
790
- * Whether we've successfully processed at least one complete part (field or file)
791
- */
792
- hasProcessedAnyPart: boolean;
793
- /**
794
- * Whether parsing has reached the end boundary
795
- */
796
- isFinished: boolean;
548
+ interface ParsedRoute {
549
+ filePath: string;
550
+ routePath: string;
551
+ params: string[];
797
552
  }
798
-
799
- /**
800
- * Unified request type supporting both HTTP/1.1 and HTTP/2
801
- */
802
- type UnifiedRequest = IncomingMessage | Http2ServerRequest;
803
- /**
804
- * Unified response type supporting both HTTP/1.1 and HTTP/2
805
- */
806
- type UnifiedResponse = ServerResponse | Http2ServerResponse;
807
553
  /**
808
- * Request parameters extracted from URL path
554
+ * Node in the radix tree for efficient route matching
809
555
  */
810
- interface RequestParams {
811
- [key: string]: string;
556
+ interface RouteNode {
557
+ segment: string;
558
+ paramName: string | null;
559
+ isWildcard: boolean;
560
+ children: RouteNode[];
561
+ handlers: Partial<Record<HttpMethod, RouteMethodOptions>>;
562
+ pattern: RegExp | null;
812
563
  }
813
- /**
814
- * Query parameters from URL
815
- */
816
- interface QueryParams {
817
- [key: string]: string | string[] | undefined;
564
+ interface RouteEntry {
565
+ /** The route path pattern */
566
+ path: string;
567
+ /** The HTTP method */
568
+ method: HttpMethod;
569
+ /** The compiled regex pattern */
570
+ pattern: RegExp;
571
+ /** The parameter names in order */
572
+ paramNames: string[];
573
+ /** The route handler options */
574
+ routeOptions: RouteMethodOptions;
818
575
  }
819
- /**
820
- * Options for streaming responses
821
- */
822
- interface StreamOptions {
823
- contentType?: string;
824
- status?: number;
825
- headers?: Record<string, string>;
576
+ interface ErrorHandlerOptions {
577
+ /** Show detailed errors in response */
578
+ detailed?: boolean;
579
+ /** Log errors to console */
580
+ log?: boolean;
826
581
  }
827
- /**
828
- * State container for storing request-scoped data
829
- * Allows for proper typing with generics
830
- */
831
- interface State {
832
- [key: string]: unknown;
833
- /**
834
- * Body parsing error information
835
- * Set when body parsing fails during request processing
836
- */
837
- _bodyError?: BodyParseError;
582
+ interface ProcessResponseOptions {
583
+ /** Status code to use if not specified */
584
+ defaultStatus?: number;
838
585
  }
839
586
  /**
840
- * Services container for storing injectable services/dependencies
841
- * Allows middleware to contribute services that are accessible throughout the request lifecycle
587
+ * Standard error response structure
842
588
  */
843
- interface Services {
844
- [key: string]: unknown;
589
+ interface StandardErrorResponse {
590
+ error: string;
591
+ message: string;
845
592
  }
846
- interface ContextResponse<S extends State = State> {
847
- raw: UnifiedResponse;
848
- sent: boolean;
849
- statusCode: number;
850
- status: (code: number) => ContextResponse<S>;
851
- header: (name: string, value: string) => ContextResponse<S>;
852
- headers: (headers: Record<string, string>) => ContextResponse<S>;
853
- type: (contentType: string) => ContextResponse<S>;
854
- json: (body: unknown, status?: number) => void;
855
- text: (body: string, status?: number) => void;
856
- html: (body: string, status?: number) => void;
857
- redirect: (url: string, status?: number) => void;
858
- stream: (readable: NodeJS.ReadableStream, options?: StreamOptions) => void;
593
+ interface FileCache {
594
+ routes: Route[];
595
+ timestamp: number;
596
+ hash: string;
859
597
  }
860
- interface ContextRequest<TBody = unknown> {
861
- raw: UnifiedRequest;
862
- method: string;
863
- path: string;
864
- url: URL | null;
865
- query: QueryParams;
866
- params: RequestParams;
867
- protocol: string;
868
- isHttp2: boolean;
869
- body?: TBody;
870
- /**
871
- * Uploaded files from multipart/form-data requests
872
- * Available when Content-Type is multipart/form-data
873
- */
874
- files?: Record<string, UploadedFile | UploadedFile[]>;
875
- /**
876
- * Complete multipart data (files + fields)
877
- * Available when Content-Type is multipart/form-data
878
- */
879
- multipart?: MultipartData;
880
- header: (name: string) => string | undefined;
881
- headers: (names?: string[]) => Record<string, string | undefined>;
598
+ interface ReloadMetrics {
599
+ fileChanges: number;
600
+ totalReloadTime: number;
601
+ averageReloadTime: number;
602
+ slowReloads: Array<{
603
+ file: string;
604
+ time: number;
605
+ }>;
882
606
  }
883
- /**
884
- * Context object representing a request/response cycle
885
- * @template S - Type of the state object
886
- * @template Svc - Type of the services object
887
- * @template TBody - Type of the request body
888
- * @template TQuery - Type of the query parameters
889
- */
890
- interface Context<S extends State = State, Svc extends Services = Services, TBody = unknown, TQuery = QueryParams> {
891
- /**
892
- * Request information
893
- */
894
- request: Omit<ContextRequest, 'body' | 'query'> & {
895
- body: TBody;
896
- query: TQuery;
897
- };
898
- /**
899
- * Response handling
900
- */
901
- response: ContextResponse<S>;
902
- /**
903
- * Request-scoped state for storing data during the request lifecycle
904
- */
905
- state: S;
906
- /**
907
- * Services container for accessing injected services/dependencies
908
- * Populated by middleware that contribute services
909
- */
910
- services: Svc;
607
+ interface WatchOptions {
608
+ debounceMs?: number;
609
+ /** Directories to ignore */
610
+ ignore?: string[];
611
+ /** Callback for new routes */
612
+ onRouteAdded?: (filePath: string, routes: Route[]) => void;
613
+ /** Callback for changed routes */
614
+ onRouteChanged?: (filePath: string, routes: Route[]) => void;
615
+ /** Callback for removed routes */
616
+ onRouteRemoved?: (filePath: string, routes: Route[]) => void;
617
+ /** Callback for errors */
618
+ onError?: (error: Error) => void;
911
619
  }
912
- interface BodyLimits {
913
- /** Maximum JSON body size in bytes (default: 512KB) */
914
- json: number;
915
- /** Maximum form data size in bytes (default: 1MB) */
916
- form: number;
917
- /** Maximum text body size in bytes (default: 5MB) */
918
- text: number;
919
- /** Maximum raw/binary body size in bytes (default: 10MB) */
920
- raw: number;
921
- /** Multipart/form-data limits */
922
- multipart: MultipartLimits;
620
+ interface RouteRegistry {
621
+ routesByPath: Map<string, Route>;
622
+ routesByFile: Map<string, Set<string>>;
623
+ pathToFile: Map<string, string>;
624
+ }
625
+ interface FindRouteFilesOptions {
626
+ /** Directories to ignore */
627
+ ignore?: string[] | undefined;
923
628
  }
924
- type MultipartLimits = {
925
- maxFileSize?: number;
926
- maxTotalSize?: number;
927
- maxFiles?: number;
928
- maxFieldSize?: number;
929
- };
930
629
  /**
931
- * Options for creating a context
630
+ * GET route creator with state and services support
631
+ * Now returns a higher-order function to handle generics properly
932
632
  */
933
- interface ContextOptions {
934
- /**
935
- * Whether to parse the request body
936
- */
937
- parseBody?: boolean;
938
- /**
939
- * Initial state to include in the context
940
- *
941
- */
942
- initialState?: State;
943
- /**
944
- * Initial services to include in the context
945
- *
946
- */
947
- initialServices?: Services;
948
- /**
949
- * Limits for various body types to prevent abuse
950
- */
951
- bodyLimits: BodyLimits;
952
- }
953
- /**
954
- * Function to get the current context from AsyncLocalStorage
955
- */
956
- type GetContextFn = <S extends State = State, Svc extends Services = Services>() => Context<S, Svc> | undefined;
633
+ type CreateGetRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
634
+ schema?: {
635
+ params?: P extends never ? never : P;
636
+ query?: Q extends never ? never : Q;
637
+ response?: R extends never ? never : R;
638
+ };
639
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // GET never has body
640
+ [
641
+ R
642
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
643
+ middleware?: Middleware[];
644
+ options?: Record<string, unknown>;
645
+ }) => {
646
+ GET: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
647
+ path: string;
648
+ };
957
649
  /**
958
- * Factory function for creating a new context
650
+ * POST route creator with state and services support
959
651
  */
960
- type CreateContextFn = (req: UnifiedRequest, res: UnifiedResponse, options?: ContextOptions) => Promise<Context>;
652
+ type CreatePostRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
653
+ schema?: {
654
+ params?: P extends never ? never : P;
655
+ query?: Q extends never ? never : Q;
656
+ body?: B extends never ? never : B;
657
+ response?: R extends never ? never : R;
658
+ };
659
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
660
+ R
661
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
662
+ middleware?: Middleware[];
663
+ options?: Record<string, unknown>;
664
+ }) => {
665
+ POST: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
666
+ path: string;
667
+ };
961
668
  /**
962
- * Type representing unknown function
963
- *
964
- * This is a generic function type that can accept any number of arguments
965
- * and return any type of value. It is used for type inference in various
966
- * contexts where the specific function signature is not known or not
967
- * important.
669
+ * PUT route creator with state and services support
968
670
  */
969
- type UnknownFunction = (...args: unknown[]) => unknown;
970
-
671
+ type CreatePutRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
672
+ schema?: {
673
+ params?: P extends never ? never : P;
674
+ query?: Q extends never ? never : Q;
675
+ body?: B extends never ? never : B;
676
+ response?: R extends never ? never : R;
677
+ };
678
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
679
+ R
680
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
681
+ middleware?: Middleware[];
682
+ options?: Record<string, unknown>;
683
+ }) => {
684
+ PUT: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
685
+ path: string;
686
+ };
971
687
  /**
972
- * Function to pass control to the next middleware
688
+ * DELETE route creator with state and services support
973
689
  */
974
- type NextFunction = () => Promise<void> | void;
690
+ type CreateDeleteRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
691
+ schema?: {
692
+ params?: P extends never ? never : P;
693
+ query?: Q extends never ? never : Q;
694
+ response?: R extends never ? never : R;
695
+ };
696
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // DELETE never has body
697
+ [
698
+ R
699
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
700
+ middleware?: Middleware[];
701
+ options?: Record<string, unknown>;
702
+ }) => {
703
+ DELETE: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
704
+ path: string;
705
+ };
975
706
  /**
976
- * Middleware function signature
707
+ * PATCH route creator with state and services support
977
708
  */
978
- type MiddlewareFunction = (ctx: Context, next: NextFunction) => Promise<void> | void;
709
+ type CreatePatchRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
710
+ schema?: {
711
+ params?: P extends never ? never : P;
712
+ query?: Q extends never ? never : Q;
713
+ body?: B extends never ? never : B;
714
+ response?: R extends never ? never : R;
715
+ };
716
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
717
+ R
718
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
719
+ middleware?: Middleware[];
720
+ options?: Record<string, unknown>;
721
+ }) => {
722
+ PATCH: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
723
+ path: string;
724
+ };
979
725
  /**
980
- * Named middleware options
726
+ * HEAD route creator with state and services support
981
727
  */
982
- interface MiddlewareOptions {
983
- /** Name of the middleware for debugging and logging */
984
- name?: string;
985
- /** The middleware handler function */
986
- handler: MiddlewareFunction;
987
- /** Skip function to conditionally bypass middleware */
988
- skip?: ((ctx: Context<any, any>) => boolean) | undefined;
989
- /** Enable debugging for this middleware */
990
- debug?: boolean;
991
- }
728
+ type CreateHeadRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
729
+ schema?: {
730
+ params?: P extends never ? never : P;
731
+ query?: Q extends never ? never : Q;
732
+ response?: R extends never ? never : R;
733
+ };
734
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // HEAD never has body
735
+ [
736
+ R
737
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
738
+ middleware?: Middleware[];
739
+ options?: Record<string, unknown>;
740
+ }) => {
741
+ HEAD: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
742
+ path: string;
743
+ };
992
744
  /**
993
- * Middleware type with generic parameters for type-safe state and service contributions
994
- * @template TState - Type of state this middleware contributes to the context
995
- * @template TServices - Type of services this middleware contributes to the context
745
+ * OPTIONS route creator with state and services support
996
746
  */
997
- interface Middleware<TState = {}, TServices = {}> {
998
- name: string;
999
- execute: MiddlewareFunction;
1000
- skip?: ((ctx: Context) => boolean) | undefined;
1001
- debug?: boolean | undefined;
1002
- _services?: TServices;
1003
- }
747
+ type CreateOptionsRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
748
+ schema?: {
749
+ params?: P extends never ? never : P;
750
+ query?: Q extends never ? never : Q;
751
+ response?: R extends never ? never : R;
752
+ };
753
+ handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // OPTIONS never has body
754
+ [
755
+ R
756
+ ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
757
+ middleware?: Middleware[];
758
+ options?: Record<string, unknown>;
759
+ }) => {
760
+ OPTIONS: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
761
+ path: string;
762
+ };
1004
763
 
1005
764
  /**
1006
- * Helper type to extract TypeScript type from Zod schema
765
+ * Compose multiple middleware functions into a single middleware function
1007
766
  */
1008
- type Infer<T> = T extends z.ZodType ? z.output<T> : unknown;
767
+ declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
768
+
1009
769
  /**
1010
- * HTTP methods supported by the router
770
+ * CORS Types for BlaizeJS Framework
771
+ *
772
+ * Comprehensive type definitions for W3C-compliant CORS middleware
773
+ * with support for string, regex, and async function origin validation.
774
+ *
775
+ * @module @blaizejs/types/cors
1011
776
  */
1012
- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
777
+
1013
778
  /**
1014
- * Schema for route validation with generic type parameters
779
+ * Origin configuration type supporting multiple validation methods
780
+ *
781
+ * @example
782
+ * ```typescript
783
+ * // String origin (exact match)
784
+ * const origin: CorsOrigin = 'https://example.com';
785
+ *
786
+ * // RegExp pattern
787
+ * const origin: CorsOrigin = /^https:\/\/.*\.example\.com$/;
788
+ *
789
+ * // Dynamic validation function
790
+ * const origin: CorsOrigin = async (origin, ctx) => {
791
+ * return await checkOriginAllowed(origin, ctx?.state.user);
792
+ * };
793
+ *
794
+ * // Array of mixed types
795
+ * const origin: CorsOrigin = [
796
+ * 'https://localhost:3000',
797
+ * /^https:\/\/.*\.example\.com$/,
798
+ * (origin) => origin.endsWith('.trusted.com')
799
+ * ];
800
+ * ```
1015
801
  */
1016
- interface RouteSchema<P extends z.ZodType = z.ZodType<any>, // URL parameters schema
1017
- Q extends z.ZodType = z.ZodType<any>, // Query parameters schema
1018
- B extends z.ZodType = z.ZodType<any>, // Body schema
1019
- R extends z.ZodType = z.ZodType<any>, // Response schema
1020
- ED extends z.ZodType = z.ZodType<any>> {
1021
- /** Parameter schema for validation */
1022
- params?: P;
1023
- /** Query schema for validation */
1024
- query?: Q;
1025
- /** Body schema for validation */
1026
- body?: B;
1027
- /** Response schema for validation */
1028
- response?: R;
1029
- /** Error Response Details schema for validation */
1030
- errorResponseDetails?: ED;
1031
- }
802
+ type CorsOrigin = string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>) | Array<string | RegExp | ((origin: string, ctx?: Context<any, any>) => boolean | Promise<boolean>)>;
1032
803
  /**
1033
- * Route handler function with strongly typed params and response
804
+ * HTTP methods that can be allowed in CORS
805
+ * Based on W3C CORS specification
1034
806
  */
1035
- 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
1036
- TServices extends Services = Services> = (ctx: Context<TState, TServices, TBody, TQuery>, params: TParams) => Promise<TResponse> | TResponse;
807
+ type CorsHttpMethod = HttpMethod | 'CONNECT' | 'TRACE';
1037
808
  /**
1038
- * Options for a route method with schema-based type inference
809
+ * Main CORS configuration options
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * const corsOptions: CorsOptions = {
814
+ * origin: 'https://example.com',
815
+ * methods: ['GET', 'POST'],
816
+ * credentials: true,
817
+ * maxAge: 86400
818
+ * };
819
+ * ```
1039
820
  */
1040
- interface RouteMethodOptions<P extends z.ZodType = z.ZodType<any>, Q extends z.ZodType = z.ZodType<any>, B extends z.ZodType = z.ZodType<any>, R extends z.ZodType = z.ZodType<any>, ED extends z.ZodType = z.ZodType<any>> {
1041
- /** Schema for request/response validation */
1042
- schema?: RouteSchema<P, Q, B, R, ED>;
1043
- /** Handler function for the route */
1044
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, R extends z.ZodType ? Infer<R> : unknown>;
1045
- /** Middleware to apply to this route */
1046
- middleware?: Middleware[];
1047
- /** Route-specific options */
1048
- options?: Record<string, unknown>;
821
+ interface CorsOptions {
822
+ /**
823
+ * Configures the Access-Control-Allow-Origin header
824
+ *
825
+ * Possible values:
826
+ * - `true`: Allow all origins (sets to '*' unless credentials is true, then reflects origin)
827
+ * - `false`: Disable CORS (no headers set)
828
+ * - `string`: Specific origin to allow
829
+ * - `RegExp`: Pattern to match origins
830
+ * - `function`: Custom validation logic
831
+ * - `array`: Multiple origin configurations
832
+ *
833
+ * @default false
834
+ */
835
+ origin?: boolean | CorsOrigin;
836
+ /**
837
+ * Configures the Access-Control-Allow-Methods header
838
+ *
839
+ * @default ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
840
+ * @example ['GET', 'POST']
841
+ */
842
+ methods?: CorsHttpMethod[] | string;
843
+ /**
844
+ * Configures the Access-Control-Allow-Headers header
845
+ *
846
+ * Pass an array of allowed headers or a comma-delimited string.
847
+ *
848
+ * @default Request's Access-Control-Request-Headers header value
849
+ * @example ['Content-Type', 'Authorization']
850
+ */
851
+ allowedHeaders?: string[] | string;
852
+ /**
853
+ * Configures the Access-Control-Expose-Headers header
854
+ *
855
+ * Headers that the browser is allowed to access.
856
+ *
857
+ * @default []
858
+ * @example ['Content-Range', 'X-Content-Range']
859
+ */
860
+ exposedHeaders?: string[] | string;
861
+ /**
862
+ * Configures the Access-Control-Allow-Credentials header
863
+ *
864
+ * Set to true to allow credentials (cookies, authorization headers, TLS client certificates).
865
+ * Note: Cannot be used with origin: '*' for security reasons.
866
+ *
867
+ * @default false
868
+ */
869
+ credentials?: boolean;
870
+ /**
871
+ * Configures the Access-Control-Max-Age header in seconds
872
+ *
873
+ * Indicates how long browsers can cache preflight response.
874
+ * Set to -1 to disable caching.
875
+ *
876
+ * @default undefined (browser decides)
877
+ * @example 86400 // 24 hours
878
+ */
879
+ maxAge?: number;
880
+ /**
881
+ * Whether to pass the CORS preflight response to the next handler
882
+ *
883
+ * When false, the preflight response is sent immediately.
884
+ * When true, control passes to the next middleware/handler.
885
+ *
886
+ * @default false
887
+ */
888
+ preflightContinue?: boolean;
889
+ /**
890
+ * HTTP status code for successful OPTIONS requests
891
+ *
892
+ * Some legacy browsers require 200, while 204 is more correct.
893
+ *
894
+ * @default 204
895
+ */
896
+ optionsSuccessStatus?: number;
1049
897
  }
1050
898
  /**
1051
- * Route definition mapping HTTP methods to handlers
899
+ * Internal CORS validation result
900
+ * Used by middleware implementation
1052
901
  */
1053
- interface RouteDefinition {
1054
- GET?: RouteMethodOptions<any, any, never, any, any>;
1055
- POST?: RouteMethodOptions<any, any, any, any, any>;
1056
- PUT?: RouteMethodOptions<any, any, any, any, any>;
1057
- DELETE?: RouteMethodOptions<any, any, never, any, any>;
1058
- PATCH?: RouteMethodOptions<any, any, any, any, any>;
1059
- HEAD?: RouteMethodOptions<any, any, never, any, any>;
1060
- OPTIONS?: RouteMethodOptions<any, any, never, any, any>;
902
+ interface CorsValidationResult {
903
+ /**
904
+ * Whether the origin is allowed
905
+ */
906
+ allowed: boolean;
907
+ /**
908
+ * The origin value to set in the header
909
+ * Can be '*', specific origin, or 'null'
910
+ */
911
+ origin?: string;
912
+ /**
913
+ * Whether to add Vary: Origin header
914
+ */
915
+ vary?: boolean;
1061
916
  }
1062
917
  /**
1063
- * Route object with path
918
+ * CORS preflight request information
919
+ * Extracted from OPTIONS request headers
1064
920
  */
1065
- interface Route extends RouteDefinition {
1066
- /** Path of the route */
1067
- path: string;
921
+ interface CorsPreflightInfo {
922
+ /**
923
+ * The origin making the request
924
+ */
925
+ origin?: string;
926
+ /**
927
+ * The method that will be used in the actual request
928
+ * From Access-Control-Request-Method header
929
+ */
930
+ requestedMethod?: string;
931
+ /**
932
+ * The headers that will be sent in the actual request
933
+ * From Access-Control-Request-Headers header
934
+ */
935
+ requestedHeaders?: string[];
1068
936
  }
1069
937
  /**
1070
- * Options for route creation
938
+ * Cache entry for origin validation results
939
+ * Used for performance optimization
1071
940
  */
1072
- interface RouteOptions {
1073
- /** Base path for the route */
1074
- basePath?: string;
941
+ interface CorsOriginCacheEntry {
942
+ /**
943
+ * Whether the origin is allowed
944
+ */
945
+ allowed: boolean;
946
+ /**
947
+ * When this cache entry expires (timestamp)
948
+ */
949
+ expiresAt: number;
950
+ /**
951
+ * Optional user identifier for cache key
952
+ */
953
+ userId?: string;
1075
954
  }
1076
955
  /**
1077
- * Result type for handling success and error responses
956
+ * Configuration for CORS origin validation cache
1078
957
  */
1079
- type Result<T, E = {
1080
- error: string;
1081
- message: string;
1082
- details?: unknown;
1083
- }> = {
1084
- success: true;
1085
- data: T;
1086
- status?: number;
1087
- } | {
1088
- success: false;
1089
- error: E;
1090
- status?: number;
1091
- };
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
+ }
1092
975
  /**
1093
- * Router options
976
+ * Statistics for CORS middleware performance monitoring
1094
977
  */
1095
- interface RouterOptions {
1096
- /** Directory containing route files */
1097
- routesDir: string;
1098
- /** Base path for all routes */
1099
- basePath?: string;
1100
- /** Watch for file changes in development */
1101
- watchMode?: boolean;
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;
1102
1003
  }
1103
1004
  /**
1104
- * Router interface
1005
+ * Cache entry type
1105
1006
  */
1106
- interface Router {
1107
- /** Handle an incoming request */
1108
- handleRequest: (ctx: Context) => Promise<void>;
1109
- /** Get all registered routes */
1110
- getRoutes: () => Route[];
1111
- /** Add a route programmatically */
1112
- addRoute: (route: Route) => void;
1113
- /** Add multiple routes programmatically with batch processing */
1114
- addRoutes: (routes: Route[]) => {
1115
- added: Route[];
1116
- removed: string[];
1117
- changed: Route[];
1118
- };
1119
- /** Add a route directory for plugins */
1120
- addRouteDirectory(directory: string, options?: {
1121
- prefix?: string;
1122
- }): Promise<void>;
1123
- /** Get route conflicts */
1124
- getRouteConflicts(): Array<{
1125
- path: string;
1126
- sources: string[];
1127
- }>;
1128
- /** Close watchers and cleanup resources */
1129
- close?: () => Promise<void>;
1007
+ interface CacheEntry {
1008
+ allowed: boolean;
1009
+ expiresAt: number;
1010
+ lastAccessed: number;
1130
1011
  }
1131
1012
  /**
1132
- * Route match result
1013
+ * Cache configuration
1133
1014
  */
1134
- interface RouteMatch {
1135
- /** The matched route handler (null if method not allowed) */
1136
- route: RouteMethodOptions | null;
1137
- /** Extracted route parameters */
1138
- params: Record<string, string>;
1139
- /** Flag indicating if the path exists but method isn't allowed */
1140
- methodNotAllowed?: boolean;
1141
- /** List of allowed methods for this path (when method not allowed) */
1142
- allowedMethods?: HttpMethod[];
1015
+ interface CacheConfig {
1016
+ ttl: number;
1017
+ maxSize: number;
1143
1018
  }
1019
+
1144
1020
  /**
1145
- * Route matcher interface
1146
- */
1147
- interface Matcher {
1148
- /** Add a route to the matcher */
1149
- add: (path: string, method: HttpMethod, route: RouteMethodOptions) => void;
1150
- /** Match a URL path to a route */
1151
- match: (path: string, method: HttpMethod) => RouteMatch | null;
1152
- /** Get all registered routes */
1153
- getRoutes: () => {
1154
- path: string;
1155
- method: HttpMethod;
1156
- }[];
1157
- /** Find routes matching a specific path */
1158
- findRoutes: (path: string) => {
1159
- path: string;
1160
- method: HttpMethod;
1161
- params: Record<string, string>;
1162
- }[];
1163
- /** Remove a route from the matcher (optional for compatibility) */
1164
- remove: (path: string) => void;
1165
- /** Clear all routes from the matcher (optional for compatibility) */
1166
- clear: () => void;
1167
- }
1168
- interface ParsedRoute {
1169
- filePath: string;
1170
- routePath: string;
1171
- params: string[];
1172
- }
1173
- /**
1174
- * Node in the radix tree for efficient route matching
1175
- */
1176
- interface RouteNode {
1177
- segment: string;
1178
- paramName: string | null;
1179
- isWildcard: boolean;
1180
- children: RouteNode[];
1181
- handlers: Partial<Record<HttpMethod, RouteMethodOptions>>;
1182
- pattern: RegExp | null;
1183
- }
1184
- interface RouteEntry {
1185
- /** The route path pattern */
1186
- path: string;
1187
- /** The HTTP method */
1188
- method: HttpMethod;
1189
- /** The compiled regex pattern */
1190
- pattern: RegExp;
1191
- /** The parameter names in order */
1192
- paramNames: string[];
1193
- /** The route handler options */
1194
- routeOptions: RouteMethodOptions;
1195
- }
1196
- interface ErrorHandlerOptions {
1197
- /** Show detailed errors in response */
1198
- detailed?: boolean;
1199
- /** Log errors to console */
1200
- log?: boolean;
1201
- }
1202
- interface ProcessResponseOptions {
1203
- /** Status code to use if not specified */
1204
- defaultStatus?: number;
1205
- }
1206
- /**
1207
- * Standard error response structure
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
+ * ```
1208
1055
  */
1209
- interface StandardErrorResponse {
1210
- error: string;
1211
- message: string;
1212
- }
1213
- interface FileCache {
1214
- routes: Route[];
1215
- timestamp: number;
1216
- hash: string;
1217
- }
1218
- interface ReloadMetrics {
1219
- fileChanges: number;
1220
- totalReloadTime: number;
1221
- averageReloadTime: number;
1222
- slowReloads: Array<{
1223
- file: string;
1224
- time: number;
1225
- }>;
1226
- }
1227
- interface WatchOptions {
1228
- debounceMs?: number;
1229
- /** Directories to ignore */
1230
- ignore?: string[];
1231
- /** Callback for new routes */
1232
- onRouteAdded?: (filePath: string, routes: Route[]) => void;
1233
- /** Callback for changed routes */
1234
- onRouteChanged?: (filePath: string, routes: Route[]) => void;
1235
- /** Callback for removed routes */
1236
- onRouteRemoved?: (filePath: string, routes: Route[]) => void;
1237
- /** Callback for errors */
1238
- onError?: (error: Error) => void;
1239
- }
1240
- interface RouteRegistry {
1241
- routesByPath: Map<string, Route>;
1242
- routesByFile: Map<string, Set<string>>;
1243
- pathToFile: Map<string, string>;
1244
- }
1245
- interface FindRouteFilesOptions {
1246
- /** Directories to ignore */
1247
- ignore?: string[] | undefined;
1248
- }
1056
+ declare function cors(userOptions?: CorsOptions | boolean): Middleware;
1057
+
1249
1058
  /**
1250
- * GET route creator with state and services support
1251
- * Now returns a higher-order function to handle generics properly
1059
+ * Create a middleware
1252
1060
  */
1253
- type CreateGetRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
1254
- schema?: {
1255
- params?: P extends never ? never : P;
1256
- query?: Q extends never ? never : Q;
1257
- response?: R extends never ? never : R;
1258
- };
1259
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // GET never has body
1260
- [
1261
- R
1262
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1263
- middleware?: Middleware[];
1264
- options?: Record<string, unknown>;
1265
- }) => {
1266
- GET: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
1267
- path: string;
1268
- };
1061
+ declare function create$2<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
1269
1062
  /**
1270
- * POST route creator with state and services support
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
+ *
1271
1070
  */
1272
- type CreatePostRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
1273
- schema?: {
1274
- params?: P extends never ? never : P;
1275
- query?: Q extends never ? never : Q;
1276
- body?: B extends never ? never : B;
1277
- response?: R extends never ? never : R;
1278
- };
1279
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
1280
- R
1281
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1282
- middleware?: Middleware[];
1283
- options?: Record<string, unknown>;
1284
- }) => {
1285
- POST: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
1286
- path: string;
1287
- };
1071
+ declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
1288
1072
  /**
1289
- * PUT route creator with state and services support
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
+ *
1290
1080
  */
1291
- type CreatePutRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
1292
- schema?: {
1293
- params?: P extends never ? never : P;
1294
- query?: Q extends never ? never : Q;
1295
- body?: B extends never ? never : B;
1296
- response?: R extends never ? never : R;
1297
- };
1298
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
1299
- R
1300
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1301
- middleware?: Middleware[];
1302
- options?: Record<string, unknown>;
1303
- }) => {
1304
- PUT: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
1305
- path: string;
1306
- };
1081
+ declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
1082
+
1307
1083
  /**
1308
- * DELETE route creator with state and services support
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.
1309
1089
  */
1310
- type CreateDeleteRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
1311
- schema?: {
1312
- params?: P extends never ? never : P;
1313
- query?: Q extends never ? never : Q;
1314
- response?: R extends never ? never : R;
1315
- };
1316
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // DELETE never has body
1317
- [
1318
- R
1319
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1320
- middleware?: Middleware[];
1321
- options?: Record<string, unknown>;
1322
- }) => {
1323
- DELETE: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
1324
- path: string;
1325
- };
1326
1090
  /**
1327
- * PATCH route creator with state and services support
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
+ * ```
1328
1109
  */
1329
- type CreatePatchRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, B = never, R = never>(config: {
1330
- schema?: {
1331
- params?: P extends never ? never : P;
1332
- query?: Q extends never ? never : Q;
1333
- body?: B extends never ? never : B;
1334
- response?: R extends never ? never : R;
1335
- };
1336
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, B extends z.ZodType ? Infer<B> : unknown, [
1337
- R
1338
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1339
- middleware?: Middleware[];
1340
- options?: Record<string, unknown>;
1341
- }) => {
1342
- PATCH: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, B extends never ? never : B extends z.ZodType ? B : never, R extends never ? never : R extends z.ZodType ? R : never>;
1343
- path: string;
1344
- };
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
+ }
1345
1124
  /**
1346
- * HEAD route creator with state and services support
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.
1347
1129
  */
1348
- type CreateHeadRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
1349
- schema?: {
1350
- params?: P extends never ? never : P;
1351
- query?: Q extends never ? never : Q;
1352
- response?: R extends never ? never : R;
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;
1353
1151
  };
1354
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // HEAD never has body
1355
- [
1356
- R
1357
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1358
- middleware?: Middleware[];
1359
- options?: Record<string, unknown>;
1360
- }) => {
1361
- HEAD: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
1362
- path: string;
1363
- };
1152
+ }
1364
1153
  /**
1365
- * OPTIONS route creator with state and services support
1154
+ * Context information for request timeout errors
1155
+ *
1156
+ * Specialized context for timeout-specific errors with timing information.
1366
1157
  */
1367
- type CreateOptionsRoute = <TState extends State = State, TServices extends Services = Services>() => <P = never, Q = never, R = never>(config: {
1368
- schema?: {
1369
- params?: P extends never ? never : P;
1370
- query?: Q extends never ? never : Q;
1371
- response?: R extends never ? never : R;
1372
- };
1373
- handler: RouteHandler<P extends z.ZodType ? Infer<P> : Record<string, string>, Q extends z.ZodType ? Infer<Q> : QueryParams, never, // OPTIONS never has body
1374
- [
1375
- R
1376
- ] extends [never] ? void : R extends z.ZodType ? Infer<R> : void, TState, TServices>;
1377
- middleware?: Middleware[];
1378
- options?: Record<string, unknown>;
1379
- }) => {
1380
- OPTIONS: RouteMethodOptions<P extends never ? never : P extends z.ZodType ? P : never, Q extends never ? never : Q extends z.ZodType ? Q : never, never, R extends never ? never : R extends z.ZodType ? R : never>;
1381
- path: string;
1382
- };
1383
-
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
+ }
1384
1172
  /**
1385
- * Compose multiple middleware functions into a single middleware function
1173
+ * Context information for response parsing errors
1174
+ *
1175
+ * Used when the client receives a response but cannot parse it properly.
1386
1176
  */
1387
- declare function compose(middlewareStack: Middleware[]): MiddlewareFunction;
1388
-
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
+ }
1389
1195
  /**
1390
- * CORS Types for BlaizeJS Framework
1391
- *
1392
- * Comprehensive type definitions for W3C-compliant CORS middleware
1393
- * with support for string, regex, and async function origin validation.
1196
+ * Validation error field details
1394
1197
  *
1395
- * @module @blaizejs/types/cors
1198
+ * Structure for field-level validation errors with multiple error messages
1199
+ * per field.
1396
1200
  */
1397
-
1201
+ interface ValidationFieldError {
1202
+ /** Field name or path (e.g., "email", "user.profile.name") */
1203
+ field: string;
1204
+ /** Array of error messages for this field */
1205
+ messages: string[];
1206
+ /** The invalid value that caused the error */
1207
+ rejectedValue?: unknown;
1208
+ /** Expected type or format */
1209
+ expectedType?: string;
1210
+ }
1211
+ interface ServiceNotAvailableDetails {
1212
+ /** Service that's unavailable */
1213
+ service?: string;
1214
+ /** Seconds to wait before retry */
1215
+ retryAfter?: number;
1216
+ /** Why service is unavailable */
1217
+ reason?: 'maintenance' | 'overload' | 'circuit_breaker' | 'dependency_down';
1218
+ /** Additional context */
1219
+ [key: string]: unknown;
1220
+ }
1398
1221
  /**
1399
- * Origin configuration type supporting multiple validation methods
1400
- *
1401
- * @example
1402
- * ```typescript
1403
- * // String origin (exact match)
1404
- * const origin: CorsOrigin = 'https://example.com';
1222
+ * Validation error details structure
1405
1223
  *
1406
- * // RegExp pattern
1407
- * const origin: CorsOrigin = /^https:\/\/.*\.example\.com$/;
1224
+ * Used by ValidationError to provide structured information about
1225
+ * what fields failed validation and why.
1226
+ */
1227
+ interface ValidationErrorDetails {
1228
+ /** Array of field-level errors */
1229
+ fields: ValidationFieldError[];
1230
+ /** Total number of validation errors */
1231
+ errorCount: number;
1232
+ /** The section that failed validation */
1233
+ section: 'params' | 'query' | 'body' | 'response';
1234
+ /** Schema name if available */
1235
+ schemaName?: string;
1236
+ }
1237
+ /**
1238
+ * All available error types in the BlaizeJS framework
1408
1239
  *
1409
- * // Dynamic validation function
1410
- * const origin: CorsOrigin = async (origin, ctx) => {
1411
- * return await checkOriginAllowed(origin, ctx?.state.user);
1412
- * };
1240
+ * This enum provides both compile-time type safety and runtime values
1241
+ * for error type identification across server and client packages.
1413
1242
  *
1414
- * // Array of mixed types
1415
- * const origin: CorsOrigin = [
1416
- * 'https://localhost:3000',
1417
- * /^https:\/\/.*\.example\.com$/,
1418
- * (origin) => origin.endsWith('.trusted.com')
1419
- * ];
1243
+ * @example Type-safe error handling:
1244
+ * ```typescript
1245
+ * function handleError(errorType: ErrorType) {
1246
+ * switch (errorType) {
1247
+ * case ErrorType.VALIDATION_ERROR:
1248
+ * // Handle validation error
1249
+ * break;
1250
+ * case ErrorType.NOT_FOUND:
1251
+ * // Handle not found error
1252
+ * break;
1253
+ * // TypeScript ensures all cases are covered
1254
+ * }
1255
+ * }
1420
1256
  * ```
1421
1257
  */
1422
- 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>)>;
1258
+ declare enum ErrorType {
1259
+ /** Request validation failed (400) */
1260
+ VALIDATION_ERROR = "VALIDATION_ERROR",
1261
+ /** Resource not found (404) */
1262
+ NOT_FOUND = "NOT_FOUND",
1263
+ /** Authentication required (401) */
1264
+ UNAUTHORIZED = "UNAUTHORIZED",
1265
+ /** Access forbidden (403) */
1266
+ FORBIDDEN = "FORBIDDEN",
1267
+ /** SSE Not Acceptable (406) */
1268
+ SSE_NOT_ACCEPTABLE = "SSE_NOT_ACCEPTABLE",
1269
+ /** Resource conflict (409) */
1270
+ CONFLICT = "CONFLICT",
1271
+ /** Rate limit exceeded (429) */
1272
+ RATE_LIMITED = "RATE_LIMITED",
1273
+ /** Internal server error (500) */
1274
+ INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR",
1275
+ /** File/Request Too Large (413) */
1276
+ PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
1277
+ /** Wrong Content Type (415) */
1278
+ UNSUPPORTED_MEDIA_TYPE = "UNSUPPORTED_MEDIA_TYPE",
1279
+ /** Upload Timeout (408) */
1280
+ UPLOAD_TIMEOUT = "UPLOAD_TIMEOUT",
1281
+ /** Valid Format Invalid Semantics (422) */
1282
+ UNPROCESSABLE_ENTITY = "UNPROCESSABLE_ENTITY",
1283
+ /** Network connectivity failure (0) */
1284
+ NETWORK_ERROR = "NETWORK_ERROR",
1285
+ /** Request or response timeout (0) */
1286
+ TIMEOUT_ERROR = "TIMEOUT_ERROR",
1287
+ /** Response parsing failure (0) */
1288
+ PARSE_ERROR = "PARSE_ERROR",
1289
+ /** Generic HTTP error (varies) */
1290
+ HTTP_ERROR = "HTTP_ERROR",
1291
+ /** SSE connection failed (502) */
1292
+ SSE_CONNECTION_ERROR = "SSE_CONNECTION_ERROR",
1293
+ /** SSE buffer overflow (503) */
1294
+ SSE_BUFFER_OVERFLOW = "SSE_BUFFER_OVERFLOW",
1295
+ /** SSE stream closed (410) */
1296
+ SSE_STREAM_CLOSED = "SSE_STREAM_CLOSED",
1297
+ /** Service temporarily unavailable (503) */
1298
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"
1299
+ }
1423
1300
  /**
1424
- * HTTP methods that can be allowed in CORS
1425
- * Based on W3C CORS specification
1301
+ * Error severity levels for logging and monitoring
1302
+ *
1303
+ * Provides a way to categorize errors by their impact and urgency.
1426
1304
  */
1427
- type CorsHttpMethod = HttpMethod | 'CONNECT' | 'TRACE';
1305
+ declare enum ErrorSeverity {
1306
+ /** Low impact, often user errors */
1307
+ LOW = "low",
1308
+ /** Medium impact, application errors */
1309
+ MEDIUM = "medium",
1310
+ /** High impact, system errors */
1311
+ HIGH = "high",
1312
+ /** Critical impact, service disruption */
1313
+ CRITICAL = "critical"
1314
+ }
1428
1315
  /**
1429
- * Main CORS configuration options
1316
+ * Abstract base class for all BlaizeJS errors
1317
+ *
1318
+ * This class provides the foundation for all error types in the BlaizeJS framework.
1319
+ * It extends JavaScript's built-in Error class and adds framework-specific properties
1320
+ * for consistent error handling across server and client.
1430
1321
  *
1431
1322
  * @example
1432
1323
  * ```typescript
1433
- * const corsOptions: CorsOptions = {
1434
- * origin: 'https://example.com',
1435
- * methods: ['GET', 'POST'],
1436
- * credentials: true,
1437
- * maxAge: 86400
1438
- * };
1324
+ * import { ErrorType } from './types';
1325
+ *
1326
+ * class NotFoundError extends BlaizeError<{ resourceId: string }> {
1327
+ * constructor(message = 'Resource not found', details?: { resourceId: string }) {
1328
+ * super(ErrorType.NOT_FOUND, message, 404, getCurrentCorrelationId(), details);
1329
+ * }
1330
+ * }
1439
1331
  * ```
1332
+ *
1333
+ * @template TDetails - Type for error-specific details object
1440
1334
  */
1441
- interface CorsOptions {
1335
+ declare abstract class BlaizeError<TDetails = unknown> extends Error {
1442
1336
  /**
1443
- * Configures the Access-Control-Allow-Origin header
1444
- *
1445
- * Possible values:
1446
- * - `true`: Allow all origins (sets to '*' unless credentials is true, then reflects origin)
1447
- * - `false`: Disable CORS (no headers set)
1448
- * - `string`: Specific origin to allow
1449
- * - `RegExp`: Pattern to match origins
1450
- * - `function`: Custom validation logic
1451
- * - `array`: Multiple origin configurations
1452
- *
1453
- * @default false
1337
+ * Error type identifier from the ErrorType enum
1338
+ * Used for programmatic error handling and client-side error routing
1454
1339
  */
1455
- origin?: boolean | CorsOrigin;
1340
+ readonly type: ErrorType;
1456
1341
  /**
1457
- * Configures the Access-Control-Allow-Methods header
1458
- *
1459
- * @default ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
1460
- * @example ['GET', 'POST']
1342
+ * Human-readable error title/message
1343
+ * Should be descriptive enough for debugging but safe for end users
1461
1344
  */
1462
- methods?: CorsHttpMethod[] | string;
1345
+ readonly title: string;
1463
1346
  /**
1464
- * Configures the Access-Control-Allow-Headers header
1465
- *
1466
- * Pass an array of allowed headers or a comma-delimited string.
1467
- *
1468
- * @default Request's Access-Control-Request-Headers header value
1469
- * @example ['Content-Type', 'Authorization']
1347
+ * HTTP status code associated with this error
1348
+ * Used by the error boundary to set appropriate response status
1470
1349
  */
1471
- allowedHeaders?: string[] | string;
1350
+ readonly status: number;
1472
1351
  /**
1473
- * Configures the Access-Control-Expose-Headers header
1474
- *
1475
- * Headers that the browser is allowed to access.
1476
- *
1477
- * @default []
1478
- * @example ['Content-Range', 'X-Content-Range']
1352
+ * Correlation ID for request tracing
1353
+ * Links this error to the specific request that generated it
1479
1354
  */
1480
- exposedHeaders?: string[] | string;
1355
+ readonly correlationId: string;
1481
1356
  /**
1482
- * Configures the Access-Control-Allow-Credentials header
1483
- *
1484
- * Set to true to allow credentials (cookies, authorization headers, TLS client certificates).
1485
- * Note: Cannot be used with origin: '*' for security reasons.
1486
- *
1487
- * @default false
1357
+ * Timestamp when the error occurred
1358
+ * Useful for debugging and log correlation
1488
1359
  */
1489
- credentials?: boolean;
1360
+ readonly timestamp: Date;
1490
1361
  /**
1491
- * Configures the Access-Control-Max-Age header in seconds
1492
- *
1493
- * Indicates how long browsers can cache preflight response.
1494
- * Set to -1 to disable caching.
1495
- *
1496
- * @default undefined (browser decides)
1497
- * @example 86400 // 24 hours
1362
+ * Additional error-specific details
1363
+ * Type-safe error context that varies by error type
1498
1364
  */
1499
- maxAge?: number;
1365
+ readonly details?: TDetails | undefined;
1500
1366
  /**
1501
- * Whether to pass the CORS preflight response to the next handler
1502
- *
1503
- * When false, the preflight response is sent immediately.
1504
- * When true, control passes to the next middleware/handler.
1367
+ * Creates a new BlaizeError instance
1505
1368
  *
1506
- * @default false
1369
+ * @param type - Error type from the ErrorType enum
1370
+ * @param title - Human-readable error message
1371
+ * @param status - HTTP status code
1372
+ * @param correlationId - Request correlation ID for tracing
1373
+ * @param details - Optional error-specific details
1507
1374
  */
1508
- preflightContinue?: boolean;
1375
+ protected constructor(type: ErrorType, title: string, status: number, correlationId: string, details?: TDetails | undefined);
1509
1376
  /**
1510
- * HTTP status code for successful OPTIONS requests
1511
- *
1512
- * Some legacy browsers require 200, while 204 is more correct.
1377
+ * Serializes the error to a plain object suitable for HTTP responses
1513
1378
  *
1514
- * @default 204
1379
+ * @returns Object representation of the error
1515
1380
  */
1516
- optionsSuccessStatus?: number;
1381
+ toJSON(): {
1382
+ type: ErrorType;
1383
+ title: string;
1384
+ status: number;
1385
+ correlationId: string;
1386
+ timestamp: string;
1387
+ } | {
1388
+ details: TDetails & ({} | null);
1389
+ type: ErrorType;
1390
+ title: string;
1391
+ status: number;
1392
+ correlationId: string;
1393
+ timestamp: string;
1394
+ };
1395
+ /**
1396
+ * Returns a string representation of the error
1397
+ * Includes correlation ID for easier debugging
1398
+ */
1399
+ toString(): string;
1517
1400
  }
1518
1401
  /**
1519
- * Internal CORS validation result
1520
- * Used by middleware implementation
1402
+ * Interface for payload too large error details
1521
1403
  */
1522
- interface CorsValidationResult {
1523
- /**
1524
- * Whether the origin is allowed
1525
- */
1526
- allowed: boolean;
1527
- /**
1528
- * The origin value to set in the header
1529
- * Can be '*', specific origin, or 'null'
1530
- */
1531
- origin?: string;
1532
- /**
1533
- * Whether to add Vary: Origin header
1534
- */
1535
- vary?: boolean;
1404
+ interface PayloadTooLargeErrorDetails {
1405
+ fileCount?: number;
1406
+ maxFiles?: number;
1407
+ filename?: string;
1408
+ field?: string;
1409
+ contentType?: string;
1410
+ currentSize?: number;
1411
+ maxSize?: number;
1536
1412
  }
1537
1413
  /**
1538
- * CORS preflight request information
1539
- * Extracted from OPTIONS request headers
1414
+ * Interface for unsupported media type error details
1540
1415
  */
1541
- interface CorsPreflightInfo {
1542
- /**
1543
- * The origin making the request
1544
- */
1545
- origin?: string;
1546
- /**
1547
- * The method that will be used in the actual request
1548
- * From Access-Control-Request-Method header
1549
- */
1550
- requestedMethod?: string;
1551
- /**
1552
- * The headers that will be sent in the actual request
1553
- * From Access-Control-Request-Headers header
1554
- */
1555
- requestedHeaders?: string[];
1416
+ interface UnsupportedMediaTypeErrorDetails {
1417
+ receivedMimeType?: string;
1418
+ allowedMimeTypes?: string[];
1419
+ filename?: string;
1420
+ }
1421
+ /**
1422
+ * Interface for authentication error details
1423
+ */
1424
+ interface UnauthorizedErrorDetails {
1425
+ /** Reason for authentication failure */
1426
+ reason?: 'missing_token' | 'invalid_token' | 'expired_token' | 'malformed_token' | 'insufficient_scope' | string;
1427
+ /** Authentication scheme (Bearer, Basic, etc.) */
1428
+ authScheme?: string;
1429
+ /** Authentication realm */
1430
+ realm?: string;
1431
+ /** Detailed error description */
1432
+ error_description?: string;
1433
+ /** Required scopes or permissions */
1434
+ requiredScopes?: string[];
1435
+ /** Login URL for interactive authentication */
1436
+ loginUrl?: string;
1437
+ /** Additional context */
1438
+ [key: string]: unknown;
1439
+ }
1440
+ /**
1441
+ * Interface for authorization/permission error details
1442
+ */
1443
+ interface ForbiddenErrorDetails {
1444
+ /** Required permission or role */
1445
+ requiredPermission?: string;
1446
+ /** User's current permissions */
1447
+ userPermissions?: string[];
1448
+ /** Resource being accessed */
1449
+ resource?: string;
1450
+ /** Action being attempted */
1451
+ action?: string;
1452
+ /** Reason for access denial */
1453
+ reason?: 'insufficient_permissions' | 'account_suspended' | 'resource_locked' | 'origin_not_allowed' | string;
1454
+ /** Additional context */
1455
+ [key: string]: unknown;
1456
+ }
1457
+ /**
1458
+ * Interface for resource conflict error details
1459
+ */
1460
+ interface ConflictErrorDetails {
1461
+ /** Type of conflict */
1462
+ conflictType?: 'duplicate_key' | 'version_mismatch' | 'concurrent_modification' | 'business_rule' | string;
1463
+ /** Field that caused the conflict */
1464
+ field?: string;
1465
+ /** Existing value that conflicts */
1466
+ existingValue?: unknown;
1467
+ /** Provided value that conflicts */
1468
+ providedValue?: unknown;
1469
+ /** Resource that has the conflicting value */
1470
+ conflictingResource?: string;
1471
+ /** Current version/etag of the resource */
1472
+ currentVersion?: string;
1473
+ /** Expected version/etag */
1474
+ expectedVersion?: string;
1475
+ /** Suggested resolution */
1476
+ resolution?: string;
1477
+ /** Additional context */
1478
+ [key: string]: unknown;
1479
+ }
1480
+ /**
1481
+ * Interface for rate limiting error details
1482
+ */
1483
+ interface RateLimitErrorDetails {
1484
+ /** Maximum requests allowed in the time window */
1485
+ limit?: number;
1486
+ /** Remaining requests in current window */
1487
+ remaining?: number;
1488
+ /** When the rate limit resets */
1489
+ resetTime?: Date;
1490
+ /** Seconds until the rate limit resets */
1491
+ retryAfter?: number;
1492
+ /** Time window for the rate limit */
1493
+ window?: string;
1494
+ /** Identifier used for rate limiting (IP, user ID, etc.) */
1495
+ identifier?: string;
1496
+ /** Type of rate limit hit */
1497
+ limitType?: 'global' | 'per_user' | 'per_ip' | 'per_endpoint' | string;
1498
+ /** Additional context */
1499
+ [key: string]: unknown;
1500
+ }
1501
+ /**
1502
+ * Interface for internal server error details
1503
+ */
1504
+ interface InternalServerErrorDetails {
1505
+ /** Original error message (for debugging) */
1506
+ originalError?: string;
1507
+ /** Stack trace (for debugging) */
1508
+ stackTrace?: string;
1509
+ /** Component where the error occurred */
1510
+ component?: string;
1511
+ /** Operation being performed */
1512
+ operation?: string;
1513
+ /** Internal error code */
1514
+ internalErrorCode?: string;
1515
+ /** When the error occurred */
1516
+ timestamp?: Date;
1517
+ /** Whether this error should be retryable */
1518
+ retryable?: boolean;
1519
+ /** Additional debugging context */
1520
+ [key: string]: unknown;
1556
1521
  }
1557
1522
  /**
1558
- * Cache entry for origin validation results
1559
- * Used for performance optimization
1523
+ * Interface for NotFound error details
1524
+ * Provides context about the missing resource
1560
1525
  */
1561
- interface CorsOriginCacheEntry {
1562
- /**
1563
- * Whether the origin is allowed
1564
- */
1565
- allowed: boolean;
1566
- /**
1567
- * When this cache entry expires (timestamp)
1568
- */
1569
- expiresAt: number;
1570
- /**
1571
- * Optional user identifier for cache key
1572
- */
1573
- userId?: string;
1526
+ interface NotFoundErrorDetails {
1527
+ /** Type of resource that was not found */
1528
+ resourceType?: string;
1529
+ /** ID or identifier of the resource */
1530
+ resourceId?: string;
1531
+ /** Collection or table where the resource was searched */
1532
+ collection?: string;
1533
+ /** Search criteria that was used */
1534
+ query?: Record<string, unknown>;
1535
+ /** Search criteria that was used (for backward compatibility) */
1536
+ searchCriteria?: Record<string, unknown>;
1537
+ /** The path that was attempted */
1538
+ path?: string;
1539
+ /** HTTP method used (for API endpoints) */
1540
+ method?: string;
1541
+ /** The path that was attempted (for backward compatibility) */
1542
+ attemptedPath?: string;
1543
+ /** Parent resource information for nested resources */
1544
+ parentResource?: {
1545
+ type: string;
1546
+ id: string;
1547
+ };
1548
+ /** Helpful suggestion for the user */
1549
+ suggestion?: string;
1550
+ /** Additional context */
1551
+ [key: string]: unknown;
1574
1552
  }
1575
1553
  /**
1576
- * Configuration for CORS origin validation cache
1554
+ * Context information for error transformation
1577
1555
  */
1578
- interface CorsOriginCacheConfig {
1579
- /**
1580
- * Time-to-live for cache entries in milliseconds
1581
- * @default 60000 (1 minute)
1582
- */
1583
- ttl?: number;
1584
- /**
1585
- * Maximum number of entries in the cache
1586
- * @default 1000
1587
- */
1588
- maxSize?: number;
1589
- /**
1590
- * Whether to include user ID in cache key
1591
- * @default true
1592
- */
1593
- includeUserId?: boolean;
1556
+ interface ErrorTransformContext {
1557
+ url: string;
1558
+ method: string;
1559
+ correlationId: string;
1560
+ timeoutMs?: number;
1561
+ elapsedMs?: number;
1562
+ statusCode?: number;
1563
+ contentType?: string;
1564
+ responseSample?: string;
1565
+ [key: string]: unknown;
1594
1566
  }
1595
1567
  /**
1596
- * Statistics for CORS middleware performance monitoring
1568
+ * SSE-specific error detail interfaces for BlaizeJS framework
1569
+ *
1570
+ * These interfaces define the structure of details for SSE errors.
1571
+ * The actual error classes are implemented in blaize-core.
1597
1572
  */
1598
- interface CorsStats {
1599
- /**
1600
- * Total number of CORS requests processed
1601
- */
1602
- totalRequests: number;
1603
- /**
1604
- * Number of preflight requests handled
1605
- */
1606
- preflightRequests: number;
1607
- /**
1608
- * Number of allowed origins
1609
- */
1610
- allowedOrigins: number;
1611
- /**
1612
- * Number of denied origins
1613
- */
1614
- deniedOrigins: number;
1615
- /**
1616
- * Cache hit rate for origin validation
1617
- */
1618
- cacheHitRate: number;
1619
- /**
1620
- * Average origin validation time in milliseconds
1621
- */
1622
- avgValidationTime: number;
1623
- }
1624
1573
  /**
1625
- * Cache entry type
1574
+ * Details for SSE connection errors
1626
1575
  */
1627
- interface CacheEntry {
1628
- allowed: boolean;
1629
- expiresAt: number;
1630
- lastAccessed: number;
1576
+ interface SSEConnectionErrorDetails {
1577
+ /** Client identifier if available */
1578
+ clientId?: string;
1579
+ /** Connection attempt number */
1580
+ attemptNumber?: number;
1581
+ /** Maximum retry attempts configured */
1582
+ maxRetries?: number;
1583
+ /** The underlying error that caused connection failure */
1584
+ cause?: string;
1585
+ /** Suggested resolution */
1586
+ suggestion?: string;
1631
1587
  }
1632
1588
  /**
1633
- * Cache configuration
1589
+ * Details for SSE buffer overflow errors
1634
1590
  */
1635
- interface CacheConfig {
1636
- ttl: number;
1591
+ interface SSEBufferOverflowErrorDetails {
1592
+ /** Client identifier */
1593
+ clientId?: string;
1594
+ /** Current buffer size when overflow occurred */
1595
+ currentSize: number;
1596
+ /** Maximum buffer size configured */
1637
1597
  maxSize: number;
1598
+ /** Number of events dropped */
1599
+ eventsDropped?: number;
1600
+ /** Buffer strategy that was applied */
1601
+ strategy: 'drop-oldest' | 'drop-newest' | 'close';
1602
+ /** Event that triggered the overflow */
1603
+ triggeringEvent?: string;
1638
1604
  }
1639
-
1640
1605
  /**
1641
- * Create CORS middleware with the specified options
1642
- *
1643
- * @param userOptions - CORS configuration options or boolean
1644
- * @returns Middleware function that handles CORS
1645
- *
1646
- * @example
1647
- * ```typescript
1648
- * import { cors } from '@blaize-core/middleware/cors';
1649
- *
1650
- * // Development mode - allow all origins
1651
- * server.use(cors(true));
1652
- *
1653
- * // Production - specific origin
1654
- * server.use(cors({
1655
- * origin: 'https://app.example.com',
1656
- * credentials: true,
1657
- * maxAge: 86400
1658
- * }));
1659
- *
1660
- * // Multiple origins with regex
1661
- * server.use(cors({
1662
- * origin: [
1663
- * 'https://app.example.com',
1664
- * /^https:\/\/.*\.example\.com$/
1665
- * ]
1666
- * }));
1667
- *
1668
- * // Dynamic origin validation
1669
- * server.use(cors({
1670
- * origin: async (origin, ctx) => {
1671
- * return await checkOriginAllowed(origin, ctx.state.user);
1672
- * }
1673
- * }));
1674
- * ```
1606
+ * Details for SSE stream closed errors
1675
1607
  */
1676
- declare function cors(userOptions?: CorsOptions | boolean): Middleware;
1677
-
1608
+ interface SSEStreamClosedErrorDetails {
1609
+ /** Client identifier */
1610
+ clientId?: string;
1611
+ /** When the stream was closed */
1612
+ closedAt?: string;
1613
+ /** Reason for closure */
1614
+ closeReason?: 'client-disconnect' | 'server-close' | 'timeout' | 'error' | 'buffer-overflow';
1615
+ /** Whether reconnection is possible */
1616
+ canReconnect?: boolean;
1617
+ /** Suggested retry interval in milliseconds */
1618
+ retryAfter?: number;
1619
+ }
1678
1620
  /**
1679
- * Create a middleware
1621
+ * Context for SSE connection errors
1680
1622
  */
1681
- declare function create$2<TState = {}, TServices = {}>(handlerOrOptions: MiddlewareFunction | MiddlewareOptions): Middleware<TState, TServices>;
1623
+ interface SSEConnectionErrorContext {
1624
+ /** The SSE endpoint URL */
1625
+ url: string;
1626
+ /** Correlation ID for tracing */
1627
+ correlationId: string;
1628
+ /** Connection state when error occurred */
1629
+ state: 'connecting' | 'connected' | 'disconnected' | 'closed';
1630
+ /** Number of reconnection attempts made */
1631
+ reconnectAttempts?: number;
1632
+ /** The original error if available */
1633
+ originalError?: Error;
1634
+ /** Additional SSE-specific details */
1635
+ sseDetails?: {
1636
+ /** Whether credentials were included */
1637
+ withCredentials?: boolean;
1638
+ /** Last received event ID */
1639
+ lastEventId?: string;
1640
+ /** EventSource ready state */
1641
+ readyState?: number;
1642
+ };
1643
+ }
1682
1644
  /**
1683
- * Create a middleware that only contributes state (no services)
1684
- * Convenience helper for state-only middleware
1685
- *
1686
- * @template T - Type of state to contribute
1687
- * @param handler - Middleware function that adds state
1688
- * @returns Middleware that contributes state only
1689
- *
1645
+ * Context for SSE stream errors (server-sent errors)
1690
1646
  */
1691
- declare function stateMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<T, {}>;
1647
+ interface SSEStreamErrorContext {
1648
+ /** The SSE endpoint URL */
1649
+ url: string;
1650
+ /** Correlation ID from server or client */
1651
+ correlationId: string;
1652
+ /** Error message from server */
1653
+ message: string;
1654
+ /** Error code if provided */
1655
+ code?: string;
1656
+ /** Error name/type from server */
1657
+ name?: string;
1658
+ /** Raw error data from server */
1659
+ rawData?: any;
1660
+ }
1692
1661
  /**
1693
- * Create a middleware that only contributes services (no state)
1694
- * Convenience helper for service-only middleware
1695
- *
1696
- * @template T - Type of services to contribute
1697
- * @param handler - Middleware function that adds services
1698
- * @returns Middleware that contributes services only
1699
- *
1662
+ * Context for SSE heartbeat timeout errors
1700
1663
  */
1701
- declare function serviceMiddleware<T = {}>(handler: MiddlewareFunction): Middleware<{}, T>;
1664
+ interface SSEHeartbeatErrorContext {
1665
+ /** The SSE endpoint URL */
1666
+ url: string;
1667
+ /** Correlation ID for tracing */
1668
+ correlationId: string;
1669
+ /** Configured heartbeat timeout in ms */
1670
+ heartbeatTimeout: number;
1671
+ /** Time since last event in ms */
1672
+ timeSinceLastEvent?: number;
1673
+ /** Last event ID received */
1674
+ lastEventId?: string;
1675
+ }
1702
1676
 
1703
1677
  /**
1704
1678
  * Represents a single Server-Sent Event
@@ -3430,4 +3404,4 @@ declare const Blaize: {
3430
3404
  VERSION: string;
3431
3405
  };
3432
3406
 
3433
- export { Blaize, BlaizeError, type BlaizeErrorResponse, type BodyLimits, type BodyParseError, 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 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$2 as createMiddleware, createMiddlewareArray, createOptionsRoute, createPatchRoute, create$1 as createPlugin, createPluginArray, createPostRoute, createPutRoute, createRouteFactory, create as createServer, serviceMiddleware as createServiceMiddleware, stateMiddleware as createStateMiddleware, extractParams, getCorrelationId, inferContext, isBodyParseError, isMiddleware, isPlugin, paramsToQuery };
3407
+ 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 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$2 as createMiddleware, createMiddlewareArray, createOptionsRoute, createPatchRoute, create$1 as createPlugin, createPluginArray, createPostRoute, createPutRoute, createRouteFactory, create as createServer, serviceMiddleware as createServiceMiddleware, stateMiddleware as createStateMiddleware, extractParams, getCorrelationId, inferContext, isMiddleware, isPlugin, paramsToQuery };