blaizejs 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-3A5J5MKL.js +38 -0
- package/dist/chunk-3A5J5MKL.js.map +1 -0
- package/dist/chunk-SF7ZGOEK.js +148 -0
- package/dist/chunk-SF7ZGOEK.js.map +1 -0
- package/dist/chunk-ZZEQFU5V.js +38 -0
- package/dist/chunk-ZZEQFU5V.js.map +1 -0
- package/dist/index.cjs +1075 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1283 -239
- package/dist/index.d.ts +1283 -239
- package/dist/index.js +800 -152
- package/dist/index.js.map +1 -1
- package/dist/internal-server-error-PKVC3ZEU.js +16 -0
- package/dist/internal-server-error-PKVC3ZEU.js.map +1 -0
- package/dist/payload-too-large-error-WZMDORKR.js +29 -0
- package/dist/payload-too-large-error-WZMDORKR.js.map +1 -0
- package/dist/unsupported-media-type-error-VUXOJ72O.js +29 -0
- package/dist/unsupported-media-type-error-VUXOJ72O.js.map +1 -0
- package/dist/validation-error-WZFF75S7.js +16 -0
- package/dist/validation-error-WZFF75S7.js.map +1 -0
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* blaizejs v0.
|
|
2
|
+
* blaizejs v0.3.1
|
|
3
3
|
* A blazing-fast, TypeScript-first Node.js framework with HTTP/2 support, file-based routing, powerful middleware system, and end-to-end type safety for building modern APIs.
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) 2025 BlaizeJS Contributors
|
|
@@ -13,6 +13,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
13
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
14
|
var __getProtoOf = Object.getPrototypeOf;
|
|
15
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __esm = (fn, res) => function __init() {
|
|
17
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
18
|
+
};
|
|
16
19
|
var __export = (target, all) => {
|
|
17
20
|
for (var name in all)
|
|
18
21
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -35,15 +38,276 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
35
38
|
));
|
|
36
39
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
40
|
|
|
41
|
+
// ../blaize-types/src/errors.ts
|
|
42
|
+
function isBodyParseError(error) {
|
|
43
|
+
return typeof error === "object" && error !== null && "type" in error && "message" in error && "error" in error && typeof error.type === "string" && typeof error.message === "string";
|
|
44
|
+
}
|
|
45
|
+
var ErrorType, ErrorSeverity, BlaizeError;
|
|
46
|
+
var init_errors = __esm({
|
|
47
|
+
"../blaize-types/src/errors.ts"() {
|
|
48
|
+
"use strict";
|
|
49
|
+
ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
50
|
+
ErrorType2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
51
|
+
ErrorType2["NOT_FOUND"] = "NOT_FOUND";
|
|
52
|
+
ErrorType2["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
53
|
+
ErrorType2["FORBIDDEN"] = "FORBIDDEN";
|
|
54
|
+
ErrorType2["CONFLICT"] = "CONFLICT";
|
|
55
|
+
ErrorType2["RATE_LIMITED"] = "RATE_LIMITED";
|
|
56
|
+
ErrorType2["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
|
|
57
|
+
ErrorType2["PAYLOAD_TOO_LARGE"] = "PAYLOAD_TOO_LARGE";
|
|
58
|
+
ErrorType2["UNSUPPORTED_MEDIA_TYPE"] = "UNSUPPORTED_MEDIA_TYPE";
|
|
59
|
+
ErrorType2["UPLOAD_TIMEOUT"] = "UPLOAD_TIMEOUT";
|
|
60
|
+
ErrorType2["UNPROCESSABLE_ENTITY"] = "UNPROCESSABLE_ENTITY";
|
|
61
|
+
ErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
62
|
+
ErrorType2["TIMEOUT_ERROR"] = "TIMEOUT_ERROR";
|
|
63
|
+
ErrorType2["PARSE_ERROR"] = "PARSE_ERROR";
|
|
64
|
+
ErrorType2["HTTP_ERROR"] = "HTTP_ERROR";
|
|
65
|
+
return ErrorType2;
|
|
66
|
+
})(ErrorType || {});
|
|
67
|
+
ErrorSeverity = /* @__PURE__ */ ((ErrorSeverity2) => {
|
|
68
|
+
ErrorSeverity2["LOW"] = "low";
|
|
69
|
+
ErrorSeverity2["MEDIUM"] = "medium";
|
|
70
|
+
ErrorSeverity2["HIGH"] = "high";
|
|
71
|
+
ErrorSeverity2["CRITICAL"] = "critical";
|
|
72
|
+
return ErrorSeverity2;
|
|
73
|
+
})(ErrorSeverity || {});
|
|
74
|
+
BlaizeError = class extends Error {
|
|
75
|
+
/**
|
|
76
|
+
* Error type identifier from the ErrorType enum
|
|
77
|
+
* Used for programmatic error handling and client-side error routing
|
|
78
|
+
*/
|
|
79
|
+
type;
|
|
80
|
+
/**
|
|
81
|
+
* Human-readable error title/message
|
|
82
|
+
* Should be descriptive enough for debugging but safe for end users
|
|
83
|
+
*/
|
|
84
|
+
title;
|
|
85
|
+
/**
|
|
86
|
+
* HTTP status code associated with this error
|
|
87
|
+
* Used by the error boundary to set appropriate response status
|
|
88
|
+
*/
|
|
89
|
+
status;
|
|
90
|
+
/**
|
|
91
|
+
* Correlation ID for request tracing
|
|
92
|
+
* Links this error to the specific request that generated it
|
|
93
|
+
*/
|
|
94
|
+
correlationId;
|
|
95
|
+
/**
|
|
96
|
+
* Timestamp when the error occurred
|
|
97
|
+
* Useful for debugging and log correlation
|
|
98
|
+
*/
|
|
99
|
+
timestamp;
|
|
100
|
+
/**
|
|
101
|
+
* Additional error-specific details
|
|
102
|
+
* Type-safe error context that varies by error type
|
|
103
|
+
*/
|
|
104
|
+
details;
|
|
105
|
+
/**
|
|
106
|
+
* Creates a new BlaizeError instance
|
|
107
|
+
*
|
|
108
|
+
* @param type - Error type from the ErrorType enum
|
|
109
|
+
* @param title - Human-readable error message
|
|
110
|
+
* @param status - HTTP status code
|
|
111
|
+
* @param correlationId - Request correlation ID for tracing
|
|
112
|
+
* @param details - Optional error-specific details
|
|
113
|
+
*/
|
|
114
|
+
constructor(type, title, status, correlationId, details) {
|
|
115
|
+
super(title);
|
|
116
|
+
this.name = this.constructor.name;
|
|
117
|
+
this.type = type;
|
|
118
|
+
this.title = title;
|
|
119
|
+
this.status = status;
|
|
120
|
+
this.correlationId = correlationId;
|
|
121
|
+
this.timestamp = /* @__PURE__ */ new Date();
|
|
122
|
+
this.details = details;
|
|
123
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
124
|
+
if (Error.captureStackTrace) {
|
|
125
|
+
Error.captureStackTrace(this, this.constructor);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Serializes the error to a plain object suitable for HTTP responses
|
|
130
|
+
*
|
|
131
|
+
* @returns Object representation of the error
|
|
132
|
+
*/
|
|
133
|
+
toJSON() {
|
|
134
|
+
const base = {
|
|
135
|
+
type: this.type,
|
|
136
|
+
title: this.title,
|
|
137
|
+
status: this.status,
|
|
138
|
+
correlationId: this.correlationId,
|
|
139
|
+
timestamp: this.timestamp.toISOString()
|
|
140
|
+
};
|
|
141
|
+
if (this.details !== void 0) {
|
|
142
|
+
return { ...base, details: this.details };
|
|
143
|
+
}
|
|
144
|
+
return base;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns a string representation of the error
|
|
148
|
+
* Includes correlation ID for easier debugging
|
|
149
|
+
*/
|
|
150
|
+
toString() {
|
|
151
|
+
return `${this.name}: ${this.title} [${this.correlationId}]`;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// src/errors/correlation.ts
|
|
158
|
+
function generateCorrelationId() {
|
|
159
|
+
const timestamp = Date.now().toString(36);
|
|
160
|
+
const random = Math.random().toString(36).substr(2, 9);
|
|
161
|
+
return `req_${timestamp}_${random}`;
|
|
162
|
+
}
|
|
163
|
+
function getCurrentCorrelationId() {
|
|
164
|
+
const stored = correlationStorage.getStore();
|
|
165
|
+
return stored && stored.trim() ? stored : "unknown";
|
|
166
|
+
}
|
|
167
|
+
var import_node_async_hooks2, correlationStorage;
|
|
168
|
+
var init_correlation = __esm({
|
|
169
|
+
"src/errors/correlation.ts"() {
|
|
170
|
+
"use strict";
|
|
171
|
+
import_node_async_hooks2 = require("async_hooks");
|
|
172
|
+
correlationStorage = new import_node_async_hooks2.AsyncLocalStorage();
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// src/errors/internal-server-error.ts
|
|
177
|
+
var internal_server_error_exports = {};
|
|
178
|
+
__export(internal_server_error_exports, {
|
|
179
|
+
InternalServerError: () => InternalServerError
|
|
180
|
+
});
|
|
181
|
+
var InternalServerError;
|
|
182
|
+
var init_internal_server_error = __esm({
|
|
183
|
+
"src/errors/internal-server-error.ts"() {
|
|
184
|
+
"use strict";
|
|
185
|
+
init_errors();
|
|
186
|
+
init_correlation();
|
|
187
|
+
InternalServerError = class extends BlaizeError {
|
|
188
|
+
/**
|
|
189
|
+
* Creates a new InternalServerError instance
|
|
190
|
+
*
|
|
191
|
+
* @param title - Human-readable error message
|
|
192
|
+
* @param details - Optional debugging context
|
|
193
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
194
|
+
*/
|
|
195
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
196
|
+
super(
|
|
197
|
+
"INTERNAL_SERVER_ERROR" /* INTERNAL_SERVER_ERROR */,
|
|
198
|
+
title,
|
|
199
|
+
500,
|
|
200
|
+
// HTTP 500 Internal Server Error
|
|
201
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
202
|
+
details
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// src/errors/validation-error.ts
|
|
210
|
+
var validation_error_exports = {};
|
|
211
|
+
__export(validation_error_exports, {
|
|
212
|
+
ValidationError: () => ValidationError
|
|
213
|
+
});
|
|
214
|
+
var ValidationError;
|
|
215
|
+
var init_validation_error = __esm({
|
|
216
|
+
"src/errors/validation-error.ts"() {
|
|
217
|
+
"use strict";
|
|
218
|
+
init_errors();
|
|
219
|
+
init_correlation();
|
|
220
|
+
ValidationError = class extends BlaizeError {
|
|
221
|
+
/**
|
|
222
|
+
* Creates a new ValidationError instance
|
|
223
|
+
*
|
|
224
|
+
* @param title - Human-readable error message
|
|
225
|
+
* @param details - Optional structured validation details
|
|
226
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
227
|
+
*/
|
|
228
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
229
|
+
super(
|
|
230
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
231
|
+
title,
|
|
232
|
+
400,
|
|
233
|
+
// HTTP 400 Bad Request
|
|
234
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
235
|
+
details
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// src/errors/payload-too-large-error.ts
|
|
243
|
+
var payload_too_large_error_exports = {};
|
|
244
|
+
__export(payload_too_large_error_exports, {
|
|
245
|
+
PayloadTooLargeError: () => PayloadTooLargeError
|
|
246
|
+
});
|
|
247
|
+
var PayloadTooLargeError;
|
|
248
|
+
var init_payload_too_large_error = __esm({
|
|
249
|
+
"src/errors/payload-too-large-error.ts"() {
|
|
250
|
+
"use strict";
|
|
251
|
+
init_correlation();
|
|
252
|
+
init_errors();
|
|
253
|
+
PayloadTooLargeError = class extends BlaizeError {
|
|
254
|
+
constructor(title, details, correlationId) {
|
|
255
|
+
super(
|
|
256
|
+
"PAYLOAD_TOO_LARGE" /* PAYLOAD_TOO_LARGE */,
|
|
257
|
+
title,
|
|
258
|
+
413,
|
|
259
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
260
|
+
details
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// src/errors/unsupported-media-type-error.ts
|
|
268
|
+
var unsupported_media_type_error_exports = {};
|
|
269
|
+
__export(unsupported_media_type_error_exports, {
|
|
270
|
+
UnsupportedMediaTypeError: () => UnsupportedMediaTypeError
|
|
271
|
+
});
|
|
272
|
+
var UnsupportedMediaTypeError;
|
|
273
|
+
var init_unsupported_media_type_error = __esm({
|
|
274
|
+
"src/errors/unsupported-media-type-error.ts"() {
|
|
275
|
+
"use strict";
|
|
276
|
+
init_correlation();
|
|
277
|
+
init_errors();
|
|
278
|
+
UnsupportedMediaTypeError = class extends BlaizeError {
|
|
279
|
+
constructor(title, details, correlationId) {
|
|
280
|
+
super(
|
|
281
|
+
"UNSUPPORTED_MEDIA_TYPE" /* UNSUPPORTED_MEDIA_TYPE */,
|
|
282
|
+
title,
|
|
283
|
+
415,
|
|
284
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
285
|
+
details
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
38
292
|
// src/index.ts
|
|
39
293
|
var index_exports = {};
|
|
40
294
|
__export(index_exports, {
|
|
41
295
|
Blaize: () => Blaize,
|
|
296
|
+
BlaizeError: () => BlaizeError,
|
|
297
|
+
ConflictError: () => ConflictError,
|
|
298
|
+
ErrorSeverity: () => ErrorSeverity,
|
|
299
|
+
ErrorType: () => ErrorType,
|
|
300
|
+
ForbiddenError: () => ForbiddenError,
|
|
301
|
+
InternalServerError: () => InternalServerError,
|
|
42
302
|
MiddlewareAPI: () => MiddlewareAPI,
|
|
303
|
+
NotFoundError: () => NotFoundError,
|
|
43
304
|
PluginsAPI: () => PluginsAPI,
|
|
305
|
+
RateLimitError: () => RateLimitError,
|
|
44
306
|
RouterAPI: () => RouterAPI,
|
|
45
307
|
ServerAPI: () => ServerAPI,
|
|
308
|
+
UnauthorizedError: () => UnauthorizedError,
|
|
46
309
|
VERSION: () => VERSION,
|
|
310
|
+
ValidationError: () => ValidationError,
|
|
47
311
|
compose: () => compose,
|
|
48
312
|
createDeleteRoute: () => createDeleteRoute,
|
|
49
313
|
createGetRoute: () => createGetRoute,
|
|
@@ -55,7 +319,8 @@ __export(index_exports, {
|
|
|
55
319
|
createPostRoute: () => createPostRoute,
|
|
56
320
|
createPutRoute: () => createPutRoute,
|
|
57
321
|
createServer: () => create3,
|
|
58
|
-
default: () => index_default
|
|
322
|
+
default: () => index_default,
|
|
323
|
+
isBodyParseError: () => isBodyParseError
|
|
59
324
|
});
|
|
60
325
|
module.exports = __toCommonJS(index_exports);
|
|
61
326
|
|
|
@@ -253,6 +518,7 @@ var createGetRoute = (config2) => {
|
|
|
253
518
|
const path6 = getRoutePath();
|
|
254
519
|
return {
|
|
255
520
|
GET: config2,
|
|
521
|
+
// Let TypeScript infer the proper types
|
|
256
522
|
path: path6
|
|
257
523
|
};
|
|
258
524
|
};
|
|
@@ -261,6 +527,7 @@ var createPostRoute = (config2) => {
|
|
|
261
527
|
const path6 = getRoutePath();
|
|
262
528
|
return {
|
|
263
529
|
POST: config2,
|
|
530
|
+
// Let TypeScript infer the proper types
|
|
264
531
|
path: path6
|
|
265
532
|
};
|
|
266
533
|
};
|
|
@@ -269,6 +536,7 @@ var createPutRoute = (config2) => {
|
|
|
269
536
|
const path6 = getRoutePath();
|
|
270
537
|
return {
|
|
271
538
|
PUT: config2,
|
|
539
|
+
// Let TypeScript infer the proper types
|
|
272
540
|
path: path6
|
|
273
541
|
};
|
|
274
542
|
};
|
|
@@ -277,6 +545,7 @@ var createDeleteRoute = (config2) => {
|
|
|
277
545
|
const path6 = getRoutePath();
|
|
278
546
|
return {
|
|
279
547
|
DELETE: config2,
|
|
548
|
+
// Let TypeScript infer the proper types
|
|
280
549
|
path: path6
|
|
281
550
|
};
|
|
282
551
|
};
|
|
@@ -285,6 +554,7 @@ var createPatchRoute = (config2) => {
|
|
|
285
554
|
const path6 = getRoutePath();
|
|
286
555
|
return {
|
|
287
556
|
PATCH: config2,
|
|
557
|
+
// Let TypeScript infer the proper types
|
|
288
558
|
path: path6
|
|
289
559
|
};
|
|
290
560
|
};
|
|
@@ -293,6 +563,7 @@ var createHeadRoute = (config2) => {
|
|
|
293
563
|
const path6 = getRoutePath();
|
|
294
564
|
return {
|
|
295
565
|
HEAD: config2,
|
|
566
|
+
// Let TypeScript infer the proper types
|
|
296
567
|
path: path6
|
|
297
568
|
};
|
|
298
569
|
};
|
|
@@ -301,6 +572,7 @@ var createOptionsRoute = (config2) => {
|
|
|
301
572
|
const path6 = getRoutePath();
|
|
302
573
|
return {
|
|
303
574
|
OPTIONS: config2,
|
|
575
|
+
// Let TypeScript infer the proper types
|
|
304
576
|
path: path6
|
|
305
577
|
};
|
|
306
578
|
};
|
|
@@ -341,7 +613,7 @@ function validateSchema(method, schema) {
|
|
|
341
613
|
}
|
|
342
614
|
|
|
343
615
|
// src/server/create.ts
|
|
344
|
-
var
|
|
616
|
+
var import_node_async_hooks3 = require("async_hooks");
|
|
345
617
|
var import_node_events = __toESM(require("events"), 1);
|
|
346
618
|
|
|
347
619
|
// src/server/start.ts
|
|
@@ -437,8 +709,474 @@ function runWithContext(context, callback) {
|
|
|
437
709
|
return contextStorage.run(context, callback);
|
|
438
710
|
}
|
|
439
711
|
|
|
712
|
+
// src/upload/multipart-parser.ts
|
|
713
|
+
var import_node_crypto = require("crypto");
|
|
714
|
+
var import_node_fs = require("fs");
|
|
715
|
+
var import_node_os = require("os");
|
|
716
|
+
var import_node_path = require("path");
|
|
717
|
+
var import_node_stream = require("stream");
|
|
718
|
+
|
|
719
|
+
// src/upload/utils.ts
|
|
720
|
+
var BOUNDARY_REGEX = /boundary=([^;]+)/i;
|
|
721
|
+
var CONTENT_DISPOSITION_REGEX = /Content-Disposition:\s*form-data;\s*name="([^"]+)"(?:;[\s\r\n]*filename="([^"]*)")?/i;
|
|
722
|
+
var CONTENT_TYPE_REGEX = /Content-Type:\s*([^\r\n]+)/i;
|
|
723
|
+
var MULTIPART_REGEX = /multipart\/form-data/i;
|
|
724
|
+
function extractBoundary(contentType) {
|
|
725
|
+
const match = contentType.match(BOUNDARY_REGEX);
|
|
726
|
+
if (!match || !match[1]) return null;
|
|
727
|
+
let boundary = match[1].trim();
|
|
728
|
+
if (boundary.startsWith('"') && boundary.endsWith('"')) {
|
|
729
|
+
boundary = boundary.slice(1, -1);
|
|
730
|
+
}
|
|
731
|
+
return boundary || null;
|
|
732
|
+
}
|
|
733
|
+
function parseContentDisposition(headers) {
|
|
734
|
+
const match = headers.match(CONTENT_DISPOSITION_REGEX);
|
|
735
|
+
if (!match || !match[1]) return null;
|
|
736
|
+
return {
|
|
737
|
+
name: match[1],
|
|
738
|
+
filename: match[2] !== void 0 ? match[2] : void 0
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function parseContentType(headers) {
|
|
742
|
+
const match = headers.match(CONTENT_TYPE_REGEX);
|
|
743
|
+
return match && match[1]?.trim() ? match[1].trim() : "application/octet-stream";
|
|
744
|
+
}
|
|
745
|
+
function isMultipartContent(contentType) {
|
|
746
|
+
return MULTIPART_REGEX.test(contentType);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/upload/multipart-parser.ts
|
|
750
|
+
var DEFAULT_OPTIONS = {
|
|
751
|
+
maxFileSize: 10 * 1024 * 1024,
|
|
752
|
+
// 10MB
|
|
753
|
+
maxFiles: 10,
|
|
754
|
+
maxFieldSize: 1 * 1024 * 1024,
|
|
755
|
+
// 1MB
|
|
756
|
+
allowedMimeTypes: [],
|
|
757
|
+
allowedExtensions: [],
|
|
758
|
+
strategy: "stream",
|
|
759
|
+
tempDir: (0, import_node_os.tmpdir)(),
|
|
760
|
+
computeHash: false
|
|
761
|
+
};
|
|
762
|
+
function createParserState(boundary, options = {}) {
|
|
763
|
+
return {
|
|
764
|
+
boundary: Buffer.from(`--${boundary}`),
|
|
765
|
+
options: { ...DEFAULT_OPTIONS, ...options },
|
|
766
|
+
fields: /* @__PURE__ */ new Map(),
|
|
767
|
+
files: /* @__PURE__ */ new Map(),
|
|
768
|
+
buffer: Buffer.alloc(0),
|
|
769
|
+
stage: "boundary",
|
|
770
|
+
currentHeaders: "",
|
|
771
|
+
currentField: null,
|
|
772
|
+
currentFilename: void 0,
|
|
773
|
+
currentMimetype: "application/octet-stream",
|
|
774
|
+
currentContentLength: 0,
|
|
775
|
+
fileCount: 0,
|
|
776
|
+
fieldCount: 0,
|
|
777
|
+
currentBufferChunks: [],
|
|
778
|
+
currentStream: null,
|
|
779
|
+
currentTempPath: null,
|
|
780
|
+
currentWriteStream: null,
|
|
781
|
+
streamController: null,
|
|
782
|
+
cleanupTasks: [],
|
|
783
|
+
// Track validation state
|
|
784
|
+
hasFoundValidBoundary: false,
|
|
785
|
+
hasProcessedAnyPart: false,
|
|
786
|
+
isFinished: false
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
async function processChunk(state, chunk) {
|
|
790
|
+
const newBuffer = Buffer.concat([state.buffer, chunk]);
|
|
791
|
+
let currentState = { ...state, buffer: newBuffer };
|
|
792
|
+
while (currentState.buffer.length > 0 && !currentState.isFinished) {
|
|
793
|
+
const nextState = await processCurrentStage(currentState);
|
|
794
|
+
if (nextState === currentState) break;
|
|
795
|
+
currentState = nextState;
|
|
796
|
+
}
|
|
797
|
+
return currentState;
|
|
798
|
+
}
|
|
799
|
+
async function processCurrentStage(state) {
|
|
800
|
+
switch (state.stage) {
|
|
801
|
+
case "boundary":
|
|
802
|
+
return processBoundary(state);
|
|
803
|
+
case "headers":
|
|
804
|
+
return processHeaders(state);
|
|
805
|
+
case "content":
|
|
806
|
+
return processContent(state);
|
|
807
|
+
default: {
|
|
808
|
+
const { InternalServerError: InternalServerError2 } = await Promise.resolve().then(() => (init_internal_server_error(), internal_server_error_exports));
|
|
809
|
+
throw new InternalServerError2(`Invalid parser stage`, {
|
|
810
|
+
operation: state.stage
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
function processBoundary(state) {
|
|
816
|
+
const boundaryIndex = state.buffer.indexOf(state.boundary);
|
|
817
|
+
if (boundaryIndex === -1) return state;
|
|
818
|
+
const hasFoundValidBoundary = true;
|
|
819
|
+
let buffer = state.buffer.subarray(boundaryIndex + state.boundary.length);
|
|
820
|
+
if (buffer.length >= 2 && buffer.subarray(0, 2).equals(Buffer.from("--"))) {
|
|
821
|
+
return {
|
|
822
|
+
...state,
|
|
823
|
+
buffer,
|
|
824
|
+
hasFoundValidBoundary,
|
|
825
|
+
isFinished: true,
|
|
826
|
+
stage: "boundary"
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
if (buffer.length >= 2 && buffer.subarray(0, 2).equals(Buffer.from("\r\n"))) {
|
|
830
|
+
buffer = buffer.subarray(2);
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
...state,
|
|
834
|
+
buffer,
|
|
835
|
+
hasFoundValidBoundary,
|
|
836
|
+
stage: "headers",
|
|
837
|
+
currentHeaders: ""
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
async function processHeaders(state) {
|
|
841
|
+
const headerEnd = state.buffer.indexOf("\r\n\r\n");
|
|
842
|
+
if (headerEnd === -1) return state;
|
|
843
|
+
const headers = state.buffer.subarray(0, headerEnd).toString("utf8");
|
|
844
|
+
const buffer = state.buffer.subarray(headerEnd + 4);
|
|
845
|
+
const disposition = parseContentDisposition(headers);
|
|
846
|
+
if (!disposition) {
|
|
847
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
848
|
+
throw new ValidationError2("Missing or invalid Content-Disposition header");
|
|
849
|
+
}
|
|
850
|
+
const mimetype = parseContentType(headers);
|
|
851
|
+
const isFile = disposition.filename !== void 0;
|
|
852
|
+
if (isFile && state.fileCount >= state.options.maxFiles) {
|
|
853
|
+
const { PayloadTooLargeError: PayloadTooLargeError2 } = await Promise.resolve().then(() => (init_payload_too_large_error(), payload_too_large_error_exports));
|
|
854
|
+
throw new PayloadTooLargeError2("Too many files in upload", {
|
|
855
|
+
fileCount: state.fileCount + 1,
|
|
856
|
+
maxFiles: state.options.maxFiles,
|
|
857
|
+
filename: disposition.filename
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
if (isFile && state.options.allowedMimeTypes.length > 0 && !state.options.allowedMimeTypes.includes(mimetype)) {
|
|
861
|
+
const { UnsupportedMediaTypeError: UnsupportedMediaTypeError2 } = await Promise.resolve().then(() => (init_unsupported_media_type_error(), unsupported_media_type_error_exports));
|
|
862
|
+
throw new UnsupportedMediaTypeError2("File type not allowed", {
|
|
863
|
+
receivedMimeType: mimetype,
|
|
864
|
+
allowedMimeTypes: state.options.allowedMimeTypes,
|
|
865
|
+
filename: disposition.filename
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
...state,
|
|
870
|
+
buffer,
|
|
871
|
+
stage: "content",
|
|
872
|
+
currentHeaders: headers,
|
|
873
|
+
currentField: disposition.name,
|
|
874
|
+
currentFilename: disposition.filename,
|
|
875
|
+
currentMimetype: mimetype,
|
|
876
|
+
currentContentLength: 0,
|
|
877
|
+
fileCount: isFile ? state.fileCount + 1 : state.fileCount,
|
|
878
|
+
fieldCount: isFile ? state.fieldCount : state.fieldCount + 1,
|
|
879
|
+
currentBufferChunks: []
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
async function processContent(state) {
|
|
883
|
+
const nextBoundaryIndex = state.buffer.indexOf(state.boundary);
|
|
884
|
+
let contentChunk;
|
|
885
|
+
let isComplete = false;
|
|
886
|
+
let buffer = state.buffer;
|
|
887
|
+
if (nextBoundaryIndex === -1) {
|
|
888
|
+
const safeLength = Math.max(0, state.buffer.length - state.boundary.length);
|
|
889
|
+
if (safeLength === 0) return state;
|
|
890
|
+
contentChunk = state.buffer.subarray(0, safeLength);
|
|
891
|
+
buffer = state.buffer.subarray(safeLength);
|
|
892
|
+
} else {
|
|
893
|
+
const contentEnd = Math.max(0, nextBoundaryIndex - 2);
|
|
894
|
+
contentChunk = state.buffer.subarray(0, contentEnd);
|
|
895
|
+
buffer = state.buffer.subarray(nextBoundaryIndex);
|
|
896
|
+
isComplete = true;
|
|
897
|
+
}
|
|
898
|
+
let updatedState = { ...state, buffer };
|
|
899
|
+
if (contentChunk.length > 0) {
|
|
900
|
+
updatedState = await processContentChunk(updatedState, contentChunk);
|
|
901
|
+
}
|
|
902
|
+
if (isComplete) {
|
|
903
|
+
updatedState = await finalizeCurrentPart(updatedState);
|
|
904
|
+
updatedState = {
|
|
905
|
+
...updatedState,
|
|
906
|
+
stage: "boundary",
|
|
907
|
+
hasProcessedAnyPart: true
|
|
908
|
+
// Mark that we've processed at least one part
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
return updatedState;
|
|
912
|
+
}
|
|
913
|
+
async function processContentChunk(state, chunk) {
|
|
914
|
+
const newContentLength = state.currentContentLength + chunk.length;
|
|
915
|
+
const maxSize = state.currentFilename !== void 0 ? state.options.maxFileSize : state.options.maxFieldSize;
|
|
916
|
+
if (newContentLength > maxSize) {
|
|
917
|
+
const isFile = state.currentFilename !== void 0;
|
|
918
|
+
const { PayloadTooLargeError: PayloadTooLargeError2 } = await Promise.resolve().then(() => (init_payload_too_large_error(), payload_too_large_error_exports));
|
|
919
|
+
const payloadErrorDetals = state.currentField ? {
|
|
920
|
+
contentType: isFile ? "file" : "field",
|
|
921
|
+
currentSize: newContentLength,
|
|
922
|
+
maxSize,
|
|
923
|
+
field: state.currentField,
|
|
924
|
+
filename: state.currentFilename
|
|
925
|
+
} : {
|
|
926
|
+
contentType: isFile ? "file" : "field",
|
|
927
|
+
currentSize: newContentLength,
|
|
928
|
+
maxSize,
|
|
929
|
+
filename: state.currentFilename
|
|
930
|
+
};
|
|
931
|
+
throw new PayloadTooLargeError2(
|
|
932
|
+
`${isFile ? "File" : "Field"} size exceeds limit`,
|
|
933
|
+
payloadErrorDetals
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
if (state.currentFilename !== void 0) {
|
|
937
|
+
return processFileChunk(state, chunk, newContentLength);
|
|
938
|
+
} else {
|
|
939
|
+
return {
|
|
940
|
+
...state,
|
|
941
|
+
currentContentLength: newContentLength,
|
|
942
|
+
currentBufferChunks: [...state.currentBufferChunks, chunk]
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async function processFileChunk(state, chunk, newContentLength) {
|
|
947
|
+
switch (state.options.strategy) {
|
|
948
|
+
case "memory":
|
|
949
|
+
return {
|
|
950
|
+
...state,
|
|
951
|
+
currentContentLength: newContentLength,
|
|
952
|
+
currentBufferChunks: [...state.currentBufferChunks, chunk]
|
|
953
|
+
};
|
|
954
|
+
case "stream":
|
|
955
|
+
if (state.streamController) {
|
|
956
|
+
state.streamController.enqueue(chunk);
|
|
957
|
+
}
|
|
958
|
+
return { ...state, currentContentLength: newContentLength };
|
|
959
|
+
case "temp":
|
|
960
|
+
if (state.currentWriteStream) {
|
|
961
|
+
await writeToStream(state.currentWriteStream, chunk);
|
|
962
|
+
}
|
|
963
|
+
return { ...state, currentContentLength: newContentLength };
|
|
964
|
+
default: {
|
|
965
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
966
|
+
throw new ValidationError2(`Invalid parsing strategy`);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
async function initializeFileProcessing(state) {
|
|
971
|
+
if (state.currentFilename === void 0) return state;
|
|
972
|
+
switch (state.options.strategy) {
|
|
973
|
+
case "memory":
|
|
974
|
+
return { ...state, currentBufferChunks: [] };
|
|
975
|
+
case "stream": {
|
|
976
|
+
let streamController = null;
|
|
977
|
+
const stream = new ReadableStream({
|
|
978
|
+
start: (controller) => {
|
|
979
|
+
streamController = controller;
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
return {
|
|
983
|
+
...state,
|
|
984
|
+
currentStream: stream,
|
|
985
|
+
// Type cast for Node.js compatibility
|
|
986
|
+
streamController
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
case "temp": {
|
|
990
|
+
const tempPath = (0, import_node_path.join)(state.options.tempDir, `upload-${(0, import_node_crypto.randomUUID)()}`);
|
|
991
|
+
const writeStream = (0, import_node_fs.createWriteStream)(tempPath);
|
|
992
|
+
const cleanupTask = async () => {
|
|
993
|
+
try {
|
|
994
|
+
const { unlink } = await import("fs/promises");
|
|
995
|
+
await unlink(tempPath);
|
|
996
|
+
} catch (error) {
|
|
997
|
+
console.warn(`Failed to cleanup temp file: ${tempPath}`, error);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
return {
|
|
1001
|
+
...state,
|
|
1002
|
+
currentTempPath: tempPath,
|
|
1003
|
+
currentWriteStream: writeStream,
|
|
1004
|
+
cleanupTasks: [...state.cleanupTasks, cleanupTask]
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
default: {
|
|
1008
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
1009
|
+
throw new ValidationError2(`Invalid file processing strategy`);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
async function finalizeCurrentPart(state) {
|
|
1014
|
+
if (!state.currentField) return resetCurrentPart(state);
|
|
1015
|
+
if (state.currentFilename !== void 0) {
|
|
1016
|
+
return finalizeFile(state);
|
|
1017
|
+
} else {
|
|
1018
|
+
return finalizeField(state);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
async function finalizeFile(state) {
|
|
1022
|
+
if (!state.currentField || state.currentFilename === void 0) {
|
|
1023
|
+
return resetCurrentPart(state);
|
|
1024
|
+
}
|
|
1025
|
+
let stream;
|
|
1026
|
+
let buffer;
|
|
1027
|
+
let tempPath;
|
|
1028
|
+
switch (state.options.strategy) {
|
|
1029
|
+
case "memory":
|
|
1030
|
+
buffer = Buffer.concat(state.currentBufferChunks);
|
|
1031
|
+
stream = import_node_stream.Readable.from(buffer);
|
|
1032
|
+
break;
|
|
1033
|
+
case "stream":
|
|
1034
|
+
if (state.streamController) {
|
|
1035
|
+
state.streamController.close();
|
|
1036
|
+
}
|
|
1037
|
+
stream = state.currentStream;
|
|
1038
|
+
break;
|
|
1039
|
+
case "temp":
|
|
1040
|
+
if (state.currentWriteStream) {
|
|
1041
|
+
await closeStream(state.currentWriteStream);
|
|
1042
|
+
}
|
|
1043
|
+
tempPath = state.currentTempPath;
|
|
1044
|
+
stream = import_node_stream.Readable.from(Buffer.alloc(0));
|
|
1045
|
+
break;
|
|
1046
|
+
default: {
|
|
1047
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
1048
|
+
throw new ValidationError2(`Invalid file finalization strategy`);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const file = {
|
|
1052
|
+
filename: state.currentFilename,
|
|
1053
|
+
fieldname: state.currentField,
|
|
1054
|
+
mimetype: state.currentMimetype,
|
|
1055
|
+
size: state.currentContentLength,
|
|
1056
|
+
stream,
|
|
1057
|
+
buffer,
|
|
1058
|
+
tempPath
|
|
1059
|
+
};
|
|
1060
|
+
const updatedFiles = addToCollection(state.files, state.currentField, file);
|
|
1061
|
+
return {
|
|
1062
|
+
...resetCurrentPart(state),
|
|
1063
|
+
files: updatedFiles
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
function finalizeField(state) {
|
|
1067
|
+
if (!state.currentField) return resetCurrentPart(state);
|
|
1068
|
+
const value = Buffer.concat(state.currentBufferChunks).toString("utf8");
|
|
1069
|
+
const updatedFields = addToCollection(state.fields, state.currentField, value);
|
|
1070
|
+
return {
|
|
1071
|
+
...resetCurrentPart(state),
|
|
1072
|
+
fields: updatedFields
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
function resetCurrentPart(state) {
|
|
1076
|
+
return {
|
|
1077
|
+
...state,
|
|
1078
|
+
currentField: null,
|
|
1079
|
+
currentFilename: void 0,
|
|
1080
|
+
currentContentLength: 0,
|
|
1081
|
+
currentBufferChunks: [],
|
|
1082
|
+
currentStream: null,
|
|
1083
|
+
streamController: null,
|
|
1084
|
+
currentTempPath: null,
|
|
1085
|
+
currentWriteStream: null
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
function addToCollection(collection, key, value) {
|
|
1089
|
+
const newCollection = new Map(collection);
|
|
1090
|
+
const existing = newCollection.get(key) || [];
|
|
1091
|
+
newCollection.set(key, [...existing, value]);
|
|
1092
|
+
return newCollection;
|
|
1093
|
+
}
|
|
1094
|
+
async function finalize(state) {
|
|
1095
|
+
if (!state.hasFoundValidBoundary) {
|
|
1096
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
1097
|
+
throw new ValidationError2("No valid multipart boundary found");
|
|
1098
|
+
}
|
|
1099
|
+
if (state.hasFoundValidBoundary && !state.hasProcessedAnyPart) {
|
|
1100
|
+
const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_validation_error(), validation_error_exports));
|
|
1101
|
+
throw new ValidationError2("Empty multipart request");
|
|
1102
|
+
}
|
|
1103
|
+
const fields = {};
|
|
1104
|
+
for (const [key, values] of state.fields.entries()) {
|
|
1105
|
+
fields[key] = values.length === 1 ? values[0] : values;
|
|
1106
|
+
}
|
|
1107
|
+
const files = {};
|
|
1108
|
+
for (const [key, fileList] of state.files.entries()) {
|
|
1109
|
+
files[key] = fileList.length === 1 ? fileList[0] : fileList;
|
|
1110
|
+
}
|
|
1111
|
+
return { fields, files };
|
|
1112
|
+
}
|
|
1113
|
+
async function cleanup(state) {
|
|
1114
|
+
await Promise.allSettled(state.cleanupTasks.map((task) => task()));
|
|
1115
|
+
if (state.streamController) {
|
|
1116
|
+
state.streamController.close();
|
|
1117
|
+
}
|
|
1118
|
+
if (state.currentWriteStream) {
|
|
1119
|
+
await closeStream(state.currentWriteStream);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
async function writeToStream(stream, chunk) {
|
|
1123
|
+
return new Promise((resolve3, reject) => {
|
|
1124
|
+
stream.write(chunk, (error) => {
|
|
1125
|
+
if (error) reject(error);
|
|
1126
|
+
else resolve3();
|
|
1127
|
+
});
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
async function closeStream(stream) {
|
|
1131
|
+
return new Promise((resolve3) => {
|
|
1132
|
+
stream.end(() => resolve3());
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
async function parseMultipartRequest(request, options = {}) {
|
|
1136
|
+
const contentType = request.headers["content-type"] || "";
|
|
1137
|
+
const boundary = extractBoundary(contentType);
|
|
1138
|
+
if (!boundary) {
|
|
1139
|
+
const { UnsupportedMediaTypeError: UnsupportedMediaTypeError2 } = await Promise.resolve().then(() => (init_unsupported_media_type_error(), unsupported_media_type_error_exports));
|
|
1140
|
+
throw new UnsupportedMediaTypeError2("Missing boundary in multipart content-type", {
|
|
1141
|
+
receivedContentType: contentType,
|
|
1142
|
+
expectedFormat: "multipart/form-data; boundary=..."
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
let state = createParserState(boundary, options);
|
|
1146
|
+
if (state.currentFilename !== void 0) {
|
|
1147
|
+
state = await initializeFileProcessing(state);
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
for await (const chunk of request) {
|
|
1151
|
+
state = await processChunk(state, chunk);
|
|
1152
|
+
}
|
|
1153
|
+
return finalize(state);
|
|
1154
|
+
} finally {
|
|
1155
|
+
await cleanup(state);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
440
1159
|
// src/context/create.ts
|
|
441
1160
|
var CONTENT_TYPE_HEADER = "Content-Type";
|
|
1161
|
+
var DEFAULT_BODY_LIMITS = {
|
|
1162
|
+
json: 512 * 1024,
|
|
1163
|
+
// 512KB - Most APIs should be much smaller
|
|
1164
|
+
form: 1024 * 1024,
|
|
1165
|
+
// 1MB - Reasonable for form submissions
|
|
1166
|
+
text: 5 * 1024 * 1024,
|
|
1167
|
+
// 5MB - Documents, logs, code files
|
|
1168
|
+
multipart: {
|
|
1169
|
+
maxFileSize: 50 * 1024 * 1024,
|
|
1170
|
+
// 50MB per file
|
|
1171
|
+
maxTotalSize: 100 * 1024 * 1024,
|
|
1172
|
+
// 100MB total request
|
|
1173
|
+
maxFiles: 10,
|
|
1174
|
+
maxFieldSize: 1024 * 1024
|
|
1175
|
+
// 1MB for form fields
|
|
1176
|
+
},
|
|
1177
|
+
raw: 10 * 1024 * 1024
|
|
1178
|
+
// 10MB for unknown content types
|
|
1179
|
+
};
|
|
442
1180
|
function parseRequestUrl(req) {
|
|
443
1181
|
const originalUrl = req.url || "/";
|
|
444
1182
|
const host = req.headers.host || "localhost";
|
|
@@ -503,7 +1241,7 @@ async function createContext(req, res, options = {}) {
|
|
|
503
1241
|
};
|
|
504
1242
|
ctx.response = createResponseObject(res, responseState, ctx);
|
|
505
1243
|
if (options.parseBody) {
|
|
506
|
-
await parseBodyIfNeeded(req, ctx);
|
|
1244
|
+
await parseBodyIfNeeded(req, ctx, options);
|
|
507
1245
|
}
|
|
508
1246
|
return ctx;
|
|
509
1247
|
}
|
|
@@ -679,34 +1417,60 @@ function createStreamResponder(res, responseState) {
|
|
|
679
1417
|
});
|
|
680
1418
|
};
|
|
681
1419
|
}
|
|
682
|
-
async function parseBodyIfNeeded(req, ctx) {
|
|
1420
|
+
async function parseBodyIfNeeded(req, ctx, options = {}) {
|
|
683
1421
|
if (shouldSkipParsing(req.method)) {
|
|
684
1422
|
return;
|
|
685
1423
|
}
|
|
686
1424
|
const contentType = req.headers["content-type"] || "";
|
|
687
1425
|
const contentLength = parseInt(req.headers["content-length"] || "0", 10);
|
|
688
|
-
if (contentLength === 0
|
|
1426
|
+
if (contentLength === 0) {
|
|
689
1427
|
return;
|
|
690
1428
|
}
|
|
1429
|
+
const limits = {
|
|
1430
|
+
json: options.bodyLimits?.json ?? DEFAULT_BODY_LIMITS.json,
|
|
1431
|
+
form: options.bodyLimits?.form ?? DEFAULT_BODY_LIMITS.form,
|
|
1432
|
+
text: options.bodyLimits?.text ?? DEFAULT_BODY_LIMITS.text,
|
|
1433
|
+
raw: options.bodyLimits?.raw ?? DEFAULT_BODY_LIMITS.raw,
|
|
1434
|
+
multipart: {
|
|
1435
|
+
maxFileSize: options.bodyLimits?.multipart?.maxFileSize ?? DEFAULT_BODY_LIMITS.multipart.maxFileSize,
|
|
1436
|
+
maxFiles: options.bodyLimits?.multipart?.maxFiles ?? DEFAULT_BODY_LIMITS.multipart.maxFiles,
|
|
1437
|
+
maxFieldSize: options.bodyLimits?.multipart?.maxFieldSize ?? DEFAULT_BODY_LIMITS.multipart.maxFieldSize,
|
|
1438
|
+
maxTotalSize: options.bodyLimits?.multipart?.maxTotalSize ?? DEFAULT_BODY_LIMITS.multipart.maxTotalSize
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
691
1441
|
try {
|
|
692
|
-
|
|
1442
|
+
if (contentType.includes("application/json")) {
|
|
1443
|
+
if (contentLength > limits.json) {
|
|
1444
|
+
throw new Error(`JSON body too large: ${contentLength} > ${limits.json} bytes`);
|
|
1445
|
+
}
|
|
1446
|
+
await parseJsonBody(req, ctx);
|
|
1447
|
+
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
1448
|
+
if (contentLength > limits.form) {
|
|
1449
|
+
throw new Error(`Form body too large: ${contentLength} > ${limits.form} bytes`);
|
|
1450
|
+
}
|
|
1451
|
+
await parseFormUrlEncodedBody(req, ctx);
|
|
1452
|
+
} else if (contentType.includes("text/")) {
|
|
1453
|
+
if (contentLength > limits.text) {
|
|
1454
|
+
throw new Error(`Text body too large: ${contentLength} > ${limits.text} bytes`);
|
|
1455
|
+
}
|
|
1456
|
+
await parseTextBody(req, ctx);
|
|
1457
|
+
} else if (isMultipartContent(contentType)) {
|
|
1458
|
+
await parseMultipartBody(req, ctx, limits.multipart);
|
|
1459
|
+
} else {
|
|
1460
|
+
if (contentLength > limits.raw) {
|
|
1461
|
+
throw new Error(`Request body too large: ${contentLength} > ${limits.raw} bytes`);
|
|
1462
|
+
}
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
693
1465
|
} catch (error) {
|
|
694
|
-
|
|
1466
|
+
const errorType = contentType.includes("multipart") ? "multipart_parse_error" : "body_read_error";
|
|
1467
|
+
setBodyError(ctx, errorType, "Error reading request body", error);
|
|
695
1468
|
}
|
|
696
1469
|
}
|
|
697
1470
|
function shouldSkipParsing(method) {
|
|
698
1471
|
const skipMethods = ["GET", "HEAD", "OPTIONS"];
|
|
699
1472
|
return skipMethods.includes(method || "GET");
|
|
700
1473
|
}
|
|
701
|
-
async function parseBodyByContentType(req, ctx, contentType) {
|
|
702
|
-
if (contentType.includes("application/json")) {
|
|
703
|
-
await parseJsonBody(req, ctx);
|
|
704
|
-
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
705
|
-
await parseFormUrlEncodedBody(req, ctx);
|
|
706
|
-
} else if (contentType.includes("text/")) {
|
|
707
|
-
await parseTextBody(req, ctx);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
1474
|
async function parseJsonBody(req, ctx) {
|
|
711
1475
|
const body = await readRequestBody(req);
|
|
712
1476
|
if (!body) {
|
|
@@ -758,8 +1522,27 @@ async function parseTextBody(req, ctx) {
|
|
|
758
1522
|
ctx.request.body = body;
|
|
759
1523
|
}
|
|
760
1524
|
}
|
|
1525
|
+
async function parseMultipartBody(req, ctx, multipartLimits) {
|
|
1526
|
+
try {
|
|
1527
|
+
const limits = multipartLimits || DEFAULT_BODY_LIMITS.multipart;
|
|
1528
|
+
const multipartData = await parseMultipartRequest(req, {
|
|
1529
|
+
strategy: "stream",
|
|
1530
|
+
maxFileSize: limits.maxFileSize,
|
|
1531
|
+
maxFiles: limits.maxFiles,
|
|
1532
|
+
maxFieldSize: limits.maxFieldSize
|
|
1533
|
+
// Could add total size validation here
|
|
1534
|
+
});
|
|
1535
|
+
ctx.request.multipart = multipartData;
|
|
1536
|
+
ctx.request.files = multipartData.files;
|
|
1537
|
+
ctx.request.body = multipartData.fields;
|
|
1538
|
+
} catch (error) {
|
|
1539
|
+
ctx.request.body = null;
|
|
1540
|
+
setBodyError(ctx, "multipart_parse_error", "Failed to parse multipart data", error);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
761
1543
|
function setBodyError(ctx, type, message, error) {
|
|
762
|
-
|
|
1544
|
+
const bodyError = { type, message, error };
|
|
1545
|
+
ctx.state._bodyError = bodyError;
|
|
763
1546
|
}
|
|
764
1547
|
async function readRequestBody(req) {
|
|
765
1548
|
return new Promise((resolve3, reject) => {
|
|
@@ -776,6 +1559,107 @@ async function readRequestBody(req) {
|
|
|
776
1559
|
});
|
|
777
1560
|
}
|
|
778
1561
|
|
|
1562
|
+
// src/errors/not-found-error.ts
|
|
1563
|
+
init_errors();
|
|
1564
|
+
init_correlation();
|
|
1565
|
+
var NotFoundError = class extends BlaizeError {
|
|
1566
|
+
/**
|
|
1567
|
+
* Creates a new NotFoundError instance
|
|
1568
|
+
*
|
|
1569
|
+
* @param title - Human-readable error message
|
|
1570
|
+
* @param details - Optional context about the missing resource
|
|
1571
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
1572
|
+
*/
|
|
1573
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
1574
|
+
super(
|
|
1575
|
+
"NOT_FOUND" /* NOT_FOUND */,
|
|
1576
|
+
title,
|
|
1577
|
+
404,
|
|
1578
|
+
// HTTP 404 Not Found
|
|
1579
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
1580
|
+
details
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
// src/errors/boundary.ts
|
|
1586
|
+
init_errors();
|
|
1587
|
+
init_correlation();
|
|
1588
|
+
init_internal_server_error();
|
|
1589
|
+
function isHandledError(error) {
|
|
1590
|
+
return error instanceof BlaizeError;
|
|
1591
|
+
}
|
|
1592
|
+
function formatErrorResponse(error) {
|
|
1593
|
+
if (isHandledError(error)) {
|
|
1594
|
+
return {
|
|
1595
|
+
type: error.type,
|
|
1596
|
+
title: error.title,
|
|
1597
|
+
status: error.status,
|
|
1598
|
+
correlationId: error.correlationId,
|
|
1599
|
+
timestamp: error.timestamp.toISOString(),
|
|
1600
|
+
details: error.details
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
const correlationId = generateCorrelationId();
|
|
1604
|
+
let originalMessage;
|
|
1605
|
+
if (error instanceof Error) {
|
|
1606
|
+
originalMessage = error.message;
|
|
1607
|
+
} else if (error === null || error === void 0) {
|
|
1608
|
+
originalMessage = "Unknown error occurred";
|
|
1609
|
+
} else {
|
|
1610
|
+
originalMessage = String(error);
|
|
1611
|
+
}
|
|
1612
|
+
const wrappedError = new InternalServerError(
|
|
1613
|
+
"Internal Server Error",
|
|
1614
|
+
{ originalMessage },
|
|
1615
|
+
correlationId
|
|
1616
|
+
);
|
|
1617
|
+
return {
|
|
1618
|
+
type: wrappedError.type,
|
|
1619
|
+
title: wrappedError.title,
|
|
1620
|
+
status: wrappedError.status,
|
|
1621
|
+
correlationId: wrappedError.correlationId,
|
|
1622
|
+
timestamp: wrappedError.timestamp.toISOString(),
|
|
1623
|
+
details: wrappedError.details
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
function extractOrGenerateCorrelationId(headerGetter) {
|
|
1627
|
+
return headerGetter("x-correlation-id") ?? generateCorrelationId();
|
|
1628
|
+
}
|
|
1629
|
+
function setErrorResponseHeaders(headerSetter, correlationId) {
|
|
1630
|
+
headerSetter("x-correlation-id", correlationId);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
// src/middleware/error-boundary.ts
|
|
1634
|
+
function createErrorBoundary(options = {}) {
|
|
1635
|
+
const { debug = false } = options;
|
|
1636
|
+
const middlewareFn = async (ctx, next) => {
|
|
1637
|
+
try {
|
|
1638
|
+
await next();
|
|
1639
|
+
} catch (error) {
|
|
1640
|
+
if (ctx.response.sent) {
|
|
1641
|
+
if (debug) {
|
|
1642
|
+
console.error("Error occurred after response was sent:", error);
|
|
1643
|
+
}
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
if (debug) {
|
|
1647
|
+
console.error("Error boundary caught error:", error);
|
|
1648
|
+
}
|
|
1649
|
+
const correlationId = extractOrGenerateCorrelationId(ctx.request.header);
|
|
1650
|
+
const errorResponse = formatErrorResponse(error);
|
|
1651
|
+
errorResponse.correlationId = correlationId;
|
|
1652
|
+
setErrorResponseHeaders(ctx.response.header, correlationId);
|
|
1653
|
+
ctx.response.status(errorResponse.status).json(errorResponse);
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
return {
|
|
1657
|
+
name: "ErrorBoundary",
|
|
1658
|
+
execute: middlewareFn,
|
|
1659
|
+
debug
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
|
|
779
1663
|
// src/server/request-handler.ts
|
|
780
1664
|
function createRequestHandler(serverInstance) {
|
|
781
1665
|
return async (req, res) => {
|
|
@@ -784,32 +1668,20 @@ function createRequestHandler(serverInstance) {
|
|
|
784
1668
|
parseBody: true
|
|
785
1669
|
// Enable automatic body parsing
|
|
786
1670
|
});
|
|
787
|
-
const
|
|
1671
|
+
const errorBoundary = createErrorBoundary();
|
|
1672
|
+
const allMiddleware = [errorBoundary, ...serverInstance.middleware];
|
|
1673
|
+
const handler = compose(allMiddleware);
|
|
788
1674
|
await runWithContext(context, async () => {
|
|
789
|
-
|
|
790
|
-
|
|
1675
|
+
await handler(context, async () => {
|
|
1676
|
+
if (!context.response.sent) {
|
|
1677
|
+
await serverInstance.router.handleRequest(context);
|
|
791
1678
|
if (!context.response.sent) {
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
error: "Not Found",
|
|
796
|
-
message: `Route not found: ${context.request.method} ${context.request.path}`
|
|
797
|
-
});
|
|
798
|
-
}
|
|
1679
|
+
throw new NotFoundError(
|
|
1680
|
+
`Route not found: ${context.request.method} ${context.request.path}`
|
|
1681
|
+
);
|
|
799
1682
|
}
|
|
800
|
-
});
|
|
801
|
-
} catch (error) {
|
|
802
|
-
console.error("Error processing request:", error);
|
|
803
|
-
if (!context.response.sent) {
|
|
804
|
-
context.response.json(
|
|
805
|
-
{
|
|
806
|
-
error: "Internal Server Error",
|
|
807
|
-
message: process.env.NODE_ENV === "development" ? error || "Unknown error" : "An error occurred processing your request"
|
|
808
|
-
},
|
|
809
|
-
500
|
|
810
|
-
);
|
|
811
1683
|
}
|
|
812
|
-
}
|
|
1684
|
+
});
|
|
813
1685
|
});
|
|
814
1686
|
} catch (error) {
|
|
815
1687
|
console.error("Error creating context:", error);
|
|
@@ -1651,81 +2523,8 @@ function watchRoutes(routesDir, options = {}) {
|
|
|
1651
2523
|
};
|
|
1652
2524
|
}
|
|
1653
2525
|
|
|
1654
|
-
// src/router/
|
|
1655
|
-
|
|
1656
|
-
if (options.log) {
|
|
1657
|
-
console.error("Route error:", error);
|
|
1658
|
-
}
|
|
1659
|
-
const status = getErrorStatus(error);
|
|
1660
|
-
const response = {
|
|
1661
|
-
error: getErrorType(error),
|
|
1662
|
-
message: getErrorMessage(error)
|
|
1663
|
-
};
|
|
1664
|
-
if (options.detailed) {
|
|
1665
|
-
if (error instanceof Error) {
|
|
1666
|
-
response.stack = error.stack;
|
|
1667
|
-
}
|
|
1668
|
-
if (error && typeof error === "object" && "details" in error && error.details) {
|
|
1669
|
-
response.details = error.details;
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
ctx.response.status(status).json(response);
|
|
1673
|
-
}
|
|
1674
|
-
function getErrorStatus(error) {
|
|
1675
|
-
if (error && typeof error === "object") {
|
|
1676
|
-
if ("status" in error && typeof error.status === "number") {
|
|
1677
|
-
return error.status;
|
|
1678
|
-
}
|
|
1679
|
-
if ("statusCode" in error && typeof error.statusCode === "number") {
|
|
1680
|
-
return error.statusCode;
|
|
1681
|
-
}
|
|
1682
|
-
if ("code" in error && typeof error.code === "string") {
|
|
1683
|
-
return getStatusFromCode(error.code);
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
return 500;
|
|
1687
|
-
}
|
|
1688
|
-
function getStatusFromCode(code) {
|
|
1689
|
-
switch (code) {
|
|
1690
|
-
case "NOT_FOUND":
|
|
1691
|
-
return 404;
|
|
1692
|
-
case "UNAUTHORIZED":
|
|
1693
|
-
return 401;
|
|
1694
|
-
case "FORBIDDEN":
|
|
1695
|
-
return 403;
|
|
1696
|
-
case "BAD_REQUEST":
|
|
1697
|
-
return 400;
|
|
1698
|
-
case "CONFLICT":
|
|
1699
|
-
return 409;
|
|
1700
|
-
default:
|
|
1701
|
-
return 500;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
function getErrorType(error) {
|
|
1705
|
-
if (error && typeof error === "object") {
|
|
1706
|
-
if ("type" in error && typeof error.type === "string") {
|
|
1707
|
-
return error.type;
|
|
1708
|
-
}
|
|
1709
|
-
if ("name" in error && typeof error.name === "string") {
|
|
1710
|
-
return error.name;
|
|
1711
|
-
}
|
|
1712
|
-
if (error instanceof Error) {
|
|
1713
|
-
return error.constructor.name;
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
return "Error";
|
|
1717
|
-
}
|
|
1718
|
-
function getErrorMessage(error) {
|
|
1719
|
-
if (error instanceof Error) {
|
|
1720
|
-
return error.message;
|
|
1721
|
-
}
|
|
1722
|
-
if (error && typeof error === "object") {
|
|
1723
|
-
if ("message" in error && typeof error.message === "string") {
|
|
1724
|
-
return error.message;
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
return String(error);
|
|
1728
|
-
}
|
|
2526
|
+
// src/router/validation/schema.ts
|
|
2527
|
+
var import_zod6 = require("zod");
|
|
1729
2528
|
|
|
1730
2529
|
// src/router/validation/body.ts
|
|
1731
2530
|
var import_zod2 = require("zod");
|
|
@@ -1764,37 +2563,49 @@ function validateResponse(response, schema) {
|
|
|
1764
2563
|
}
|
|
1765
2564
|
|
|
1766
2565
|
// src/router/validation/schema.ts
|
|
2566
|
+
init_internal_server_error();
|
|
2567
|
+
init_validation_error();
|
|
1767
2568
|
function createRequestValidator(schema, debug = false) {
|
|
1768
2569
|
const middlewareFn = async (ctx, next) => {
|
|
1769
|
-
const errors = {};
|
|
1770
2570
|
if (schema.params && ctx.request.params) {
|
|
1771
2571
|
try {
|
|
1772
2572
|
ctx.request.params = validateParams(ctx.request.params, schema.params);
|
|
1773
2573
|
} catch (error) {
|
|
1774
|
-
|
|
2574
|
+
const fieldErrors = extractZodFieldErrors(error);
|
|
2575
|
+
const errorCount = fieldErrors.reduce((sum, fe) => sum + fe.messages.length, 0);
|
|
2576
|
+
throw new ValidationError("Request validation failed", {
|
|
2577
|
+
fields: fieldErrors,
|
|
2578
|
+
errorCount,
|
|
2579
|
+
section: "params"
|
|
2580
|
+
});
|
|
1775
2581
|
}
|
|
1776
2582
|
}
|
|
1777
2583
|
if (schema.query && ctx.request.query) {
|
|
1778
2584
|
try {
|
|
1779
2585
|
ctx.request.query = validateQuery(ctx.request.query, schema.query);
|
|
1780
2586
|
} catch (error) {
|
|
1781
|
-
|
|
2587
|
+
const fieldErrors = extractZodFieldErrors(error);
|
|
2588
|
+
const errorCount = fieldErrors.reduce((sum, fe) => sum + fe.messages.length, 0);
|
|
2589
|
+
throw new ValidationError("Request validation failed", {
|
|
2590
|
+
fields: fieldErrors,
|
|
2591
|
+
errorCount,
|
|
2592
|
+
section: "query"
|
|
2593
|
+
});
|
|
1782
2594
|
}
|
|
1783
2595
|
}
|
|
1784
2596
|
if (schema.body) {
|
|
1785
2597
|
try {
|
|
1786
2598
|
ctx.request.body = validateBody(ctx.request.body, schema.body);
|
|
1787
2599
|
} catch (error) {
|
|
1788
|
-
|
|
2600
|
+
const fieldErrors = extractZodFieldErrors(error);
|
|
2601
|
+
const errorCount = fieldErrors.reduce((sum, fe) => sum + fe.messages.length, 0);
|
|
2602
|
+
throw new ValidationError("Request validation failed", {
|
|
2603
|
+
fields: fieldErrors,
|
|
2604
|
+
errorCount,
|
|
2605
|
+
section: "body"
|
|
2606
|
+
});
|
|
1789
2607
|
}
|
|
1790
2608
|
}
|
|
1791
|
-
if (Object.keys(errors).length > 0) {
|
|
1792
|
-
ctx.response.status(400).json({
|
|
1793
|
-
error: "Validation Error",
|
|
1794
|
-
details: errors
|
|
1795
|
-
});
|
|
1796
|
-
return;
|
|
1797
|
-
}
|
|
1798
2609
|
await next();
|
|
1799
2610
|
};
|
|
1800
2611
|
return {
|
|
@@ -1813,12 +2624,11 @@ function createResponseValidator(responseSchema, debug = false) {
|
|
|
1813
2624
|
return originalJson.call(ctx.response, validatedBody, status);
|
|
1814
2625
|
} catch (error) {
|
|
1815
2626
|
ctx.response.json = originalJson;
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
2627
|
+
throw new InternalServerError("Response validation failed", {
|
|
2628
|
+
responseSchema: responseSchema.description || "Unknown schema",
|
|
2629
|
+
validationError: extractZodFieldErrors(error),
|
|
2630
|
+
originalResponse: body
|
|
1820
2631
|
});
|
|
1821
|
-
return ctx.response;
|
|
1822
2632
|
}
|
|
1823
2633
|
};
|
|
1824
2634
|
await next();
|
|
@@ -1829,11 +2639,25 @@ function createResponseValidator(responseSchema, debug = false) {
|
|
|
1829
2639
|
debug
|
|
1830
2640
|
};
|
|
1831
2641
|
}
|
|
1832
|
-
function
|
|
1833
|
-
if (error
|
|
1834
|
-
|
|
2642
|
+
function extractZodFieldErrors(error) {
|
|
2643
|
+
if (error instanceof import_zod6.z.ZodError) {
|
|
2644
|
+
const fieldErrorMap = /* @__PURE__ */ new Map();
|
|
2645
|
+
for (const issue of error.issues) {
|
|
2646
|
+
const fieldPath = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
2647
|
+
if (!fieldErrorMap.has(fieldPath)) {
|
|
2648
|
+
fieldErrorMap.set(fieldPath, []);
|
|
2649
|
+
}
|
|
2650
|
+
fieldErrorMap.get(fieldPath).push(issue.message);
|
|
2651
|
+
}
|
|
2652
|
+
return Array.from(fieldErrorMap.entries()).map(([field, messages]) => ({
|
|
2653
|
+
field,
|
|
2654
|
+
messages
|
|
2655
|
+
}));
|
|
2656
|
+
}
|
|
2657
|
+
if (error instanceof Error) {
|
|
2658
|
+
return [{ field: "unknown", messages: [error.message] }];
|
|
1835
2659
|
}
|
|
1836
|
-
return
|
|
2660
|
+
return [{ field: "unknown", messages: [String(error)] }];
|
|
1837
2661
|
}
|
|
1838
2662
|
|
|
1839
2663
|
// src/router/handlers/executor.ts
|
|
@@ -2268,8 +3092,7 @@ function createRouter(options) {
|
|
|
2268
3092
|
const match = matcher.match(path6, method);
|
|
2269
3093
|
if (!match) {
|
|
2270
3094
|
console.log(`\u274C No match found for: ${method} ${path6}`);
|
|
2271
|
-
|
|
2272
|
-
return;
|
|
3095
|
+
throw new NotFoundError("Not found");
|
|
2273
3096
|
}
|
|
2274
3097
|
console.log(`\u2705 Route matched: ${method} ${path6}`);
|
|
2275
3098
|
console.log(` Params: ${JSON.stringify(match.params)}`);
|
|
@@ -2284,14 +3107,7 @@ function createRouter(options) {
|
|
|
2284
3107
|
return;
|
|
2285
3108
|
}
|
|
2286
3109
|
ctx.request.params = match.params;
|
|
2287
|
-
|
|
2288
|
-
await executeHandler(ctx, match.route, match.params);
|
|
2289
|
-
} catch (error) {
|
|
2290
|
-
handleRouteError(ctx, error, {
|
|
2291
|
-
detailed: process.env.NODE_ENV !== "production",
|
|
2292
|
-
log: true
|
|
2293
|
-
});
|
|
2294
|
-
}
|
|
3110
|
+
await executeHandler(ctx, match.route, match.params);
|
|
2295
3111
|
},
|
|
2296
3112
|
/**
|
|
2297
3113
|
* Get all registered routes (using optimized registry)
|
|
@@ -2352,7 +3168,7 @@ function createRouter(options) {
|
|
|
2352
3168
|
}
|
|
2353
3169
|
|
|
2354
3170
|
// src/server/create.ts
|
|
2355
|
-
var
|
|
3171
|
+
var DEFAULT_OPTIONS2 = {
|
|
2356
3172
|
port: 3e3,
|
|
2357
3173
|
host: "localhost",
|
|
2358
3174
|
routesDir: "./routes",
|
|
@@ -2363,7 +3179,7 @@ var DEFAULT_OPTIONS = {
|
|
|
2363
3179
|
plugins: []
|
|
2364
3180
|
};
|
|
2365
3181
|
function createServerOptions(options = {}) {
|
|
2366
|
-
const baseOptions = { ...
|
|
3182
|
+
const baseOptions = { ...DEFAULT_OPTIONS2 };
|
|
2367
3183
|
setRuntimeConfig({ routesDir: options.routesDir || baseOptions.routesDir });
|
|
2368
3184
|
return {
|
|
2369
3185
|
port: options.port ?? baseOptions.port,
|
|
@@ -2443,7 +3259,7 @@ function create3(options = {}) {
|
|
|
2443
3259
|
const { port, host, middleware, plugins } = validatedOptions;
|
|
2444
3260
|
const initialMiddleware = Array.isArray(middleware) ? [...middleware] : [];
|
|
2445
3261
|
const initialPlugins = Array.isArray(plugins) ? [...plugins] : [];
|
|
2446
|
-
const contextStorage2 = new
|
|
3262
|
+
const contextStorage2 = new import_node_async_hooks3.AsyncLocalStorage();
|
|
2447
3263
|
const router = createRouter({
|
|
2448
3264
|
routesDir: validatedOptions.routesDir,
|
|
2449
3265
|
watchMode: process.env.NODE_ENV === "development"
|
|
@@ -2483,7 +3299,106 @@ function create3(options = {}) {
|
|
|
2483
3299
|
return serverInstance;
|
|
2484
3300
|
}
|
|
2485
3301
|
|
|
3302
|
+
// ../blaize-types/src/index.ts
|
|
3303
|
+
init_errors();
|
|
3304
|
+
|
|
3305
|
+
// src/index.ts
|
|
3306
|
+
init_validation_error();
|
|
3307
|
+
|
|
3308
|
+
// src/errors/unauthorized-error.ts
|
|
3309
|
+
init_errors();
|
|
3310
|
+
init_correlation();
|
|
3311
|
+
var UnauthorizedError = class extends BlaizeError {
|
|
3312
|
+
/**
|
|
3313
|
+
* Creates a new UnauthorizedError instance
|
|
3314
|
+
*
|
|
3315
|
+
* @param title - Human-readable error message
|
|
3316
|
+
* @param details - Optional authentication context
|
|
3317
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
3318
|
+
*/
|
|
3319
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
3320
|
+
super(
|
|
3321
|
+
"UNAUTHORIZED" /* UNAUTHORIZED */,
|
|
3322
|
+
title,
|
|
3323
|
+
401,
|
|
3324
|
+
// HTTP 401 Unauthorized
|
|
3325
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
3326
|
+
details
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
};
|
|
3330
|
+
|
|
3331
|
+
// src/errors/forbidden-error.ts
|
|
3332
|
+
init_errors();
|
|
3333
|
+
init_correlation();
|
|
3334
|
+
var ForbiddenError = class extends BlaizeError {
|
|
3335
|
+
/**
|
|
3336
|
+
* Creates a new ForbiddenError instance
|
|
3337
|
+
*
|
|
3338
|
+
* @param title - Human-readable error message
|
|
3339
|
+
* @param details - Optional permission context
|
|
3340
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
3341
|
+
*/
|
|
3342
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
3343
|
+
super(
|
|
3344
|
+
"FORBIDDEN" /* FORBIDDEN */,
|
|
3345
|
+
title,
|
|
3346
|
+
403,
|
|
3347
|
+
// HTTP 403 Forbidden
|
|
3348
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
3349
|
+
details
|
|
3350
|
+
);
|
|
3351
|
+
}
|
|
3352
|
+
};
|
|
3353
|
+
|
|
3354
|
+
// src/errors/conflict-error.ts
|
|
3355
|
+
init_errors();
|
|
3356
|
+
init_correlation();
|
|
3357
|
+
var ConflictError = class extends BlaizeError {
|
|
3358
|
+
/**
|
|
3359
|
+
* Creates a new ConflictError instance
|
|
3360
|
+
*
|
|
3361
|
+
* @param title - Human-readable error message
|
|
3362
|
+
* @param details - Optional conflict context
|
|
3363
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
3364
|
+
*/
|
|
3365
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
3366
|
+
super(
|
|
3367
|
+
"CONFLICT" /* CONFLICT */,
|
|
3368
|
+
title,
|
|
3369
|
+
409,
|
|
3370
|
+
// HTTP 409 Conflict
|
|
3371
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
3372
|
+
details
|
|
3373
|
+
);
|
|
3374
|
+
}
|
|
3375
|
+
};
|
|
3376
|
+
|
|
3377
|
+
// src/errors/rate-limit-error.ts
|
|
3378
|
+
init_errors();
|
|
3379
|
+
init_correlation();
|
|
3380
|
+
var RateLimitError = class extends BlaizeError {
|
|
3381
|
+
/**
|
|
3382
|
+
* Creates a new RateLimitError instance
|
|
3383
|
+
*
|
|
3384
|
+
* @param title - Human-readable error message
|
|
3385
|
+
* @param details - Optional rate limit context
|
|
3386
|
+
* @param correlationId - Optional correlation ID (uses current context if not provided)
|
|
3387
|
+
*/
|
|
3388
|
+
constructor(title, details = void 0, correlationId = void 0) {
|
|
3389
|
+
super(
|
|
3390
|
+
"RATE_LIMITED" /* RATE_LIMITED */,
|
|
3391
|
+
title,
|
|
3392
|
+
429,
|
|
3393
|
+
// HTTP 429 Too Many Requests
|
|
3394
|
+
correlationId ?? getCurrentCorrelationId(),
|
|
3395
|
+
details
|
|
3396
|
+
);
|
|
3397
|
+
}
|
|
3398
|
+
};
|
|
3399
|
+
|
|
2486
3400
|
// src/index.ts
|
|
3401
|
+
init_internal_server_error();
|
|
2487
3402
|
var VERSION = "0.1.0";
|
|
2488
3403
|
var ServerAPI = { createServer: create3 };
|
|
2489
3404
|
var RouterAPI = {
|
|
@@ -2514,11 +3429,21 @@ var index_default = Blaize;
|
|
|
2514
3429
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2515
3430
|
0 && (module.exports = {
|
|
2516
3431
|
Blaize,
|
|
3432
|
+
BlaizeError,
|
|
3433
|
+
ConflictError,
|
|
3434
|
+
ErrorSeverity,
|
|
3435
|
+
ErrorType,
|
|
3436
|
+
ForbiddenError,
|
|
3437
|
+
InternalServerError,
|
|
2517
3438
|
MiddlewareAPI,
|
|
3439
|
+
NotFoundError,
|
|
2518
3440
|
PluginsAPI,
|
|
3441
|
+
RateLimitError,
|
|
2519
3442
|
RouterAPI,
|
|
2520
3443
|
ServerAPI,
|
|
3444
|
+
UnauthorizedError,
|
|
2521
3445
|
VERSION,
|
|
3446
|
+
ValidationError,
|
|
2522
3447
|
compose,
|
|
2523
3448
|
createDeleteRoute,
|
|
2524
3449
|
createGetRoute,
|
|
@@ -2529,6 +3454,7 @@ var index_default = Blaize;
|
|
|
2529
3454
|
createPlugin,
|
|
2530
3455
|
createPostRoute,
|
|
2531
3456
|
createPutRoute,
|
|
2532
|
-
createServer
|
|
3457
|
+
createServer,
|
|
3458
|
+
isBodyParseError
|
|
2533
3459
|
});
|
|
2534
3460
|
//# sourceMappingURL=index.cjs.map
|