@dangao/bun-server 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/controller.d.ts +1 -1
- package/dist/auth/controller.d.ts.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/core/application.d.ts +10 -2
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/context.d.ts +6 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/database/connection-manager.d.ts +72 -0
- package/dist/database/connection-manager.d.ts.map +1 -0
- package/dist/database/connection-pool.d.ts +79 -0
- package/dist/database/connection-pool.d.ts.map +1 -0
- package/dist/database/database-extension.d.ts +20 -0
- package/dist/database/database-extension.d.ts.map +1 -0
- package/dist/database/database-module.d.ts +18 -0
- package/dist/database/database-module.d.ts.map +1 -0
- package/dist/database/health-indicator.d.ts +15 -0
- package/dist/database/health-indicator.d.ts.map +1 -0
- package/dist/database/index.d.ts +9 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/orm/decorators.d.ts +70 -0
- package/dist/database/orm/decorators.d.ts.map +1 -0
- package/dist/database/orm/drizzle-repository.d.ts +34 -0
- package/dist/database/orm/drizzle-repository.d.ts.map +1 -0
- package/dist/database/orm/index.d.ts +11 -0
- package/dist/database/orm/index.d.ts.map +1 -0
- package/dist/database/orm/repository-decorator.d.ts +21 -0
- package/dist/database/orm/repository-decorator.d.ts.map +1 -0
- package/dist/database/orm/repository.d.ts +36 -0
- package/dist/database/orm/repository.d.ts.map +1 -0
- package/dist/database/orm/service.d.ts +26 -0
- package/dist/database/orm/service.d.ts.map +1 -0
- package/dist/database/orm/transaction-decorator.d.ts +17 -0
- package/dist/database/orm/transaction-decorator.d.ts.map +1 -0
- package/dist/database/orm/transaction-interceptor.d.ts +28 -0
- package/dist/database/orm/transaction-interceptor.d.ts.map +1 -0
- package/dist/database/orm/transaction-manager.d.ts +77 -0
- package/dist/database/orm/transaction-manager.d.ts.map +1 -0
- package/dist/database/orm/transaction-types.d.ts +136 -0
- package/dist/database/orm/transaction-types.d.ts.map +1 -0
- package/dist/database/orm/types.d.ts +95 -0
- package/dist/database/orm/types.d.ts.map +1 -0
- package/dist/database/service.d.ts +71 -0
- package/dist/database/service.d.ts.map +1 -0
- package/dist/database/types.d.ts +168 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/error/error-codes.d.ts +49 -3
- package/dist/error/error-codes.d.ts.map +1 -1
- package/dist/error/handler.d.ts.map +1 -1
- package/dist/error/http-exception.d.ts +26 -7
- package/dist/error/http-exception.d.ts.map +1 -1
- package/dist/error/i18n.d.ts +46 -2
- package/dist/error/i18n.d.ts.map +1 -1
- package/dist/error/index.d.ts +1 -1
- package/dist/error/index.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1705 -36
- package/dist/metrics/collector.d.ts +47 -0
- package/dist/metrics/collector.d.ts.map +1 -0
- package/dist/metrics/controller.d.ts +17 -0
- package/dist/metrics/controller.d.ts.map +1 -0
- package/dist/metrics/index.d.ts +7 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/metrics-module.d.ts +9 -0
- package/dist/metrics/metrics-module.d.ts.map +1 -0
- package/dist/metrics/middleware.d.ts +7 -0
- package/dist/metrics/middleware.d.ts.map +1 -0
- package/dist/metrics/prometheus.d.ts +23 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/types.d.ts +88 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/middleware/builtin/index.d.ts +1 -0
- package/dist/middleware/builtin/index.d.ts.map +1 -1
- package/dist/middleware/builtin/rate-limit.d.ts +104 -0
- package/dist/middleware/builtin/rate-limit.d.ts.map +1 -0
- package/dist/middleware/decorators.d.ts +7 -0
- package/dist/middleware/decorators.d.ts.map +1 -1
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/readme.md +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
2
4
|
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
3
18
|
var __export = (target, all) => {
|
|
4
19
|
for (var name in all)
|
|
5
20
|
__defProp(target, name, {
|
|
@@ -25,6 +40,7 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
25
40
|
return Reflect.metadata(k, v);
|
|
26
41
|
};
|
|
27
42
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
43
|
+
var __require = import.meta.require;
|
|
28
44
|
|
|
29
45
|
// src/validation/decorators.ts
|
|
30
46
|
import"reflect-metadata";
|
|
@@ -175,38 +191,98 @@ var init_error_codes = __esm(() => {
|
|
|
175
191
|
["INVALID_REQUEST" /* INVALID_REQUEST */]: 400,
|
|
176
192
|
["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: 404,
|
|
177
193
|
["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: 405,
|
|
194
|
+
["RATE_LIMIT_EXCEEDED" /* RATE_LIMIT_EXCEEDED */]: 429,
|
|
195
|
+
["SERVICE_UNAVAILABLE" /* SERVICE_UNAVAILABLE */]: 503,
|
|
196
|
+
["TIMEOUT" /* TIMEOUT */]: 408,
|
|
178
197
|
["AUTH_REQUIRED" /* AUTH_REQUIRED */]: 401,
|
|
179
198
|
["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: 401,
|
|
180
199
|
["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: 401,
|
|
181
200
|
["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: 403,
|
|
201
|
+
["AUTH_INVALID_CREDENTIALS" /* AUTH_INVALID_CREDENTIALS */]: 401,
|
|
202
|
+
["AUTH_ACCOUNT_LOCKED" /* AUTH_ACCOUNT_LOCKED */]: 423,
|
|
203
|
+
["AUTH_ACCOUNT_DISABLED" /* AUTH_ACCOUNT_DISABLED */]: 403,
|
|
182
204
|
["VALIDATION_FAILED" /* VALIDATION_FAILED */]: 400,
|
|
183
205
|
["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: 400,
|
|
184
206
|
["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: 400,
|
|
185
207
|
["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: 400,
|
|
208
|
+
["VALIDATION_TYPE_MISMATCH" /* VALIDATION_TYPE_MISMATCH */]: 400,
|
|
209
|
+
["VALIDATION_CONSTRAINT_VIOLATION" /* VALIDATION_CONSTRAINT_VIOLATION */]: 400,
|
|
186
210
|
["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: 400,
|
|
187
211
|
["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: 400,
|
|
188
212
|
["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: 400,
|
|
189
213
|
["OAUTH2_INVALID_REDIRECT_URI" /* OAUTH2_INVALID_REDIRECT_URI */]: 400,
|
|
190
|
-
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: 400
|
|
214
|
+
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: 400,
|
|
215
|
+
["OAUTH2_ACCESS_DENIED" /* OAUTH2_ACCESS_DENIED */]: 403,
|
|
216
|
+
["OAUTH2_SERVER_ERROR" /* OAUTH2_SERVER_ERROR */]: 500,
|
|
217
|
+
["DATABASE_CONNECTION_FAILED" /* DATABASE_CONNECTION_FAILED */]: 503,
|
|
218
|
+
["DATABASE_QUERY_FAILED" /* DATABASE_QUERY_FAILED */]: 500,
|
|
219
|
+
["DATABASE_TRANSACTION_FAILED" /* DATABASE_TRANSACTION_FAILED */]: 500,
|
|
220
|
+
["DATABASE_CONSTRAINT_VIOLATION" /* DATABASE_CONSTRAINT_VIOLATION */]: 409,
|
|
221
|
+
["DATABASE_TIMEOUT" /* DATABASE_TIMEOUT */]: 504,
|
|
222
|
+
["DATABASE_POOL_EXHAUSTED" /* DATABASE_POOL_EXHAUSTED */]: 503,
|
|
223
|
+
["DATABASE_MIGRATION_FAILED" /* DATABASE_MIGRATION_FAILED */]: 500,
|
|
224
|
+
["FILE_NOT_FOUND" /* FILE_NOT_FOUND */]: 404,
|
|
225
|
+
["FILE_UPLOAD_FAILED" /* FILE_UPLOAD_FAILED */]: 500,
|
|
226
|
+
["FILE_DOWNLOAD_FAILED" /* FILE_DOWNLOAD_FAILED */]: 500,
|
|
227
|
+
["FILE_SIZE_EXCEEDED" /* FILE_SIZE_EXCEEDED */]: 413,
|
|
228
|
+
["FILE_TYPE_NOT_ALLOWED" /* FILE_TYPE_NOT_ALLOWED */]: 415,
|
|
229
|
+
["FILE_ACCESS_DENIED" /* FILE_ACCESS_DENIED */]: 403,
|
|
230
|
+
["FILE_PATH_TRAVERSAL" /* FILE_PATH_TRAVERSAL */]: 400,
|
|
231
|
+
["MIDDLEWARE_EXECUTION_FAILED" /* MIDDLEWARE_EXECUTION_FAILED */]: 500,
|
|
232
|
+
["MIDDLEWARE_TIMEOUT" /* MIDDLEWARE_TIMEOUT */]: 504,
|
|
233
|
+
["CORS_NOT_ALLOWED" /* CORS_NOT_ALLOWED */]: 403,
|
|
234
|
+
["CONFIG_INVALID" /* CONFIG_INVALID */]: 500,
|
|
235
|
+
["CONFIG_MISSING" /* CONFIG_MISSING */]: 500,
|
|
236
|
+
["CONFIG_VALIDATION_FAILED" /* CONFIG_VALIDATION_FAILED */]: 500
|
|
191
237
|
};
|
|
192
238
|
ERROR_CODE_MESSAGES = {
|
|
193
239
|
["INTERNAL_ERROR" /* INTERNAL_ERROR */]: "Internal Server Error",
|
|
194
240
|
["INVALID_REQUEST" /* INVALID_REQUEST */]: "Invalid Request",
|
|
195
241
|
["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "Resource Not Found",
|
|
196
242
|
["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: "Method Not Allowed",
|
|
243
|
+
["RATE_LIMIT_EXCEEDED" /* RATE_LIMIT_EXCEEDED */]: "Rate Limit Exceeded",
|
|
244
|
+
["SERVICE_UNAVAILABLE" /* SERVICE_UNAVAILABLE */]: "Service Unavailable",
|
|
245
|
+
["TIMEOUT" /* TIMEOUT */]: "Request Timeout",
|
|
197
246
|
["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "Authentication Required",
|
|
198
247
|
["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "Invalid Authentication Token",
|
|
199
248
|
["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: "Authentication Token Expired",
|
|
200
249
|
["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: "Insufficient Permissions",
|
|
250
|
+
["AUTH_INVALID_CREDENTIALS" /* AUTH_INVALID_CREDENTIALS */]: "Invalid Credentials",
|
|
251
|
+
["AUTH_ACCOUNT_LOCKED" /* AUTH_ACCOUNT_LOCKED */]: "Account Locked",
|
|
252
|
+
["AUTH_ACCOUNT_DISABLED" /* AUTH_ACCOUNT_DISABLED */]: "Account Disabled",
|
|
201
253
|
["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "Validation Failed",
|
|
202
254
|
["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: "Required Field Missing",
|
|
203
255
|
["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: "Invalid Format",
|
|
204
256
|
["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: "Value Out of Range",
|
|
257
|
+
["VALIDATION_TYPE_MISMATCH" /* VALIDATION_TYPE_MISMATCH */]: "Type Mismatch",
|
|
258
|
+
["VALIDATION_CONSTRAINT_VIOLATION" /* VALIDATION_CONSTRAINT_VIOLATION */]: "Constraint Violation",
|
|
205
259
|
["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: "Invalid Client",
|
|
206
260
|
["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: "Invalid Grant",
|
|
207
261
|
["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: "Invalid Scope",
|
|
208
262
|
["OAUTH2_INVALID_REDIRECT_URI" /* OAUTH2_INVALID_REDIRECT_URI */]: "Invalid Redirect URI",
|
|
209
|
-
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: "Unsupported Grant Type"
|
|
263
|
+
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: "Unsupported Grant Type",
|
|
264
|
+
["OAUTH2_ACCESS_DENIED" /* OAUTH2_ACCESS_DENIED */]: "Access Denied",
|
|
265
|
+
["OAUTH2_SERVER_ERROR" /* OAUTH2_SERVER_ERROR */]: "OAuth2 Server Error",
|
|
266
|
+
["DATABASE_CONNECTION_FAILED" /* DATABASE_CONNECTION_FAILED */]: "Database Connection Failed",
|
|
267
|
+
["DATABASE_QUERY_FAILED" /* DATABASE_QUERY_FAILED */]: "Database Query Failed",
|
|
268
|
+
["DATABASE_TRANSACTION_FAILED" /* DATABASE_TRANSACTION_FAILED */]: "Database Transaction Failed",
|
|
269
|
+
["DATABASE_CONSTRAINT_VIOLATION" /* DATABASE_CONSTRAINT_VIOLATION */]: "Database Constraint Violation",
|
|
270
|
+
["DATABASE_TIMEOUT" /* DATABASE_TIMEOUT */]: "Database Timeout",
|
|
271
|
+
["DATABASE_POOL_EXHAUSTED" /* DATABASE_POOL_EXHAUSTED */]: "Database Connection Pool Exhausted",
|
|
272
|
+
["DATABASE_MIGRATION_FAILED" /* DATABASE_MIGRATION_FAILED */]: "Database Migration Failed",
|
|
273
|
+
["FILE_NOT_FOUND" /* FILE_NOT_FOUND */]: "File Not Found",
|
|
274
|
+
["FILE_UPLOAD_FAILED" /* FILE_UPLOAD_FAILED */]: "File Upload Failed",
|
|
275
|
+
["FILE_DOWNLOAD_FAILED" /* FILE_DOWNLOAD_FAILED */]: "File Download Failed",
|
|
276
|
+
["FILE_SIZE_EXCEEDED" /* FILE_SIZE_EXCEEDED */]: "File Size Exceeded",
|
|
277
|
+
["FILE_TYPE_NOT_ALLOWED" /* FILE_TYPE_NOT_ALLOWED */]: "File Type Not Allowed",
|
|
278
|
+
["FILE_ACCESS_DENIED" /* FILE_ACCESS_DENIED */]: "File Access Denied",
|
|
279
|
+
["FILE_PATH_TRAVERSAL" /* FILE_PATH_TRAVERSAL */]: "Path Traversal Detected",
|
|
280
|
+
["MIDDLEWARE_EXECUTION_FAILED" /* MIDDLEWARE_EXECUTION_FAILED */]: "Middleware Execution Failed",
|
|
281
|
+
["MIDDLEWARE_TIMEOUT" /* MIDDLEWARE_TIMEOUT */]: "Middleware Timeout",
|
|
282
|
+
["CORS_NOT_ALLOWED" /* CORS_NOT_ALLOWED */]: "CORS Not Allowed",
|
|
283
|
+
["CONFIG_INVALID" /* CONFIG_INVALID */]: "Invalid Configuration",
|
|
284
|
+
["CONFIG_MISSING" /* CONFIG_MISSING */]: "Missing Configuration",
|
|
285
|
+
["CONFIG_VALIDATION_FAILED" /* CONFIG_VALIDATION_FAILED */]: "Configuration Validation Failed"
|
|
210
286
|
};
|
|
211
287
|
});
|
|
212
288
|
|
|
@@ -218,42 +294,44 @@ var init_http_exception = __esm(() => {
|
|
|
218
294
|
status;
|
|
219
295
|
code;
|
|
220
296
|
details;
|
|
221
|
-
|
|
297
|
+
messageParams;
|
|
298
|
+
constructor(status, message, details, code, messageParams) {
|
|
222
299
|
super(message);
|
|
223
300
|
this.name = this.constructor.name;
|
|
224
301
|
this.status = status;
|
|
225
302
|
this.code = code;
|
|
226
303
|
this.details = details;
|
|
304
|
+
this.messageParams = messageParams;
|
|
227
305
|
}
|
|
228
|
-
static withCode(code, message, details) {
|
|
306
|
+
static withCode(code, message, details, messageParams) {
|
|
229
307
|
const status = ERROR_CODE_TO_STATUS[code] || 500;
|
|
230
308
|
const finalMessage = message || ERROR_CODE_MESSAGES[code] || "Internal Server Error";
|
|
231
|
-
return new HttpException(status, finalMessage, details, code);
|
|
309
|
+
return new HttpException(status, finalMessage, details, code, messageParams);
|
|
232
310
|
}
|
|
233
311
|
};
|
|
234
312
|
BadRequestException = class BadRequestException extends HttpException {
|
|
235
|
-
constructor(message = "Bad Request", details, code) {
|
|
236
|
-
super(400, message, details, code);
|
|
313
|
+
constructor(message = "Bad Request", details, code, messageParams) {
|
|
314
|
+
super(400, message, details, code, messageParams);
|
|
237
315
|
}
|
|
238
316
|
};
|
|
239
317
|
UnauthorizedException = class UnauthorizedException extends HttpException {
|
|
240
|
-
constructor(message = "Unauthorized", details, code) {
|
|
241
|
-
super(401, message, details, code);
|
|
318
|
+
constructor(message = "Unauthorized", details, code, messageParams) {
|
|
319
|
+
super(401, message, details, code, messageParams);
|
|
242
320
|
}
|
|
243
321
|
};
|
|
244
322
|
ForbiddenException = class ForbiddenException extends HttpException {
|
|
245
|
-
constructor(message = "Forbidden", details, code) {
|
|
246
|
-
super(403, message, details, code);
|
|
323
|
+
constructor(message = "Forbidden", details, code, messageParams) {
|
|
324
|
+
super(403, message, details, code, messageParams);
|
|
247
325
|
}
|
|
248
326
|
};
|
|
249
327
|
NotFoundException = class NotFoundException extends HttpException {
|
|
250
|
-
constructor(message = "Not Found", details, code) {
|
|
251
|
-
super(404, message, details, code);
|
|
328
|
+
constructor(message = "Not Found", details, code, messageParams) {
|
|
329
|
+
super(404, message, details, code, messageParams);
|
|
252
330
|
}
|
|
253
331
|
};
|
|
254
332
|
InternalServerErrorException = class InternalServerErrorException extends HttpException {
|
|
255
|
-
constructor(message = "Internal Server Error", details, code) {
|
|
256
|
-
super(500, message, details, code);
|
|
333
|
+
constructor(message = "Internal Server Error", details, code, messageParams) {
|
|
334
|
+
super(500, message, details, code, messageParams);
|
|
257
335
|
}
|
|
258
336
|
};
|
|
259
337
|
});
|
|
@@ -295,18 +373,35 @@ class ErrorMessageI18n {
|
|
|
295
373
|
static getLanguage() {
|
|
296
374
|
return this.currentLanguage;
|
|
297
375
|
}
|
|
298
|
-
static getMessage(code, language) {
|
|
376
|
+
static getMessage(code, language, params) {
|
|
299
377
|
const lang = language || this.currentLanguage;
|
|
300
378
|
const messages = ERROR_MESSAGES_I18N[lang];
|
|
301
|
-
|
|
379
|
+
let message = messages?.[code] || ERROR_CODE_MESSAGES[code] || "Internal Server Error";
|
|
380
|
+
if (params) {
|
|
381
|
+
message = this.replaceTemplate(message, params);
|
|
382
|
+
}
|
|
383
|
+
return message;
|
|
384
|
+
}
|
|
385
|
+
static replaceTemplate(template, params) {
|
|
386
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
387
|
+
const value = params[key];
|
|
388
|
+
return value !== undefined ? String(value) : match;
|
|
389
|
+
});
|
|
302
390
|
}
|
|
303
391
|
static parseLanguageFromHeader(acceptLanguage) {
|
|
304
392
|
if (!acceptLanguage) {
|
|
305
393
|
return "en";
|
|
306
394
|
}
|
|
307
|
-
|
|
395
|
+
const lowerAcceptLanguage = acceptLanguage.toLowerCase();
|
|
396
|
+
if (lowerAcceptLanguage.includes("zh-cn") || lowerAcceptLanguage.includes("zh")) {
|
|
308
397
|
return "zh-CN";
|
|
309
398
|
}
|
|
399
|
+
if (lowerAcceptLanguage.includes("ja")) {
|
|
400
|
+
return "ja";
|
|
401
|
+
}
|
|
402
|
+
if (lowerAcceptLanguage.includes("ko")) {
|
|
403
|
+
return "ko";
|
|
404
|
+
}
|
|
310
405
|
return "en";
|
|
311
406
|
}
|
|
312
407
|
}
|
|
@@ -322,19 +417,65 @@ var init_i18n = __esm(() => {
|
|
|
322
417
|
["INVALID_REQUEST" /* INVALID_REQUEST */]: "\u65E0\u6548\u7684\u8BF7\u6C42",
|
|
323
418
|
["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "\u8D44\u6E90\u672A\u627E\u5230",
|
|
324
419
|
["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: "\u65B9\u6CD5\u4E0D\u5141\u8BB8",
|
|
420
|
+
["RATE_LIMIT_EXCEEDED" /* RATE_LIMIT_EXCEEDED */]: "\u8BF7\u6C42\u9891\u7387\u8D85\u9650",
|
|
421
|
+
["SERVICE_UNAVAILABLE" /* SERVICE_UNAVAILABLE */]: "\u670D\u52A1\u4E0D\u53EF\u7528",
|
|
422
|
+
["TIMEOUT" /* TIMEOUT */]: "\u8BF7\u6C42\u8D85\u65F6",
|
|
325
423
|
["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "\u9700\u8981\u8BA4\u8BC1",
|
|
326
424
|
["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "\u65E0\u6548\u7684\u8BA4\u8BC1\u4EE4\u724C",
|
|
327
425
|
["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: "\u8BA4\u8BC1\u4EE4\u724C\u5DF2\u8FC7\u671F",
|
|
328
426
|
["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: "\u6743\u9650\u4E0D\u8DB3",
|
|
427
|
+
["AUTH_INVALID_CREDENTIALS" /* AUTH_INVALID_CREDENTIALS */]: "\u65E0\u6548\u7684\u51ED\u636E",
|
|
428
|
+
["AUTH_ACCOUNT_LOCKED" /* AUTH_ACCOUNT_LOCKED */]: "\u8D26\u6237\u5DF2\u9501\u5B9A",
|
|
429
|
+
["AUTH_ACCOUNT_DISABLED" /* AUTH_ACCOUNT_DISABLED */]: "\u8D26\u6237\u5DF2\u7981\u7528",
|
|
329
430
|
["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "\u9A8C\u8BC1\u5931\u8D25",
|
|
330
431
|
["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: "\u5FC5\u586B\u5B57\u6BB5\u7F3A\u5931",
|
|
331
432
|
["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: "\u683C\u5F0F\u65E0\u6548",
|
|
332
433
|
["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: "\u503C\u8D85\u51FA\u8303\u56F4",
|
|
434
|
+
["VALIDATION_TYPE_MISMATCH" /* VALIDATION_TYPE_MISMATCH */]: "\u7C7B\u578B\u4E0D\u5339\u914D",
|
|
435
|
+
["VALIDATION_CONSTRAINT_VIOLATION" /* VALIDATION_CONSTRAINT_VIOLATION */]: "\u7EA6\u675F\u8FDD\u53CD",
|
|
333
436
|
["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: "\u65E0\u6548\u7684\u5BA2\u6237\u7AEF",
|
|
334
437
|
["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: "\u65E0\u6548\u7684\u6388\u6743",
|
|
335
438
|
["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: "\u65E0\u6548\u7684\u4F5C\u7528\u57DF",
|
|
336
439
|
["OAUTH2_INVALID_REDIRECT_URI" /* OAUTH2_INVALID_REDIRECT_URI */]: "\u65E0\u6548\u7684\u91CD\u5B9A\u5411 URI",
|
|
337
|
-
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: "\u4E0D\u652F\u6301\u7684\u6388\u6743\u7C7B\u578B"
|
|
440
|
+
["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: "\u4E0D\u652F\u6301\u7684\u6388\u6743\u7C7B\u578B",
|
|
441
|
+
["OAUTH2_ACCESS_DENIED" /* OAUTH2_ACCESS_DENIED */]: "\u8BBF\u95EE\u88AB\u62D2\u7EDD",
|
|
442
|
+
["OAUTH2_SERVER_ERROR" /* OAUTH2_SERVER_ERROR */]: "OAuth2 \u670D\u52A1\u5668\u9519\u8BEF",
|
|
443
|
+
["DATABASE_CONNECTION_FAILED" /* DATABASE_CONNECTION_FAILED */]: "\u6570\u636E\u5E93\u8FDE\u63A5\u5931\u8D25",
|
|
444
|
+
["DATABASE_QUERY_FAILED" /* DATABASE_QUERY_FAILED */]: "\u6570\u636E\u5E93\u67E5\u8BE2\u5931\u8D25",
|
|
445
|
+
["DATABASE_TRANSACTION_FAILED" /* DATABASE_TRANSACTION_FAILED */]: "\u6570\u636E\u5E93\u4E8B\u52A1\u5931\u8D25",
|
|
446
|
+
["DATABASE_CONSTRAINT_VIOLATION" /* DATABASE_CONSTRAINT_VIOLATION */]: "\u6570\u636E\u5E93\u7EA6\u675F\u8FDD\u53CD",
|
|
447
|
+
["DATABASE_TIMEOUT" /* DATABASE_TIMEOUT */]: "\u6570\u636E\u5E93\u8D85\u65F6",
|
|
448
|
+
["DATABASE_POOL_EXHAUSTED" /* DATABASE_POOL_EXHAUSTED */]: "\u6570\u636E\u5E93\u8FDE\u63A5\u6C60\u8017\u5C3D",
|
|
449
|
+
["DATABASE_MIGRATION_FAILED" /* DATABASE_MIGRATION_FAILED */]: "\u6570\u636E\u5E93\u8FC1\u79FB\u5931\u8D25",
|
|
450
|
+
["FILE_NOT_FOUND" /* FILE_NOT_FOUND */]: "\u6587\u4EF6\u672A\u627E\u5230",
|
|
451
|
+
["FILE_UPLOAD_FAILED" /* FILE_UPLOAD_FAILED */]: "\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25",
|
|
452
|
+
["FILE_DOWNLOAD_FAILED" /* FILE_DOWNLOAD_FAILED */]: "\u6587\u4EF6\u4E0B\u8F7D\u5931\u8D25",
|
|
453
|
+
["FILE_SIZE_EXCEEDED" /* FILE_SIZE_EXCEEDED */]: "\u6587\u4EF6\u5927\u5C0F\u8D85\u9650",
|
|
454
|
+
["FILE_TYPE_NOT_ALLOWED" /* FILE_TYPE_NOT_ALLOWED */]: "\u4E0D\u5141\u8BB8\u7684\u6587\u4EF6\u7C7B\u578B",
|
|
455
|
+
["FILE_ACCESS_DENIED" /* FILE_ACCESS_DENIED */]: "\u6587\u4EF6\u8BBF\u95EE\u88AB\u62D2\u7EDD",
|
|
456
|
+
["FILE_PATH_TRAVERSAL" /* FILE_PATH_TRAVERSAL */]: "\u68C0\u6D4B\u5230\u8DEF\u5F84\u904D\u5386\u653B\u51FB",
|
|
457
|
+
["MIDDLEWARE_EXECUTION_FAILED" /* MIDDLEWARE_EXECUTION_FAILED */]: "\u4E2D\u95F4\u4EF6\u6267\u884C\u5931\u8D25",
|
|
458
|
+
["MIDDLEWARE_TIMEOUT" /* MIDDLEWARE_TIMEOUT */]: "\u4E2D\u95F4\u4EF6\u8D85\u65F6",
|
|
459
|
+
["CORS_NOT_ALLOWED" /* CORS_NOT_ALLOWED */]: "CORS \u4E0D\u5141\u8BB8",
|
|
460
|
+
["CONFIG_INVALID" /* CONFIG_INVALID */]: "\u65E0\u6548\u7684\u914D\u7F6E",
|
|
461
|
+
["CONFIG_MISSING" /* CONFIG_MISSING */]: "\u7F3A\u5C11\u914D\u7F6E",
|
|
462
|
+
["CONFIG_VALIDATION_FAILED" /* CONFIG_VALIDATION_FAILED */]: "\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25"
|
|
463
|
+
},
|
|
464
|
+
ja: {
|
|
465
|
+
["INTERNAL_ERROR" /* INTERNAL_ERROR */]: "\u30B5\u30FC\u30D0\u30FC\u5185\u90E8\u30A8\u30E9\u30FC",
|
|
466
|
+
["INVALID_REQUEST" /* INVALID_REQUEST */]: "\u7121\u52B9\u306A\u30EA\u30AF\u30A8\u30B9\u30C8",
|
|
467
|
+
["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "\u30EA\u30BD\u30FC\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
|
|
468
|
+
["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059",
|
|
469
|
+
["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "\u7121\u52B9\u306A\u8A8D\u8A3C\u30C8\u30FC\u30AF\u30F3",
|
|
470
|
+
["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
471
|
+
},
|
|
472
|
+
ko: {
|
|
473
|
+
["INTERNAL_ERROR" /* INTERNAL_ERROR */]: "\uC11C\uBC84 \uB0B4\uBD80 \uC624\uB958",
|
|
474
|
+
["INVALID_REQUEST" /* INVALID_REQUEST */]: "\uC798\uBABB\uB41C \uC694\uCCAD",
|
|
475
|
+
["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "\uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
476
|
+
["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4",
|
|
477
|
+
["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "\uC798\uBABB\uB41C \uC778\uC99D \uD1A0\uD070",
|
|
478
|
+
["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "\uC720\uD6A8\uC131 \uAC80\uC0AC \uC2E4\uD328"
|
|
338
479
|
}
|
|
339
480
|
};
|
|
340
481
|
});
|
|
@@ -356,7 +497,7 @@ async function handleError(error, context) {
|
|
|
356
497
|
if (error.code) {
|
|
357
498
|
const acceptLanguage = context.getHeader("accept-language");
|
|
358
499
|
const language = ErrorMessageI18n.parseLanguageFromHeader(acceptLanguage);
|
|
359
|
-
errorMessage = ErrorMessageI18n.getMessage(error.code, language);
|
|
500
|
+
errorMessage = ErrorMessageI18n.getMessage(error.code, language, error.messageParams);
|
|
360
501
|
}
|
|
361
502
|
const responseBody = {
|
|
362
503
|
error: errorMessage
|
|
@@ -390,6 +531,181 @@ var init_handler = __esm(() => {
|
|
|
390
531
|
init_i18n();
|
|
391
532
|
});
|
|
392
533
|
|
|
534
|
+
// src/database/orm/transaction-types.ts
|
|
535
|
+
var Propagation, IsolationLevel, TransactionStatus, TRANSACTION_SERVICE_TOKEN;
|
|
536
|
+
var init_transaction_types = __esm(() => {
|
|
537
|
+
((Propagation2) => {
|
|
538
|
+
Propagation2["REQUIRED"] = "REQUIRED";
|
|
539
|
+
Propagation2["REQUIRES_NEW"] = "REQUIRES_NEW";
|
|
540
|
+
Propagation2["SUPPORTS"] = "SUPPORTS";
|
|
541
|
+
Propagation2["NOT_SUPPORTED"] = "NOT_SUPPORTED";
|
|
542
|
+
Propagation2["NEVER"] = "NEVER";
|
|
543
|
+
Propagation2["NESTED"] = "NESTED";
|
|
544
|
+
})(Propagation ||= {});
|
|
545
|
+
((IsolationLevel2) => {
|
|
546
|
+
IsolationLevel2["READ_UNCOMMITTED"] = "READ_UNCOMMITTED";
|
|
547
|
+
IsolationLevel2["READ_COMMITTED"] = "READ_COMMITTED";
|
|
548
|
+
IsolationLevel2["REPEATABLE_READ"] = "REPEATABLE_READ";
|
|
549
|
+
IsolationLevel2["SERIALIZABLE"] = "SERIALIZABLE";
|
|
550
|
+
})(IsolationLevel ||= {});
|
|
551
|
+
((TransactionStatus2) => {
|
|
552
|
+
TransactionStatus2["ACTIVE"] = "ACTIVE";
|
|
553
|
+
TransactionStatus2["COMMITTED"] = "COMMITTED";
|
|
554
|
+
TransactionStatus2["ROLLED_BACK"] = "ROLLED_BACK";
|
|
555
|
+
TransactionStatus2["SUSPENDED"] = "SUSPENDED";
|
|
556
|
+
})(TransactionStatus ||= {});
|
|
557
|
+
TRANSACTION_SERVICE_TOKEN = Symbol("@dangao/bun-server:orm:transaction:service");
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// src/database/orm/transaction-decorator.ts
|
|
561
|
+
var exports_transaction_decorator = {};
|
|
562
|
+
__export(exports_transaction_decorator, {
|
|
563
|
+
getTransactionMetadata: () => getTransactionMetadata,
|
|
564
|
+
Transactional: () => Transactional,
|
|
565
|
+
TRANSACTION_METADATA_KEY: () => TRANSACTION_METADATA_KEY
|
|
566
|
+
});
|
|
567
|
+
import"reflect-metadata";
|
|
568
|
+
function Transactional(options) {
|
|
569
|
+
return (target, propertyKey, descriptor) => {
|
|
570
|
+
if (!descriptor || typeof descriptor.value !== "function") {
|
|
571
|
+
throw new Error("@Transactional() can only be applied to methods");
|
|
572
|
+
}
|
|
573
|
+
const metadata = {
|
|
574
|
+
propagation: options?.propagation ?? "REQUIRED" /* REQUIRED */,
|
|
575
|
+
isolationLevel: options?.isolationLevel,
|
|
576
|
+
timeout: options?.timeout,
|
|
577
|
+
readOnly: options?.readOnly ?? false,
|
|
578
|
+
rollbackFor: options?.rollbackFor ?? [],
|
|
579
|
+
noRollbackFor: options?.noRollbackFor ?? []
|
|
580
|
+
};
|
|
581
|
+
Reflect.defineMetadata(TRANSACTION_METADATA_KEY, metadata, target, propertyKey);
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function getTransactionMetadata(target, propertyKey) {
|
|
585
|
+
if (typeof target === "object" && target !== null) {
|
|
586
|
+
return Reflect.getMetadata(TRANSACTION_METADATA_KEY, target, propertyKey);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
var TRANSACTION_METADATA_KEY;
|
|
591
|
+
var init_transaction_decorator = __esm(() => {
|
|
592
|
+
init_transaction_types();
|
|
593
|
+
TRANSACTION_METADATA_KEY = Symbol("@dangao/bun-server:orm:transaction");
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// src/database/orm/transaction-interceptor.ts
|
|
597
|
+
var exports_transaction_interceptor = {};
|
|
598
|
+
__export(exports_transaction_interceptor, {
|
|
599
|
+
TransactionInterceptor: () => TransactionInterceptor
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
class TransactionInterceptor {
|
|
603
|
+
static async executeWithTransaction(target, propertyKey, originalMethod, args, container) {
|
|
604
|
+
const transactionMetadata = getTransactionMetadata(target, propertyKey);
|
|
605
|
+
if (!transactionMetadata) {
|
|
606
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
607
|
+
}
|
|
608
|
+
let transactionManager;
|
|
609
|
+
try {
|
|
610
|
+
transactionManager = container.resolve(TRANSACTION_SERVICE_TOKEN);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
console.warn("TransactionManager not found, executing without transaction");
|
|
613
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
614
|
+
}
|
|
615
|
+
const propagation = transactionMetadata.propagation ?? "REQUIRED" /* REQUIRED */;
|
|
616
|
+
const currentTransaction = transactionManager.getCurrentTransaction();
|
|
617
|
+
switch (propagation) {
|
|
618
|
+
case "REQUIRED" /* REQUIRED */:
|
|
619
|
+
if (currentTransaction) {
|
|
620
|
+
return await this.executeInExistingTransaction(originalMethod, target, args, currentTransaction.id, transactionManager);
|
|
621
|
+
} else {
|
|
622
|
+
return await this.executeInNewTransaction(originalMethod, target, args, transactionMetadata, transactionManager);
|
|
623
|
+
}
|
|
624
|
+
case "REQUIRES_NEW" /* REQUIRES_NEW */:
|
|
625
|
+
return await this.executeInNewTransaction(originalMethod, target, args, transactionMetadata, transactionManager);
|
|
626
|
+
case "SUPPORTS" /* SUPPORTS */:
|
|
627
|
+
if (currentTransaction) {
|
|
628
|
+
return await this.executeInExistingTransaction(originalMethod, target, args, currentTransaction.id, transactionManager);
|
|
629
|
+
} else {
|
|
630
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
631
|
+
}
|
|
632
|
+
case "NOT_SUPPORTED" /* NOT_SUPPORTED */:
|
|
633
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
634
|
+
case "NEVER" /* NEVER */:
|
|
635
|
+
if (currentTransaction) {
|
|
636
|
+
throw new Error("Transaction propagation NEVER requires no existing transaction");
|
|
637
|
+
}
|
|
638
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
639
|
+
case "NESTED" /* NESTED */:
|
|
640
|
+
if (currentTransaction) {
|
|
641
|
+
return await this.executeInNestedTransaction(originalMethod, target, args, currentTransaction.id, transactionMetadata, transactionManager);
|
|
642
|
+
} else {
|
|
643
|
+
return await this.executeInNewTransaction(originalMethod, target, args, transactionMetadata, transactionManager);
|
|
644
|
+
}
|
|
645
|
+
default:
|
|
646
|
+
return await Promise.resolve(originalMethod.apply(target, args));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
static async executeInNewTransaction(method, target, args, options, transactionManager) {
|
|
650
|
+
const context = await transactionManager.beginTransaction({
|
|
651
|
+
timeout: options.timeout
|
|
652
|
+
});
|
|
653
|
+
try {
|
|
654
|
+
const result = await Promise.resolve(method.apply(target, args));
|
|
655
|
+
await transactionManager.commitTransaction(context.id);
|
|
656
|
+
return result;
|
|
657
|
+
} catch (error) {
|
|
658
|
+
if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
|
|
659
|
+
await transactionManager.rollbackTransaction(context.id);
|
|
660
|
+
} else {
|
|
661
|
+
await transactionManager.commitTransaction(context.id);
|
|
662
|
+
}
|
|
663
|
+
throw error;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
static async executeInExistingTransaction(method, target, args, transactionId, transactionManager) {
|
|
667
|
+
return await Promise.resolve(method.apply(target, args));
|
|
668
|
+
}
|
|
669
|
+
static async executeInNestedTransaction(method, target, args, parentTransactionId, options, transactionManager) {
|
|
670
|
+
const savepointName = await transactionManager.createSavepoint(parentTransactionId);
|
|
671
|
+
try {
|
|
672
|
+
const result = await Promise.resolve(method.apply(target, args));
|
|
673
|
+
return result;
|
|
674
|
+
} catch (error) {
|
|
675
|
+
if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
|
|
676
|
+
await transactionManager.rollbackToSavepoint(parentTransactionId, savepointName);
|
|
677
|
+
}
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
static shouldRollback(error, rollbackFor, noRollbackFor) {
|
|
682
|
+
if (!error) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
if (noRollbackFor && noRollbackFor.length > 0) {
|
|
686
|
+
for (const ErrorClass of noRollbackFor) {
|
|
687
|
+
if (error instanceof ErrorClass) {
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (rollbackFor && rollbackFor.length > 0) {
|
|
693
|
+
for (const ErrorClass of rollbackFor) {
|
|
694
|
+
if (error instanceof ErrorClass) {
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
var init_transaction_interceptor = __esm(() => {
|
|
704
|
+
init_transaction_types();
|
|
705
|
+
init_transaction_decorator();
|
|
706
|
+
init_transaction_types();
|
|
707
|
+
});
|
|
708
|
+
|
|
393
709
|
// src/request/body-parser.ts
|
|
394
710
|
class BodyParser {
|
|
395
711
|
static async parse(request) {
|
|
@@ -525,6 +841,17 @@ class Context {
|
|
|
525
841
|
getHeader(key) {
|
|
526
842
|
return this.headers.get(key);
|
|
527
843
|
}
|
|
844
|
+
getClientIp() {
|
|
845
|
+
const forwardedFor = this.getHeader("X-Forwarded-For");
|
|
846
|
+
if (forwardedFor) {
|
|
847
|
+
return forwardedFor.split(",")[0].trim();
|
|
848
|
+
}
|
|
849
|
+
const realIp = this.getHeader("X-Real-IP");
|
|
850
|
+
if (realIp) {
|
|
851
|
+
return realIp.trim();
|
|
852
|
+
}
|
|
853
|
+
return "unknown";
|
|
854
|
+
}
|
|
528
855
|
setHeader(key, value) {
|
|
529
856
|
this.responseHeaders.set(key, value);
|
|
530
857
|
}
|
|
@@ -1325,6 +1652,112 @@ function getRouteMetadata(target) {
|
|
|
1325
1652
|
}
|
|
1326
1653
|
// src/middleware/decorators.ts
|
|
1327
1654
|
import"reflect-metadata";
|
|
1655
|
+
|
|
1656
|
+
// src/middleware/builtin/rate-limit.ts
|
|
1657
|
+
class MemoryRateLimitStore {
|
|
1658
|
+
store = new Map;
|
|
1659
|
+
async get(key) {
|
|
1660
|
+
const entry = this.store.get(key);
|
|
1661
|
+
if (!entry) {
|
|
1662
|
+
return 0;
|
|
1663
|
+
}
|
|
1664
|
+
if (Date.now() > entry.resetTime) {
|
|
1665
|
+
this.store.delete(key);
|
|
1666
|
+
return 0;
|
|
1667
|
+
}
|
|
1668
|
+
return entry.count;
|
|
1669
|
+
}
|
|
1670
|
+
async increment(key, windowMs) {
|
|
1671
|
+
const now = Date.now();
|
|
1672
|
+
const entry = this.store.get(key);
|
|
1673
|
+
if (!entry || now > entry.resetTime) {
|
|
1674
|
+
const resetTime = now + windowMs;
|
|
1675
|
+
this.store.set(key, { count: 1, resetTime });
|
|
1676
|
+
return 1;
|
|
1677
|
+
}
|
|
1678
|
+
entry.count++;
|
|
1679
|
+
return entry.count;
|
|
1680
|
+
}
|
|
1681
|
+
async reset(key) {
|
|
1682
|
+
this.store.delete(key);
|
|
1683
|
+
}
|
|
1684
|
+
cleanup() {
|
|
1685
|
+
const now = Date.now();
|
|
1686
|
+
for (const [key, entry] of this.store.entries()) {
|
|
1687
|
+
if (now > entry.resetTime) {
|
|
1688
|
+
this.store.delete(key);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
function defaultKeyGenerator(context) {
|
|
1694
|
+
return `rate-limit:${context.getClientIp()}`;
|
|
1695
|
+
}
|
|
1696
|
+
function createRateLimitMiddleware(options) {
|
|
1697
|
+
const {
|
|
1698
|
+
max,
|
|
1699
|
+
windowMs = 60000,
|
|
1700
|
+
store = new MemoryRateLimitStore,
|
|
1701
|
+
keyGenerator = defaultKeyGenerator,
|
|
1702
|
+
skipSuccessfulRequests = false,
|
|
1703
|
+
skipFailedRequests = false,
|
|
1704
|
+
message = "Too Many Requests",
|
|
1705
|
+
statusCode = 429,
|
|
1706
|
+
standardHeaders = true,
|
|
1707
|
+
legacyHeaders = true
|
|
1708
|
+
} = options;
|
|
1709
|
+
return async (context, next) => {
|
|
1710
|
+
const key = await keyGenerator(context);
|
|
1711
|
+
const currentCount = await store.increment(key, windowMs);
|
|
1712
|
+
const remaining = Math.max(0, max - currentCount);
|
|
1713
|
+
const resetTime = Date.now() + windowMs;
|
|
1714
|
+
if (standardHeaders) {
|
|
1715
|
+
context.setHeader("RateLimit-Limit", max.toString());
|
|
1716
|
+
context.setHeader("RateLimit-Remaining", remaining.toString());
|
|
1717
|
+
context.setHeader("RateLimit-Reset", Math.ceil(resetTime / 1000).toString());
|
|
1718
|
+
}
|
|
1719
|
+
if (legacyHeaders) {
|
|
1720
|
+
context.setHeader("X-RateLimit-Limit", max.toString());
|
|
1721
|
+
context.setHeader("X-RateLimit-Remaining", remaining.toString());
|
|
1722
|
+
context.setHeader("X-RateLimit-Reset", Math.ceil(resetTime / 1000).toString());
|
|
1723
|
+
}
|
|
1724
|
+
if (currentCount > max) {
|
|
1725
|
+
context.setStatus(statusCode);
|
|
1726
|
+
return context.createResponse({
|
|
1727
|
+
error: message,
|
|
1728
|
+
retryAfter: Math.ceil(windowMs / 1000)
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
const response = await next();
|
|
1732
|
+
const shouldSkip = skipSuccessfulRequests && response.status >= 200 && response.status < 300 || skipFailedRequests && response.status >= 400;
|
|
1733
|
+
if (shouldSkip) {
|
|
1734
|
+
const current = await store.get(key);
|
|
1735
|
+
if (current > 0) {}
|
|
1736
|
+
}
|
|
1737
|
+
return response;
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
function createTokenKeyGenerator(tokenHeader = "Authorization") {
|
|
1741
|
+
return (context) => {
|
|
1742
|
+
const token = context.getHeader(tokenHeader);
|
|
1743
|
+
if (token) {
|
|
1744
|
+
const tokenValue = token.startsWith("Bearer ") ? token.substring(7) : token;
|
|
1745
|
+
return `rate-limit:token:${tokenValue}`;
|
|
1746
|
+
}
|
|
1747
|
+
return defaultKeyGenerator(context);
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
function createUserKeyGenerator(getUserId) {
|
|
1751
|
+
return (context) => {
|
|
1752
|
+
const userId = getUserId(context);
|
|
1753
|
+
if (userId) {
|
|
1754
|
+
return `rate-limit:user:${userId}`;
|
|
1755
|
+
}
|
|
1756
|
+
return defaultKeyGenerator(context);
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// src/middleware/decorators.ts
|
|
1328
1761
|
var CLASS_MIDDLEWARE_METADATA_KEY = Symbol("middleware:class");
|
|
1329
1762
|
var METHOD_MIDDLEWARE_METADATA_KEY = Symbol("middleware:method");
|
|
1330
1763
|
function appendMiddlewareMetadata(target, propertyKey, middlewares) {
|
|
@@ -1344,6 +1777,12 @@ function UseMiddleware(...middlewares) {
|
|
|
1344
1777
|
appendMiddlewareMetadata(propertyKey === undefined ? target : target, propertyKey, middlewares);
|
|
1345
1778
|
};
|
|
1346
1779
|
}
|
|
1780
|
+
function RateLimit(options) {
|
|
1781
|
+
return function(target, propertyKey) {
|
|
1782
|
+
const middleware = createRateLimitMiddleware(options);
|
|
1783
|
+
appendMiddlewareMetadata(target, propertyKey, [middleware]);
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1347
1786
|
function getClassMiddlewares(constructor) {
|
|
1348
1787
|
return Reflect.getMetadata(CLASS_MIDDLEWARE_METADATA_KEY, constructor) || [];
|
|
1349
1788
|
}
|
|
@@ -1690,7 +2129,19 @@ class ControllerRegistry {
|
|
|
1690
2129
|
if (!method || typeof method !== "function") {
|
|
1691
2130
|
throw new Error(`Method ${propertyKey} not found on controller ${controllerClass.name}`);
|
|
1692
2131
|
}
|
|
1693
|
-
|
|
2132
|
+
let result;
|
|
2133
|
+
try {
|
|
2134
|
+
const { TransactionInterceptor: TransactionInterceptor2 } = await Promise.resolve().then(() => (init_transaction_interceptor(), exports_transaction_interceptor));
|
|
2135
|
+
const { getTransactionMetadata: getTransactionMetadata2 } = await Promise.resolve().then(() => (init_transaction_decorator(), exports_transaction_decorator));
|
|
2136
|
+
const hasTransaction = getTransactionMetadata2(prototype2, propertyKey);
|
|
2137
|
+
if (hasTransaction) {
|
|
2138
|
+
result = TransactionInterceptor2.executeWithTransaction(prototype2, propertyKey, method, params, controllerContainer);
|
|
2139
|
+
} else {
|
|
2140
|
+
result = method.apply(controllerInstance, params);
|
|
2141
|
+
}
|
|
2142
|
+
} catch (error) {
|
|
2143
|
+
result = method.apply(controllerInstance, params);
|
|
2144
|
+
}
|
|
1694
2145
|
const responseData = await Promise.resolve(result);
|
|
1695
2146
|
if (responseData instanceof Response) {
|
|
1696
2147
|
return responseData;
|
|
@@ -2051,10 +2502,11 @@ class Application {
|
|
|
2051
2502
|
use(middleware) {
|
|
2052
2503
|
this.middlewarePipeline.use(middleware);
|
|
2053
2504
|
}
|
|
2054
|
-
listen(port, hostname) {
|
|
2505
|
+
async listen(port, hostname) {
|
|
2055
2506
|
if (this.server?.isRunning()) {
|
|
2056
2507
|
throw new Error("Application is already running");
|
|
2057
2508
|
}
|
|
2509
|
+
await this.initializeExtensions();
|
|
2058
2510
|
const serverOptions = {
|
|
2059
2511
|
port: port ?? this.options.port ?? 3000,
|
|
2060
2512
|
hostname: hostname ?? this.options.hostname,
|
|
@@ -2064,9 +2516,27 @@ class Application {
|
|
|
2064
2516
|
this.server = new BunServer(serverOptions);
|
|
2065
2517
|
this.server.start();
|
|
2066
2518
|
}
|
|
2067
|
-
|
|
2519
|
+
async initializeExtensions() {
|
|
2520
|
+
const container = this.getContainer();
|
|
2521
|
+
for (const extension of this.extensions) {
|
|
2522
|
+
if (extension && typeof extension === "object" && "initialize" in extension && typeof extension.initialize === "function") {
|
|
2523
|
+
await extension.initialize(container);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
async stop() {
|
|
2528
|
+
await this.closeExtensions();
|
|
2068
2529
|
this.server?.stop();
|
|
2069
2530
|
}
|
|
2531
|
+
async closeExtensions() {
|
|
2532
|
+
const container = this.getContainer();
|
|
2533
|
+
for (let i = this.extensions.length - 1;i >= 0; i--) {
|
|
2534
|
+
const extension = this.extensions[i];
|
|
2535
|
+
if (extension && typeof extension === "object" && "close" in extension && typeof extension.close === "function") {
|
|
2536
|
+
await extension.close(container);
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2070
2540
|
async handleRequest(context) {
|
|
2071
2541
|
if (["POST", "PUT", "PATCH"].includes(context.method)) {
|
|
2072
2542
|
await context.getBody();
|
|
@@ -3122,19 +3592,19 @@ class OAuth2Controller {
|
|
|
3122
3592
|
constructor(oauth2Service) {
|
|
3123
3593
|
this.oauth2Service = oauth2Service;
|
|
3124
3594
|
}
|
|
3125
|
-
authorize(clientId, redirectUri, state, scope) {
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
}
|
|
3595
|
+
authorize(clientId, redirectUri, responseType, state, scope) {
|
|
3596
|
+
if (!clientId || !redirectUri) {
|
|
3597
|
+
throw new Error("Missing required parameters: client_id and redirect_uri are required");
|
|
3598
|
+
}
|
|
3599
|
+
if (responseType !== "code") {
|
|
3600
|
+
throw new Error(`Unsupported response_type: ${responseType}. Only 'code' is supported.`);
|
|
3601
|
+
}
|
|
3132
3602
|
const request = {
|
|
3133
|
-
clientId
|
|
3134
|
-
redirectUri
|
|
3603
|
+
clientId,
|
|
3604
|
+
redirectUri,
|
|
3135
3605
|
responseType: "code",
|
|
3136
|
-
scope:
|
|
3137
|
-
state:
|
|
3606
|
+
scope: scope || undefined,
|
|
3607
|
+
state: state || undefined
|
|
3138
3608
|
};
|
|
3139
3609
|
const validation = this.oauth2Service.validateAuthorizationRequest(request);
|
|
3140
3610
|
if (!validation.valid) {
|
|
@@ -3195,13 +3665,15 @@ __legacyDecorateClassTS([
|
|
|
3195
3665
|
GET("/authorize"),
|
|
3196
3666
|
__legacyDecorateParamTS(0, Query("client_id")),
|
|
3197
3667
|
__legacyDecorateParamTS(1, Query("redirect_uri")),
|
|
3198
|
-
__legacyDecorateParamTS(2, Query("
|
|
3199
|
-
__legacyDecorateParamTS(3, Query("
|
|
3668
|
+
__legacyDecorateParamTS(2, Query("response_type")),
|
|
3669
|
+
__legacyDecorateParamTS(3, Query("state")),
|
|
3670
|
+
__legacyDecorateParamTS(4, Query("scope")),
|
|
3200
3671
|
__legacyMetadataTS("design:type", Function),
|
|
3201
3672
|
__legacyMetadataTS("design:paramtypes", [
|
|
3202
3673
|
String,
|
|
3203
3674
|
String,
|
|
3204
3675
|
String,
|
|
3676
|
+
String,
|
|
3205
3677
|
String
|
|
3206
3678
|
]),
|
|
3207
3679
|
__legacyMetadataTS("design:returntype", undefined)
|
|
@@ -3489,6 +3961,1166 @@ HealthModule = __legacyDecorateClassTS([
|
|
|
3489
3961
|
providers: []
|
|
3490
3962
|
})
|
|
3491
3963
|
], HealthModule);
|
|
3964
|
+
// src/metrics/collector.ts
|
|
3965
|
+
class MetricsCollector {
|
|
3966
|
+
counters = new Map;
|
|
3967
|
+
gauges = new Map;
|
|
3968
|
+
histograms = new Map;
|
|
3969
|
+
customMetrics = [];
|
|
3970
|
+
registerCustomMetric(metric) {
|
|
3971
|
+
this.customMetrics.push(metric);
|
|
3972
|
+
}
|
|
3973
|
+
incrementCounter(name, labels, value = 1) {
|
|
3974
|
+
const key = this.getKey(name, labels);
|
|
3975
|
+
const counterMap = this.counters.get(name) || new Map;
|
|
3976
|
+
const current = counterMap.get(key) || 0;
|
|
3977
|
+
counterMap.set(key, current + value);
|
|
3978
|
+
this.counters.set(name, counterMap);
|
|
3979
|
+
}
|
|
3980
|
+
setGauge(name, labels, value) {
|
|
3981
|
+
const key = this.getKey(name, labels);
|
|
3982
|
+
const gaugeMap = this.gauges.get(name) || new Map;
|
|
3983
|
+
gaugeMap.set(key, value);
|
|
3984
|
+
this.gauges.set(name, gaugeMap);
|
|
3985
|
+
}
|
|
3986
|
+
observeHistogram(name, labels, value) {
|
|
3987
|
+
const key = this.getKey(name, labels);
|
|
3988
|
+
const histogramMap = this.histograms.get(name) || new Map;
|
|
3989
|
+
const values = histogramMap.get(key) || [];
|
|
3990
|
+
values.push(value);
|
|
3991
|
+
histogramMap.set(key, values);
|
|
3992
|
+
this.histograms.set(name, histogramMap);
|
|
3993
|
+
}
|
|
3994
|
+
async getAllDataPoints() {
|
|
3995
|
+
const dataPoints = [];
|
|
3996
|
+
for (const [name, counterMap] of this.counters.entries()) {
|
|
3997
|
+
for (const [key, value] of counterMap.entries()) {
|
|
3998
|
+
const labels = this.parseKey(key);
|
|
3999
|
+
dataPoints.push({
|
|
4000
|
+
name,
|
|
4001
|
+
type: "counter",
|
|
4002
|
+
value,
|
|
4003
|
+
labels: labels && Object.keys(labels).length > 0 ? labels : undefined
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
for (const [name, gaugeMap] of this.gauges.entries()) {
|
|
4008
|
+
for (const [key, value] of gaugeMap.entries()) {
|
|
4009
|
+
const labels = this.parseKey(key);
|
|
4010
|
+
dataPoints.push({
|
|
4011
|
+
name,
|
|
4012
|
+
type: "gauge",
|
|
4013
|
+
value,
|
|
4014
|
+
labels: labels && Object.keys(labels).length > 0 ? labels : undefined
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
for (const [name, histogramMap] of this.histograms.entries()) {
|
|
4019
|
+
for (const [key, values] of histogramMap.entries()) {
|
|
4020
|
+
const labels = this.parseKey(key);
|
|
4021
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
4022
|
+
const count = values.length;
|
|
4023
|
+
const buckets = this.calculateBuckets(values);
|
|
4024
|
+
dataPoints.push({
|
|
4025
|
+
name: `${name}_sum`,
|
|
4026
|
+
type: "histogram",
|
|
4027
|
+
value: sum,
|
|
4028
|
+
labels: labels && Object.keys(labels).length > 0 ? labels : undefined
|
|
4029
|
+
});
|
|
4030
|
+
dataPoints.push({
|
|
4031
|
+
name: `${name}_count`,
|
|
4032
|
+
type: "histogram",
|
|
4033
|
+
value: count,
|
|
4034
|
+
labels: labels && Object.keys(labels).length > 0 ? labels : undefined
|
|
4035
|
+
});
|
|
4036
|
+
for (const [bucket, bucketCount] of Object.entries(buckets)) {
|
|
4037
|
+
dataPoints.push({
|
|
4038
|
+
name: `${name}_bucket`,
|
|
4039
|
+
type: "histogram",
|
|
4040
|
+
value: bucketCount,
|
|
4041
|
+
labels: {
|
|
4042
|
+
...labels,
|
|
4043
|
+
le: bucket
|
|
4044
|
+
}
|
|
4045
|
+
});
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
for (const metric of this.customMetrics) {
|
|
4050
|
+
try {
|
|
4051
|
+
const value = await metric.getValue();
|
|
4052
|
+
dataPoints.push({
|
|
4053
|
+
name: metric.name,
|
|
4054
|
+
type: metric.type,
|
|
4055
|
+
value,
|
|
4056
|
+
help: metric.help
|
|
4057
|
+
});
|
|
4058
|
+
} catch (error) {
|
|
4059
|
+
console.error(`Failed to collect custom metric ${metric.name}:`, error);
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
return dataPoints;
|
|
4063
|
+
}
|
|
4064
|
+
reset() {
|
|
4065
|
+
this.counters.clear();
|
|
4066
|
+
this.gauges.clear();
|
|
4067
|
+
this.histograms.clear();
|
|
4068
|
+
}
|
|
4069
|
+
getKey(name, labels) {
|
|
4070
|
+
if (!labels || Object.keys(labels).length === 0) {
|
|
4071
|
+
return "";
|
|
4072
|
+
}
|
|
4073
|
+
const sortedLabels = Object.keys(labels).sort().map((key) => `${key}="${labels[key]}"`).join(",");
|
|
4074
|
+
return `{${sortedLabels}}`;
|
|
4075
|
+
}
|
|
4076
|
+
parseKey(key) {
|
|
4077
|
+
if (!key || key === "") {
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
const labels = {};
|
|
4081
|
+
const match = key.match(/\{([^}]+)\}/);
|
|
4082
|
+
if (match) {
|
|
4083
|
+
const labelPairs = match[1].split(",");
|
|
4084
|
+
for (const pair of labelPairs) {
|
|
4085
|
+
const [k, v] = pair.split("=");
|
|
4086
|
+
if (k && v) {
|
|
4087
|
+
labels[k.trim()] = v.trim().replace(/^"|"$/g, "");
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
return Object.keys(labels).length > 0 ? labels : undefined;
|
|
4092
|
+
}
|
|
4093
|
+
calculateBuckets(values) {
|
|
4094
|
+
const defaultBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
|
|
4095
|
+
const buckets = {};
|
|
4096
|
+
for (const bucket of defaultBuckets) {
|
|
4097
|
+
buckets[bucket.toString()] = values.filter((v) => v <= bucket).length;
|
|
4098
|
+
}
|
|
4099
|
+
buckets["+Inf"] = values.length;
|
|
4100
|
+
return buckets;
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
// src/metrics/prometheus.ts
|
|
4105
|
+
class PrometheusFormatter {
|
|
4106
|
+
format(dataPoints) {
|
|
4107
|
+
const lines = [];
|
|
4108
|
+
const metricGroups = this.groupByMetricName(dataPoints);
|
|
4109
|
+
for (const [metricName, points] of metricGroups.entries()) {
|
|
4110
|
+
const help = points[0]?.help;
|
|
4111
|
+
if (help) {
|
|
4112
|
+
lines.push(`# HELP ${metricName} ${help}`);
|
|
4113
|
+
}
|
|
4114
|
+
const type = points[0]?.type;
|
|
4115
|
+
if (type) {
|
|
4116
|
+
lines.push(`# TYPE ${metricName} ${type}`);
|
|
4117
|
+
}
|
|
4118
|
+
for (const point of points) {
|
|
4119
|
+
const labelString = this.formatLabels(point.labels);
|
|
4120
|
+
const line = labelString ? `${point.name}${labelString} ${point.value}` : `${point.name} ${point.value}`;
|
|
4121
|
+
lines.push(line);
|
|
4122
|
+
}
|
|
4123
|
+
lines.push("");
|
|
4124
|
+
}
|
|
4125
|
+
return lines.join(`
|
|
4126
|
+
`);
|
|
4127
|
+
}
|
|
4128
|
+
groupByMetricName(dataPoints) {
|
|
4129
|
+
const groups = new Map;
|
|
4130
|
+
for (const point of dataPoints) {
|
|
4131
|
+
const name = point.name;
|
|
4132
|
+
const existing = groups.get(name) || [];
|
|
4133
|
+
existing.push(point);
|
|
4134
|
+
groups.set(name, existing);
|
|
4135
|
+
}
|
|
4136
|
+
return groups;
|
|
4137
|
+
}
|
|
4138
|
+
formatLabels(labels) {
|
|
4139
|
+
if (!labels || Object.keys(labels).length === 0) {
|
|
4140
|
+
return "";
|
|
4141
|
+
}
|
|
4142
|
+
const labelPairs = Object.keys(labels).sort().map((key) => `${key}="${this.escapeLabelValue(labels[key])}"`).join(",");
|
|
4143
|
+
return `{${labelPairs}}`;
|
|
4144
|
+
}
|
|
4145
|
+
escapeLabelValue(value) {
|
|
4146
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
|
|
4150
|
+
// src/metrics/types.ts
|
|
4151
|
+
var METRICS_SERVICE_TOKEN = Symbol("@dangao/bun-server:metrics:service");
|
|
4152
|
+
var METRICS_OPTIONS_TOKEN = Symbol("@dangao/bun-server:metrics:options");
|
|
4153
|
+
|
|
4154
|
+
// src/metrics/controller.ts
|
|
4155
|
+
class MetricsController {
|
|
4156
|
+
collector;
|
|
4157
|
+
options;
|
|
4158
|
+
formatter;
|
|
4159
|
+
constructor(collector, options) {
|
|
4160
|
+
this.collector = collector;
|
|
4161
|
+
this.options = options;
|
|
4162
|
+
this.formatter = new PrometheusFormatter;
|
|
4163
|
+
}
|
|
4164
|
+
async metrics() {
|
|
4165
|
+
const dataPoints = await this.collector.getAllDataPoints();
|
|
4166
|
+
const prometheusText = this.formatter.format(dataPoints);
|
|
4167
|
+
return new Response(prometheusText, {
|
|
4168
|
+
headers: {
|
|
4169
|
+
"Content-Type": "text/plain; version=0.0.4; charset=utf-8"
|
|
4170
|
+
}
|
|
4171
|
+
});
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
__legacyDecorateClassTS([
|
|
4175
|
+
GET("/metrics"),
|
|
4176
|
+
__legacyMetadataTS("design:type", Function),
|
|
4177
|
+
__legacyMetadataTS("design:paramtypes", []),
|
|
4178
|
+
__legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
4179
|
+
], MetricsController.prototype, "metrics", null);
|
|
4180
|
+
MetricsController = __legacyDecorateClassTS([
|
|
4181
|
+
Controller("/"),
|
|
4182
|
+
__legacyDecorateParamTS(0, Inject(METRICS_SERVICE_TOKEN)),
|
|
4183
|
+
__legacyDecorateParamTS(1, Inject(METRICS_OPTIONS_TOKEN)),
|
|
4184
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
4185
|
+
typeof MetricsCollector === "undefined" ? Object : MetricsCollector,
|
|
4186
|
+
typeof MetricsModuleOptions === "undefined" ? Object : MetricsModuleOptions
|
|
4187
|
+
])
|
|
4188
|
+
], MetricsController);
|
|
4189
|
+
|
|
4190
|
+
// src/metrics/metrics-module.ts
|
|
4191
|
+
class MetricsModule {
|
|
4192
|
+
static forRoot(options = {}) {
|
|
4193
|
+
const providers2 = [];
|
|
4194
|
+
const collector = new MetricsCollector;
|
|
4195
|
+
if (options.customMetrics) {
|
|
4196
|
+
for (const metric of options.customMetrics) {
|
|
4197
|
+
collector.registerCustomMetric(metric);
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
providers2.push({
|
|
4201
|
+
provide: METRICS_SERVICE_TOKEN,
|
|
4202
|
+
useValue: collector
|
|
4203
|
+
}, {
|
|
4204
|
+
provide: METRICS_OPTIONS_TOKEN,
|
|
4205
|
+
useValue: options
|
|
4206
|
+
}, MetricsCollector);
|
|
4207
|
+
const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, MetricsModule) || {};
|
|
4208
|
+
const metadata = {
|
|
4209
|
+
...existingMetadata,
|
|
4210
|
+
controllers: [...existingMetadata.controllers || [], MetricsController],
|
|
4211
|
+
providers: [...existingMetadata.providers || [], ...providers2],
|
|
4212
|
+
exports: [
|
|
4213
|
+
...existingMetadata.exports || [],
|
|
4214
|
+
METRICS_SERVICE_TOKEN,
|
|
4215
|
+
MetricsCollector
|
|
4216
|
+
]
|
|
4217
|
+
};
|
|
4218
|
+
Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, MetricsModule);
|
|
4219
|
+
return MetricsModule;
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
MetricsModule = __legacyDecorateClassTS([
|
|
4223
|
+
Module({
|
|
4224
|
+
controllers: [MetricsController],
|
|
4225
|
+
providers: []
|
|
4226
|
+
})
|
|
4227
|
+
], MetricsModule);
|
|
4228
|
+
// src/metrics/middleware.ts
|
|
4229
|
+
function createHttpMetricsMiddleware(collector) {
|
|
4230
|
+
return async (context2, next) => {
|
|
4231
|
+
const startTime = Date.now();
|
|
4232
|
+
const response = await next();
|
|
4233
|
+
const duration = Date.now() - startTime;
|
|
4234
|
+
const durationSeconds = duration / 1000;
|
|
4235
|
+
const method = context2.method;
|
|
4236
|
+
const path = context2.path;
|
|
4237
|
+
const statusCode = response.status;
|
|
4238
|
+
collector.incrementCounter("http_requests_total", {
|
|
4239
|
+
method,
|
|
4240
|
+
path,
|
|
4241
|
+
status: statusCode.toString()
|
|
4242
|
+
});
|
|
4243
|
+
collector.observeHistogram("http_request_duration_seconds", {
|
|
4244
|
+
method,
|
|
4245
|
+
path,
|
|
4246
|
+
status: statusCode.toString()
|
|
4247
|
+
}, durationSeconds);
|
|
4248
|
+
collector.observeHistogram("http_request_duration_seconds_summary", {
|
|
4249
|
+
method,
|
|
4250
|
+
path
|
|
4251
|
+
}, durationSeconds);
|
|
4252
|
+
return response;
|
|
4253
|
+
};
|
|
4254
|
+
}
|
|
4255
|
+
// src/database/types.ts
|
|
4256
|
+
var DATABASE_SERVICE_TOKEN = Symbol("@dangao/bun-server:database:service");
|
|
4257
|
+
var DATABASE_OPTIONS_TOKEN = Symbol("@dangao/bun-server:database:options");
|
|
4258
|
+
|
|
4259
|
+
// src/database/database-extension.ts
|
|
4260
|
+
class DatabaseExtension {
|
|
4261
|
+
register(container) {}
|
|
4262
|
+
async initialize(container) {
|
|
4263
|
+
try {
|
|
4264
|
+
const databaseService = container.resolve(DATABASE_SERVICE_TOKEN);
|
|
4265
|
+
await databaseService.initialize();
|
|
4266
|
+
} catch (error) {
|
|
4267
|
+
if (error instanceof Error && error.message.includes("Provider not found")) {
|
|
4268
|
+
return;
|
|
4269
|
+
}
|
|
4270
|
+
throw error;
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
async close(container) {
|
|
4274
|
+
try {
|
|
4275
|
+
const databaseService = container.resolve(DATABASE_SERVICE_TOKEN);
|
|
4276
|
+
await databaseService.closePool();
|
|
4277
|
+
} catch (error) {
|
|
4278
|
+
if (error instanceof Error && error.message.includes("Provider not found")) {
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
4281
|
+
throw error;
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
// src/database/health-indicator.ts
|
|
4287
|
+
class DatabaseHealthIndicator {
|
|
4288
|
+
databaseService;
|
|
4289
|
+
name = "database";
|
|
4290
|
+
constructor(databaseService) {
|
|
4291
|
+
this.databaseService = databaseService;
|
|
4292
|
+
}
|
|
4293
|
+
async check() {
|
|
4294
|
+
try {
|
|
4295
|
+
const isHealthy = await this.databaseService.healthCheck();
|
|
4296
|
+
const connectionInfo = this.databaseService.getConnectionInfo();
|
|
4297
|
+
if (isHealthy) {
|
|
4298
|
+
return {
|
|
4299
|
+
status: "up",
|
|
4300
|
+
details: {
|
|
4301
|
+
type: connectionInfo.type,
|
|
4302
|
+
status: connectionInfo.status
|
|
4303
|
+
}
|
|
4304
|
+
};
|
|
4305
|
+
}
|
|
4306
|
+
return {
|
|
4307
|
+
status: "down",
|
|
4308
|
+
details: {
|
|
4309
|
+
type: connectionInfo.type,
|
|
4310
|
+
status: connectionInfo.status,
|
|
4311
|
+
error: connectionInfo.error
|
|
4312
|
+
}
|
|
4313
|
+
};
|
|
4314
|
+
} catch (error) {
|
|
4315
|
+
return {
|
|
4316
|
+
status: "down",
|
|
4317
|
+
details: {
|
|
4318
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4319
|
+
}
|
|
4320
|
+
};
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
// src/database/orm/service.ts
|
|
4326
|
+
class OrmService {
|
|
4327
|
+
databaseService;
|
|
4328
|
+
options;
|
|
4329
|
+
drizzleInstance = null;
|
|
4330
|
+
constructor(databaseService, options = {}) {
|
|
4331
|
+
this.databaseService = databaseService;
|
|
4332
|
+
this.options = options;
|
|
4333
|
+
}
|
|
4334
|
+
getDrizzle() {
|
|
4335
|
+
if (this.options.drizzle) {
|
|
4336
|
+
return this.options.drizzle;
|
|
4337
|
+
}
|
|
4338
|
+
if (this.drizzleInstance) {
|
|
4339
|
+
return this.drizzleInstance;
|
|
4340
|
+
}
|
|
4341
|
+
return null;
|
|
4342
|
+
}
|
|
4343
|
+
setDrizzle(drizzle) {
|
|
4344
|
+
this.drizzleInstance = drizzle;
|
|
4345
|
+
}
|
|
4346
|
+
getDatabaseService() {
|
|
4347
|
+
return this.databaseService;
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
OrmService = __legacyDecorateClassTS([
|
|
4351
|
+
Injectable(),
|
|
4352
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
4353
|
+
typeof DatabaseService === "undefined" ? Object : DatabaseService,
|
|
4354
|
+
typeof OrmModuleOptions === "undefined" ? Object : OrmModuleOptions
|
|
4355
|
+
])
|
|
4356
|
+
], OrmService);
|
|
4357
|
+
|
|
4358
|
+
// src/database/orm/transaction-manager.ts
|
|
4359
|
+
init_transaction_types();
|
|
4360
|
+
class TransactionManager {
|
|
4361
|
+
databaseService;
|
|
4362
|
+
transactions = new Map;
|
|
4363
|
+
connectionTransactions = new Map;
|
|
4364
|
+
constructor(databaseService) {
|
|
4365
|
+
this.databaseService = databaseService;
|
|
4366
|
+
}
|
|
4367
|
+
async beginTransaction(options = {}) {
|
|
4368
|
+
const transactionId = this.generateTransactionId();
|
|
4369
|
+
const context2 = {
|
|
4370
|
+
id: transactionId,
|
|
4371
|
+
status: "ACTIVE" /* ACTIVE */,
|
|
4372
|
+
startTime: Date.now(),
|
|
4373
|
+
level: 0,
|
|
4374
|
+
savepoints: []
|
|
4375
|
+
};
|
|
4376
|
+
const connection = await this.databaseService.getConnection();
|
|
4377
|
+
this.connectionTransactions.set(connection, transactionId);
|
|
4378
|
+
this.transactions.set(transactionId, context2);
|
|
4379
|
+
await this.executeBegin(connection, options);
|
|
4380
|
+
return context2;
|
|
4381
|
+
}
|
|
4382
|
+
async commitTransaction(transactionId) {
|
|
4383
|
+
const context2 = this.transactions.get(transactionId);
|
|
4384
|
+
if (!context2) {
|
|
4385
|
+
throw new Error(`Transaction ${transactionId} not found`);
|
|
4386
|
+
}
|
|
4387
|
+
if (context2.status !== "ACTIVE" /* ACTIVE */) {
|
|
4388
|
+
throw new Error(`Transaction ${transactionId} is not active`);
|
|
4389
|
+
}
|
|
4390
|
+
const connection = this.findConnectionByTransactionId(transactionId);
|
|
4391
|
+
if (!connection) {
|
|
4392
|
+
throw new Error(`Connection not found for transaction ${transactionId}`);
|
|
4393
|
+
}
|
|
4394
|
+
await this.executeCommit(connection);
|
|
4395
|
+
context2.status = "COMMITTED" /* COMMITTED */;
|
|
4396
|
+
this.cleanupTransaction(transactionId);
|
|
4397
|
+
}
|
|
4398
|
+
async rollbackTransaction(transactionId) {
|
|
4399
|
+
const context2 = this.transactions.get(transactionId);
|
|
4400
|
+
if (!context2) {
|
|
4401
|
+
throw new Error(`Transaction ${transactionId} not found`);
|
|
4402
|
+
}
|
|
4403
|
+
const connection = this.findConnectionByTransactionId(transactionId);
|
|
4404
|
+
if (!connection) {
|
|
4405
|
+
throw new Error(`Connection not found for transaction ${transactionId}`);
|
|
4406
|
+
}
|
|
4407
|
+
await this.executeRollback(connection);
|
|
4408
|
+
context2.status = "ROLLED_BACK" /* ROLLED_BACK */;
|
|
4409
|
+
this.cleanupTransaction(transactionId);
|
|
4410
|
+
}
|
|
4411
|
+
async createSavepoint(transactionId) {
|
|
4412
|
+
const context2 = this.transactions.get(transactionId);
|
|
4413
|
+
if (!context2) {
|
|
4414
|
+
throw new Error(`Transaction ${transactionId} not found`);
|
|
4415
|
+
}
|
|
4416
|
+
const savepointName = `sp_${context2.level}_${Date.now()}`;
|
|
4417
|
+
context2.savepoints = context2.savepoints || [];
|
|
4418
|
+
context2.savepoints.push(savepointName);
|
|
4419
|
+
context2.level += 1;
|
|
4420
|
+
const connection = this.findConnectionByTransactionId(transactionId);
|
|
4421
|
+
if (connection) {
|
|
4422
|
+
await this.executeSavepoint(connection, savepointName);
|
|
4423
|
+
}
|
|
4424
|
+
return savepointName;
|
|
4425
|
+
}
|
|
4426
|
+
async rollbackToSavepoint(transactionId, savepointName) {
|
|
4427
|
+
const context2 = this.transactions.get(transactionId);
|
|
4428
|
+
if (!context2) {
|
|
4429
|
+
throw new Error(`Transaction ${transactionId} not found`);
|
|
4430
|
+
}
|
|
4431
|
+
const connection = this.findConnectionByTransactionId(transactionId);
|
|
4432
|
+
if (connection) {
|
|
4433
|
+
await this.executeRollbackToSavepoint(connection, savepointName);
|
|
4434
|
+
}
|
|
4435
|
+
const index = context2.savepoints?.indexOf(savepointName) ?? -1;
|
|
4436
|
+
if (index >= 0 && context2.savepoints) {
|
|
4437
|
+
context2.savepoints = context2.savepoints.slice(0, index);
|
|
4438
|
+
context2.level = index;
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
getCurrentTransaction() {
|
|
4442
|
+
for (const context2 of this.transactions.values()) {
|
|
4443
|
+
if (context2.status === "ACTIVE" /* ACTIVE */) {
|
|
4444
|
+
return context2;
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
return null;
|
|
4448
|
+
}
|
|
4449
|
+
hasActiveTransaction() {
|
|
4450
|
+
return this.getCurrentTransaction() !== null;
|
|
4451
|
+
}
|
|
4452
|
+
generateTransactionId() {
|
|
4453
|
+
return `tx_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
4454
|
+
}
|
|
4455
|
+
findConnectionByTransactionId(transactionId) {
|
|
4456
|
+
for (const [connection, txId] of this.connectionTransactions.entries()) {
|
|
4457
|
+
if (txId === transactionId) {
|
|
4458
|
+
return connection;
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
return null;
|
|
4462
|
+
}
|
|
4463
|
+
cleanupTransaction(transactionId) {
|
|
4464
|
+
this.transactions.delete(transactionId);
|
|
4465
|
+
for (const [connection, txId] of this.connectionTransactions.entries()) {
|
|
4466
|
+
if (txId === transactionId) {
|
|
4467
|
+
this.connectionTransactions.delete(connection);
|
|
4468
|
+
break;
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
async executeBegin(connection, options) {
|
|
4473
|
+
const dbType = this.databaseService["config"].database.type;
|
|
4474
|
+
if (dbType === "sqlite") {
|
|
4475
|
+
await this.databaseService.query("BEGIN TRANSACTION");
|
|
4476
|
+
} else if (dbType === "postgres" || dbType === "mysql") {
|
|
4477
|
+
let sql = "START TRANSACTION";
|
|
4478
|
+
if (options.isolationLevel) {
|
|
4479
|
+
const isolation = this.getIsolationLevelSQL(options.isolationLevel);
|
|
4480
|
+
sql += ` ${isolation}`;
|
|
4481
|
+
}
|
|
4482
|
+
if (options.readOnly) {
|
|
4483
|
+
sql += " READ ONLY";
|
|
4484
|
+
}
|
|
4485
|
+
await this.databaseService.query(sql);
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
async executeCommit(connection) {
|
|
4489
|
+
await this.databaseService.query("COMMIT");
|
|
4490
|
+
}
|
|
4491
|
+
async executeRollback(connection) {
|
|
4492
|
+
await this.databaseService.query("ROLLBACK");
|
|
4493
|
+
}
|
|
4494
|
+
async executeSavepoint(connection, savepointName) {
|
|
4495
|
+
await this.databaseService.query(`SAVEPOINT ${savepointName}`);
|
|
4496
|
+
}
|
|
4497
|
+
async executeRollbackToSavepoint(connection, savepointName) {
|
|
4498
|
+
await this.databaseService.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);
|
|
4499
|
+
}
|
|
4500
|
+
getIsolationLevelSQL(level) {
|
|
4501
|
+
const dbType = this.databaseService["config"].database.type;
|
|
4502
|
+
const levelMap = {
|
|
4503
|
+
["READ_UNCOMMITTED" /* READ_UNCOMMITTED */]: "READ UNCOMMITTED",
|
|
4504
|
+
["READ_COMMITTED" /* READ_COMMITTED */]: "READ COMMITTED",
|
|
4505
|
+
["REPEATABLE_READ" /* REPEATABLE_READ */]: "REPEATABLE READ",
|
|
4506
|
+
["SERIALIZABLE" /* SERIALIZABLE */]: "SERIALIZABLE"
|
|
4507
|
+
};
|
|
4508
|
+
if (dbType === "postgres") {
|
|
4509
|
+
return `SET TRANSACTION ISOLATION LEVEL ${levelMap[level]}`;
|
|
4510
|
+
} else if (dbType === "mysql") {
|
|
4511
|
+
return `SET TRANSACTION ISOLATION LEVEL ${levelMap[level]}`;
|
|
4512
|
+
}
|
|
4513
|
+
return "";
|
|
4514
|
+
}
|
|
4515
|
+
}
|
|
4516
|
+
TransactionManager = __legacyDecorateClassTS([
|
|
4517
|
+
Injectable(),
|
|
4518
|
+
__legacyDecorateParamTS(0, Inject(DATABASE_SERVICE_TOKEN)),
|
|
4519
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
4520
|
+
typeof DatabaseService === "undefined" ? Object : DatabaseService
|
|
4521
|
+
])
|
|
4522
|
+
], TransactionManager);
|
|
4523
|
+
|
|
4524
|
+
// src/database/connection-pool.ts
|
|
4525
|
+
class ConnectionPool {
|
|
4526
|
+
config;
|
|
4527
|
+
options;
|
|
4528
|
+
connections = [];
|
|
4529
|
+
pendingConnections = new Set;
|
|
4530
|
+
isClosing = false;
|
|
4531
|
+
constructor(config, options = {}) {
|
|
4532
|
+
this.config = config;
|
|
4533
|
+
this.options = {
|
|
4534
|
+
maxConnections: options.maxConnections ?? 10,
|
|
4535
|
+
connectionTimeout: options.connectionTimeout ?? 30000,
|
|
4536
|
+
retryCount: options.retryCount ?? 3,
|
|
4537
|
+
retryDelay: options.retryDelay ?? 1000
|
|
4538
|
+
};
|
|
4539
|
+
}
|
|
4540
|
+
async acquire() {
|
|
4541
|
+
if (this.isClosing) {
|
|
4542
|
+
throw new Error("Connection pool is closing");
|
|
4543
|
+
}
|
|
4544
|
+
const idleConnection = this.connections.find((conn) => !conn.inUse);
|
|
4545
|
+
if (idleConnection) {
|
|
4546
|
+
idleConnection.inUse = true;
|
|
4547
|
+
idleConnection.lastUsedAt = Date.now();
|
|
4548
|
+
return idleConnection.connection;
|
|
4549
|
+
}
|
|
4550
|
+
if (this.connections.length < this.options.maxConnections) {
|
|
4551
|
+
const connection = await this.createConnection();
|
|
4552
|
+
const poolConnection = {
|
|
4553
|
+
connection,
|
|
4554
|
+
inUse: true,
|
|
4555
|
+
createdAt: Date.now(),
|
|
4556
|
+
lastUsedAt: Date.now()
|
|
4557
|
+
};
|
|
4558
|
+
this.connections.push(poolConnection);
|
|
4559
|
+
return connection;
|
|
4560
|
+
}
|
|
4561
|
+
return await this.waitForConnection();
|
|
4562
|
+
}
|
|
4563
|
+
release(connection) {
|
|
4564
|
+
const poolConnection = this.connections.find((conn) => conn.connection === connection);
|
|
4565
|
+
if (poolConnection) {
|
|
4566
|
+
poolConnection.inUse = false;
|
|
4567
|
+
poolConnection.lastUsedAt = Date.now();
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
async close() {
|
|
4571
|
+
this.isClosing = true;
|
|
4572
|
+
await Promise.all(Array.from(this.pendingConnections));
|
|
4573
|
+
const closePromises = this.connections.map((poolConnection) => this.closeConnection(poolConnection.connection));
|
|
4574
|
+
await Promise.all(closePromises);
|
|
4575
|
+
this.connections = [];
|
|
4576
|
+
this.isClosing = false;
|
|
4577
|
+
}
|
|
4578
|
+
getPoolStats() {
|
|
4579
|
+
const inUse = this.connections.filter((conn) => conn.inUse).length;
|
|
4580
|
+
return {
|
|
4581
|
+
total: this.connections.length,
|
|
4582
|
+
inUse,
|
|
4583
|
+
idle: this.connections.length - inUse,
|
|
4584
|
+
maxConnections: this.options.maxConnections
|
|
4585
|
+
};
|
|
4586
|
+
}
|
|
4587
|
+
async createConnection() {
|
|
4588
|
+
const createPromise = this.createConnectionWithRetry();
|
|
4589
|
+
this.pendingConnections.add(createPromise);
|
|
4590
|
+
try {
|
|
4591
|
+
const connection = await createPromise;
|
|
4592
|
+
return connection;
|
|
4593
|
+
} finally {
|
|
4594
|
+
this.pendingConnections.delete(createPromise);
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
async createConnectionWithRetry() {
|
|
4598
|
+
let lastError;
|
|
4599
|
+
for (let i = 0;i <= this.options.retryCount; i++) {
|
|
4600
|
+
try {
|
|
4601
|
+
if (this.config.type === "sqlite") {
|
|
4602
|
+
return await this.createSqliteConnection(this.config.config);
|
|
4603
|
+
} else if (this.config.type === "postgres") {
|
|
4604
|
+
return await this.createPostgresConnection(this.config.config);
|
|
4605
|
+
} else if (this.config.type === "mysql") {
|
|
4606
|
+
return await this.createMysqlConnection(this.config.config);
|
|
4607
|
+
}
|
|
4608
|
+
} catch (error) {
|
|
4609
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
4610
|
+
if (i < this.options.retryCount) {
|
|
4611
|
+
await this.sleep(this.options.retryDelay);
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
throw lastError ?? new Error("Failed to create database connection");
|
|
4616
|
+
}
|
|
4617
|
+
async createSqliteConnection(config) {
|
|
4618
|
+
const { Database } = await import("bun:sqlite");
|
|
4619
|
+
const db = new Database(config.path);
|
|
4620
|
+
return db;
|
|
4621
|
+
}
|
|
4622
|
+
async createPostgresConnection(config) {
|
|
4623
|
+
const url = `postgres://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`;
|
|
4624
|
+
const { SQL } = await Promise.resolve(globalThis.Bun);
|
|
4625
|
+
return new SQL(url, {
|
|
4626
|
+
max: 1,
|
|
4627
|
+
tls: config.ssl ?? false
|
|
4628
|
+
});
|
|
4629
|
+
}
|
|
4630
|
+
async createMysqlConnection(config) {
|
|
4631
|
+
const url = `mysql://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`;
|
|
4632
|
+
const { SQL } = await Promise.resolve(globalThis.Bun);
|
|
4633
|
+
return new SQL(url, {
|
|
4634
|
+
max: 1
|
|
4635
|
+
});
|
|
4636
|
+
}
|
|
4637
|
+
async closeConnection(connection) {
|
|
4638
|
+
const dbType = this.config.type;
|
|
4639
|
+
if (dbType === "sqlite") {
|
|
4640
|
+
await this.closeSqliteConnection(connection);
|
|
4641
|
+
} else if (dbType === "postgres") {
|
|
4642
|
+
await this.closePostgresConnection(connection);
|
|
4643
|
+
} else if (dbType === "mysql") {
|
|
4644
|
+
await this.closeMysqlConnection(connection);
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
async closeSqliteConnection(connection) {
|
|
4648
|
+
if (connection && typeof connection === "object" && "close" in connection && typeof connection.close === "function") {
|
|
4649
|
+
connection.close();
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
async closePostgresConnection(_connection) {
|
|
4653
|
+
if (_connection && typeof _connection === "object" && "close" in _connection && typeof _connection.close === "function") {
|
|
4654
|
+
_connection.close();
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
async closeMysqlConnection(_connection) {
|
|
4658
|
+
if (_connection && typeof _connection === "object" && "close" in _connection && typeof _connection.close === "function") {
|
|
4659
|
+
_connection.close();
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
async waitForConnection() {
|
|
4663
|
+
const startTime = Date.now();
|
|
4664
|
+
const timeout = this.options.connectionTimeout;
|
|
4665
|
+
while (Date.now() - startTime < timeout) {
|
|
4666
|
+
const idleConnection = this.connections.find((conn) => !conn.inUse);
|
|
4667
|
+
if (idleConnection) {
|
|
4668
|
+
idleConnection.inUse = true;
|
|
4669
|
+
idleConnection.lastUsedAt = Date.now();
|
|
4670
|
+
return idleConnection.connection;
|
|
4671
|
+
}
|
|
4672
|
+
await this.sleep(100);
|
|
4673
|
+
}
|
|
4674
|
+
throw new Error(`Connection timeout: No available connection within ${timeout}ms`);
|
|
4675
|
+
}
|
|
4676
|
+
sleep(ms) {
|
|
4677
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
|
|
4681
|
+
// src/database/connection-manager.ts
|
|
4682
|
+
class DatabaseConnectionManager {
|
|
4683
|
+
config;
|
|
4684
|
+
poolOptions;
|
|
4685
|
+
pool;
|
|
4686
|
+
currentConnection = null;
|
|
4687
|
+
status = "disconnected";
|
|
4688
|
+
error;
|
|
4689
|
+
constructor(config, poolOptions = {}) {
|
|
4690
|
+
this.config = config;
|
|
4691
|
+
this.poolOptions = {
|
|
4692
|
+
maxConnections: poolOptions.maxConnections ?? 10,
|
|
4693
|
+
connectionTimeout: poolOptions.connectionTimeout ?? 30000,
|
|
4694
|
+
retryCount: poolOptions.retryCount ?? 3,
|
|
4695
|
+
retryDelay: poolOptions.retryDelay ?? 1000
|
|
4696
|
+
};
|
|
4697
|
+
this.pool = new ConnectionPool(config, this.poolOptions);
|
|
4698
|
+
}
|
|
4699
|
+
async connect() {
|
|
4700
|
+
if (this.status === "connected") {
|
|
4701
|
+
return;
|
|
4702
|
+
}
|
|
4703
|
+
this.status = "connecting";
|
|
4704
|
+
try {
|
|
4705
|
+
this.currentConnection = await this.pool.acquire();
|
|
4706
|
+
this.status = "connected";
|
|
4707
|
+
this.error = undefined;
|
|
4708
|
+
} catch (error) {
|
|
4709
|
+
this.status = "error";
|
|
4710
|
+
this.error = error instanceof Error ? error.message : String(error);
|
|
4711
|
+
throw error;
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
async disconnect() {
|
|
4715
|
+
if (this.status === "disconnected" || !this.currentConnection) {
|
|
4716
|
+
return;
|
|
4717
|
+
}
|
|
4718
|
+
try {
|
|
4719
|
+
this.pool.release(this.currentConnection);
|
|
4720
|
+
this.currentConnection = null;
|
|
4721
|
+
this.status = "disconnected";
|
|
4722
|
+
this.error = undefined;
|
|
4723
|
+
} catch (error) {
|
|
4724
|
+
this.status = "error";
|
|
4725
|
+
this.error = error instanceof Error ? error.message : String(error);
|
|
4726
|
+
throw error;
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
async closePool() {
|
|
4730
|
+
await this.pool.close();
|
|
4731
|
+
this.currentConnection = null;
|
|
4732
|
+
this.status = "disconnected";
|
|
4733
|
+
this.error = undefined;
|
|
4734
|
+
}
|
|
4735
|
+
async healthCheck() {
|
|
4736
|
+
if (this.status !== "connected" || !this.currentConnection) {
|
|
4737
|
+
return false;
|
|
4738
|
+
}
|
|
4739
|
+
try {
|
|
4740
|
+
if (this.config.type === "sqlite") {
|
|
4741
|
+
return await this.healthCheckSqlite(this.currentConnection);
|
|
4742
|
+
} else if (this.config.type === "postgres") {
|
|
4743
|
+
return await this.healthCheckPostgres(this.currentConnection);
|
|
4744
|
+
} else if (this.config.type === "mysql") {
|
|
4745
|
+
return await this.healthCheckMysql(this.currentConnection);
|
|
4746
|
+
}
|
|
4747
|
+
return false;
|
|
4748
|
+
} catch {
|
|
4749
|
+
return false;
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
getPoolStats() {
|
|
4753
|
+
return this.pool.getPoolStats();
|
|
4754
|
+
}
|
|
4755
|
+
getConnectionInfo() {
|
|
4756
|
+
return {
|
|
4757
|
+
status: this.status,
|
|
4758
|
+
type: this.config.type,
|
|
4759
|
+
error: this.error
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4762
|
+
getConnection() {
|
|
4763
|
+
return this.currentConnection;
|
|
4764
|
+
}
|
|
4765
|
+
async acquireConnection() {
|
|
4766
|
+
return await this.pool.acquire();
|
|
4767
|
+
}
|
|
4768
|
+
releaseConnection(connection) {
|
|
4769
|
+
this.pool.release(connection);
|
|
4770
|
+
}
|
|
4771
|
+
getDatabaseType() {
|
|
4772
|
+
return this.config.type;
|
|
4773
|
+
}
|
|
4774
|
+
async healthCheckSqlite(connection) {
|
|
4775
|
+
try {
|
|
4776
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
4777
|
+
const db = connection;
|
|
4778
|
+
db.query("SELECT 1").all();
|
|
4779
|
+
return true;
|
|
4780
|
+
}
|
|
4781
|
+
return false;
|
|
4782
|
+
} catch {
|
|
4783
|
+
return false;
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
async healthCheckPostgres(connection) {
|
|
4787
|
+
try {
|
|
4788
|
+
if (connection && typeof connection === "function") {
|
|
4789
|
+
const result = await connection`SELECT 1`;
|
|
4790
|
+
return Array.isArray(result) && result.length > 0;
|
|
4791
|
+
}
|
|
4792
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
4793
|
+
await connection.query("SELECT 1");
|
|
4794
|
+
return true;
|
|
4795
|
+
}
|
|
4796
|
+
return false;
|
|
4797
|
+
} catch {
|
|
4798
|
+
return false;
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
async healthCheckMysql(connection) {
|
|
4802
|
+
try {
|
|
4803
|
+
if (connection && typeof connection === "function") {
|
|
4804
|
+
const result = await connection`SELECT 1`;
|
|
4805
|
+
return Array.isArray(result) && result.length > 0;
|
|
4806
|
+
}
|
|
4807
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
4808
|
+
await connection.query("SELECT 1");
|
|
4809
|
+
return true;
|
|
4810
|
+
}
|
|
4811
|
+
return false;
|
|
4812
|
+
} catch {
|
|
4813
|
+
return false;
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
// src/database/service.ts
|
|
4819
|
+
class DatabaseService2 {
|
|
4820
|
+
connectionManager;
|
|
4821
|
+
options;
|
|
4822
|
+
constructor(options) {
|
|
4823
|
+
this.options = options;
|
|
4824
|
+
this.connectionManager = new DatabaseConnectionManager(options.database, options.pool);
|
|
4825
|
+
}
|
|
4826
|
+
async initialize() {
|
|
4827
|
+
await this.connectionManager.connect();
|
|
4828
|
+
}
|
|
4829
|
+
async close() {
|
|
4830
|
+
await this.connectionManager.disconnect();
|
|
4831
|
+
}
|
|
4832
|
+
async closePool() {
|
|
4833
|
+
await this.connectionManager.closePool();
|
|
4834
|
+
}
|
|
4835
|
+
getPoolStats() {
|
|
4836
|
+
return this.connectionManager.getPoolStats();
|
|
4837
|
+
}
|
|
4838
|
+
getConnection() {
|
|
4839
|
+
return this.connectionManager.getConnection();
|
|
4840
|
+
}
|
|
4841
|
+
get config() {
|
|
4842
|
+
return this.options;
|
|
4843
|
+
}
|
|
4844
|
+
getDatabaseType() {
|
|
4845
|
+
return this.connectionManager.getDatabaseType();
|
|
4846
|
+
}
|
|
4847
|
+
async healthCheck() {
|
|
4848
|
+
if (!this.options.enableHealthCheck) {
|
|
4849
|
+
return true;
|
|
4850
|
+
}
|
|
4851
|
+
return await this.connectionManager.healthCheck();
|
|
4852
|
+
}
|
|
4853
|
+
getConnectionInfo() {
|
|
4854
|
+
return this.connectionManager.getConnectionInfo();
|
|
4855
|
+
}
|
|
4856
|
+
query(sql, params) {
|
|
4857
|
+
const connection = this.getConnection();
|
|
4858
|
+
if (!connection) {
|
|
4859
|
+
throw new Error("Database connection is not established");
|
|
4860
|
+
}
|
|
4861
|
+
const dbType = this.getDatabaseType();
|
|
4862
|
+
if (dbType === "sqlite") {
|
|
4863
|
+
return this.querySqlite(connection, sql, params);
|
|
4864
|
+
} else if (dbType === "postgres" || dbType === "mysql") {
|
|
4865
|
+
return this.queryBunSQL(connection, sql, params);
|
|
4866
|
+
}
|
|
4867
|
+
throw new Error(`Query not supported for database type: ${dbType}`);
|
|
4868
|
+
}
|
|
4869
|
+
querySqlite(connection, sql, params) {
|
|
4870
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
4871
|
+
const db = connection;
|
|
4872
|
+
const statement = db.query(sql);
|
|
4873
|
+
const result = params && params.length > 0 ? statement.all(...params) : statement.all();
|
|
4874
|
+
return result;
|
|
4875
|
+
}
|
|
4876
|
+
throw new Error("Invalid SQLite connection");
|
|
4877
|
+
}
|
|
4878
|
+
async queryBunSQL(connection, sql, params) {
|
|
4879
|
+
if (connection && typeof connection === "function") {
|
|
4880
|
+
try {
|
|
4881
|
+
const sqlWithParams = this.interpolateParams(sql, params);
|
|
4882
|
+
const result = await connection`${sqlWithParams}`;
|
|
4883
|
+
return result;
|
|
4884
|
+
} catch {
|
|
4885
|
+
throw new Error("Bun.SQL parameterized queries are not fully supported. Consider using template string queries.");
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
4889
|
+
const db = connection;
|
|
4890
|
+
const result = await db.query(sql, ...params ?? []);
|
|
4891
|
+
return result;
|
|
4892
|
+
}
|
|
4893
|
+
throw new Error("Invalid Bun.SQL connection");
|
|
4894
|
+
}
|
|
4895
|
+
interpolateParams(sql, params) {
|
|
4896
|
+
if (!params || params.length === 0) {
|
|
4897
|
+
return sql;
|
|
4898
|
+
}
|
|
4899
|
+
let result = sql;
|
|
4900
|
+
for (let i = 0;i < params.length; i++) {
|
|
4901
|
+
const param = params[i];
|
|
4902
|
+
const value = typeof param === "string" ? `'${param.replace(/'/g, "''")}'` : String(param);
|
|
4903
|
+
result = result.replace("?", value);
|
|
4904
|
+
}
|
|
4905
|
+
return result;
|
|
4906
|
+
}
|
|
4907
|
+
}
|
|
4908
|
+
DatabaseService2 = __legacyDecorateClassTS([
|
|
4909
|
+
Injectable(),
|
|
4910
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
4911
|
+
typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions
|
|
4912
|
+
])
|
|
4913
|
+
], DatabaseService2);
|
|
4914
|
+
|
|
4915
|
+
// src/database/orm/types.ts
|
|
4916
|
+
var ORM_SERVICE_TOKEN = Symbol("@dangao/bun-server:orm:service");
|
|
4917
|
+
|
|
4918
|
+
// src/database/database-module.ts
|
|
4919
|
+
init_transaction_types();
|
|
4920
|
+
class DatabaseModule {
|
|
4921
|
+
static forRoot(options) {
|
|
4922
|
+
const providers2 = [];
|
|
4923
|
+
const service = new DatabaseService2(options);
|
|
4924
|
+
providers2.push({
|
|
4925
|
+
provide: DATABASE_SERVICE_TOKEN,
|
|
4926
|
+
useValue: service
|
|
4927
|
+
}, {
|
|
4928
|
+
provide: DATABASE_OPTIONS_TOKEN,
|
|
4929
|
+
useValue: options
|
|
4930
|
+
}, DatabaseService2);
|
|
4931
|
+
if (options.orm?.enabled) {
|
|
4932
|
+
const ormService = new OrmService(service, {
|
|
4933
|
+
enabled: true,
|
|
4934
|
+
drizzle: options.orm.drizzle,
|
|
4935
|
+
databaseService: service
|
|
4936
|
+
});
|
|
4937
|
+
providers2.push({
|
|
4938
|
+
provide: ORM_SERVICE_TOKEN,
|
|
4939
|
+
useValue: ormService
|
|
4940
|
+
}, OrmService);
|
|
4941
|
+
}
|
|
4942
|
+
const transactionManager = new TransactionManager(service);
|
|
4943
|
+
providers2.push({
|
|
4944
|
+
provide: TRANSACTION_SERVICE_TOKEN,
|
|
4945
|
+
useValue: transactionManager
|
|
4946
|
+
}, TransactionManager);
|
|
4947
|
+
const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, DatabaseModule) || {};
|
|
4948
|
+
const databaseExtension = new DatabaseExtension;
|
|
4949
|
+
const metadata = {
|
|
4950
|
+
...existingMetadata,
|
|
4951
|
+
providers: [...existingMetadata.providers || [], ...providers2],
|
|
4952
|
+
exports: [
|
|
4953
|
+
...existingMetadata.exports || [],
|
|
4954
|
+
DATABASE_SERVICE_TOKEN,
|
|
4955
|
+
DATABASE_OPTIONS_TOKEN,
|
|
4956
|
+
DatabaseService2,
|
|
4957
|
+
TRANSACTION_SERVICE_TOKEN,
|
|
4958
|
+
TransactionManager,
|
|
4959
|
+
...options.orm?.enabled ? [ORM_SERVICE_TOKEN, OrmService] : []
|
|
4960
|
+
],
|
|
4961
|
+
extensions: [
|
|
4962
|
+
...existingMetadata.extensions || [],
|
|
4963
|
+
databaseExtension
|
|
4964
|
+
]
|
|
4965
|
+
};
|
|
4966
|
+
Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, DatabaseModule);
|
|
4967
|
+
return DatabaseModule;
|
|
4968
|
+
}
|
|
4969
|
+
static createHealthIndicator(databaseService) {
|
|
4970
|
+
return new DatabaseHealthIndicator(databaseService);
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
DatabaseModule = __legacyDecorateClassTS([
|
|
4974
|
+
Module({
|
|
4975
|
+
providers: []
|
|
4976
|
+
})
|
|
4977
|
+
], DatabaseModule);
|
|
4978
|
+
// src/database/orm/decorators.ts
|
|
4979
|
+
import"reflect-metadata";
|
|
4980
|
+
var ENTITY_METADATA_KEY = Symbol("@dangao/bun-server:orm:entity");
|
|
4981
|
+
var COLUMN_METADATA_KEY = Symbol("@dangao/bun-server:orm:column");
|
|
4982
|
+
function Entity(tableName) {
|
|
4983
|
+
return (target) => {
|
|
4984
|
+
Reflect.defineMetadata(ENTITY_METADATA_KEY, { tableName }, target);
|
|
4985
|
+
};
|
|
4986
|
+
}
|
|
4987
|
+
function Column(options) {
|
|
4988
|
+
return (target, propertyKey) => {
|
|
4989
|
+
const existingColumns = Reflect.getMetadata(COLUMN_METADATA_KEY, target.constructor) || [];
|
|
4990
|
+
const existingIndex = existingColumns.findIndex((col) => col.propertyKey === String(propertyKey));
|
|
4991
|
+
const columnDef = {
|
|
4992
|
+
name: options?.name ?? String(propertyKey),
|
|
4993
|
+
type: options?.type ?? "TEXT",
|
|
4994
|
+
primaryKey: options?.primaryKey ?? false,
|
|
4995
|
+
autoIncrement: options?.autoIncrement ?? false,
|
|
4996
|
+
nullable: options?.nullable !== undefined ? options.nullable : true,
|
|
4997
|
+
defaultValue: options?.defaultValue,
|
|
4998
|
+
propertyKey: String(propertyKey)
|
|
4999
|
+
};
|
|
5000
|
+
if (existingIndex >= 0) {
|
|
5001
|
+
const existing = existingColumns[existingIndex];
|
|
5002
|
+
existingColumns[existingIndex] = {
|
|
5003
|
+
...existing,
|
|
5004
|
+
name: options?.name ?? existing.name,
|
|
5005
|
+
type: options?.type ?? existing.type,
|
|
5006
|
+
primaryKey: options?.primaryKey !== undefined ? options.primaryKey : existing.primaryKey,
|
|
5007
|
+
nullable: options?.nullable !== undefined ? options.nullable : existing.nullable,
|
|
5008
|
+
autoIncrement: options?.autoIncrement !== undefined ? options.autoIncrement : existing.autoIncrement,
|
|
5009
|
+
defaultValue: options?.defaultValue !== undefined ? options.defaultValue : existing.defaultValue,
|
|
5010
|
+
propertyKey: String(propertyKey)
|
|
5011
|
+
};
|
|
5012
|
+
} else {
|
|
5013
|
+
existingColumns.push(columnDef);
|
|
5014
|
+
}
|
|
5015
|
+
Reflect.defineMetadata(COLUMN_METADATA_KEY, existingColumns, target.constructor);
|
|
5016
|
+
};
|
|
5017
|
+
}
|
|
5018
|
+
function PrimaryKey() {
|
|
5019
|
+
return Column({ primaryKey: true, nullable: false });
|
|
5020
|
+
}
|
|
5021
|
+
function getEntityMetadata(target) {
|
|
5022
|
+
if (typeof target === "function" || typeof target === "object" && target !== null) {
|
|
5023
|
+
return Reflect.getMetadata(ENTITY_METADATA_KEY, target);
|
|
5024
|
+
}
|
|
5025
|
+
return;
|
|
5026
|
+
}
|
|
5027
|
+
function getColumnMetadata(target) {
|
|
5028
|
+
if (typeof target === "function" || typeof target === "object" && target !== null) {
|
|
5029
|
+
return Reflect.getMetadata(COLUMN_METADATA_KEY, target) || [];
|
|
5030
|
+
}
|
|
5031
|
+
return [];
|
|
5032
|
+
}
|
|
5033
|
+
// src/database/orm/repository-decorator.ts
|
|
5034
|
+
import"reflect-metadata";
|
|
5035
|
+
var REPOSITORY_METADATA_KEY = Symbol("@dangao/bun-server:orm:repository");
|
|
5036
|
+
function Repository(tableName, primaryKey = "id") {
|
|
5037
|
+
return function(target) {
|
|
5038
|
+
Injectable()(target);
|
|
5039
|
+
Reflect.defineMetadata(REPOSITORY_METADATA_KEY, { tableName, primaryKey }, target);
|
|
5040
|
+
return target;
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
function getRepositoryMetadata(target) {
|
|
5044
|
+
if (typeof target === "function" || typeof target === "object" && target !== null) {
|
|
5045
|
+
return Reflect.getMetadata(REPOSITORY_METADATA_KEY, target);
|
|
5046
|
+
}
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
// src/database/orm/index.ts
|
|
5051
|
+
init_transaction_decorator();
|
|
5052
|
+
|
|
5053
|
+
// src/database/orm/repository.ts
|
|
5054
|
+
class BaseRepository {
|
|
5055
|
+
databaseService;
|
|
5056
|
+
constructor(databaseService) {
|
|
5057
|
+
this.databaseService = databaseService;
|
|
5058
|
+
}
|
|
5059
|
+
async findAll() {
|
|
5060
|
+
const sql = `SELECT * FROM ${this.tableName}`;
|
|
5061
|
+
const result = await this.executeQuery(sql);
|
|
5062
|
+
return Array.isArray(result) ? result : [];
|
|
5063
|
+
}
|
|
5064
|
+
async findById(id) {
|
|
5065
|
+
const sql = `SELECT * FROM ${this.tableName} WHERE ${this.primaryKey} = ?`;
|
|
5066
|
+
const result = await this.executeQuery(sql, [id]);
|
|
5067
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
5068
|
+
return result[0];
|
|
5069
|
+
}
|
|
5070
|
+
return null;
|
|
5071
|
+
}
|
|
5072
|
+
async create(data) {
|
|
5073
|
+
const keys = Object.keys(data);
|
|
5074
|
+
const values = Object.values(data);
|
|
5075
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
5076
|
+
const sql = `INSERT INTO ${this.tableName} (${keys.join(", ")}) VALUES (${placeholders})`;
|
|
5077
|
+
await this.executeQuery(sql, values);
|
|
5078
|
+
const lastIdResult = await this.executeQuery("SELECT last_insert_rowid() as id");
|
|
5079
|
+
const lastId = Array.isArray(lastIdResult) && lastIdResult[0] ? lastIdResult[0].id : null;
|
|
5080
|
+
if (lastId !== null) {
|
|
5081
|
+
return await this.findById(lastId);
|
|
5082
|
+
}
|
|
5083
|
+
return data;
|
|
5084
|
+
}
|
|
5085
|
+
async update(id, data) {
|
|
5086
|
+
const keys = Object.keys(data);
|
|
5087
|
+
const values = Object.values(data);
|
|
5088
|
+
const setClause = keys.map((key) => `${key} = ?`).join(", ");
|
|
5089
|
+
const sql = `UPDATE ${this.tableName} SET ${setClause} WHERE ${this.primaryKey} = ?`;
|
|
5090
|
+
await this.executeQuery(sql, [...values, id]);
|
|
5091
|
+
return await this.findById(id);
|
|
5092
|
+
}
|
|
5093
|
+
async delete(id) {
|
|
5094
|
+
const sql = `DELETE FROM ${this.tableName} WHERE ${this.primaryKey} = ?`;
|
|
5095
|
+
await this.executeQuery(sql, [id]);
|
|
5096
|
+
return true;
|
|
5097
|
+
}
|
|
5098
|
+
async executeQuery(sql, params) {
|
|
5099
|
+
const result = this.databaseService.query(sql, params);
|
|
5100
|
+
if (result instanceof Promise) {
|
|
5101
|
+
const resolved = await result;
|
|
5102
|
+
return Array.isArray(resolved) ? resolved : [resolved];
|
|
5103
|
+
}
|
|
5104
|
+
return Array.isArray(result) ? result : [result];
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
BaseRepository = __legacyDecorateClassTS([
|
|
5108
|
+
__legacyDecorateParamTS(0, Inject(DATABASE_SERVICE_TOKEN)),
|
|
5109
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
5110
|
+
typeof DatabaseService === "undefined" ? Object : DatabaseService
|
|
5111
|
+
])
|
|
5112
|
+
], BaseRepository);
|
|
5113
|
+
// src/database/orm/drizzle-repository.ts
|
|
5114
|
+
class DrizzleBaseRepository {
|
|
5115
|
+
databaseService;
|
|
5116
|
+
constructor(databaseService) {
|
|
5117
|
+
this.databaseService = databaseService;
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
|
|
5121
|
+
// src/database/orm/index.ts
|
|
5122
|
+
init_transaction_interceptor();
|
|
5123
|
+
init_transaction_types();
|
|
3492
5124
|
// src/testing/harness.ts
|
|
3493
5125
|
import { performance as performance2 } from "perf_hooks";
|
|
3494
5126
|
|
|
@@ -3551,12 +5183,20 @@ class StressTester {
|
|
|
3551
5183
|
}
|
|
3552
5184
|
export {
|
|
3553
5185
|
requiresAuth,
|
|
5186
|
+
getTransactionMetadata,
|
|
5187
|
+
getRepositoryMetadata,
|
|
5188
|
+
getEntityMetadata,
|
|
5189
|
+
getColumnMetadata,
|
|
3554
5190
|
getAuthMetadata,
|
|
5191
|
+
createUserKeyGenerator,
|
|
5192
|
+
createTokenKeyGenerator,
|
|
3555
5193
|
createSwaggerUIMiddleware,
|
|
3556
5194
|
createStaticFileMiddleware,
|
|
3557
5195
|
createSecurityFilter,
|
|
3558
5196
|
createRequestLoggingMiddleware,
|
|
5197
|
+
createRateLimitMiddleware,
|
|
3559
5198
|
createLoggerMiddleware,
|
|
5199
|
+
createHttpMetricsMiddleware,
|
|
3560
5200
|
createFileUploadMiddleware,
|
|
3561
5201
|
createErrorHandlingMiddleware,
|
|
3562
5202
|
createCorsMiddleware,
|
|
@@ -3567,6 +5207,11 @@ export {
|
|
|
3567
5207
|
Validate,
|
|
3568
5208
|
UseMiddleware,
|
|
3569
5209
|
UnauthorizedException,
|
|
5210
|
+
Transactional,
|
|
5211
|
+
TransactionStatus,
|
|
5212
|
+
TransactionManager,
|
|
5213
|
+
TransactionInterceptor,
|
|
5214
|
+
TRANSACTION_SERVICE_TOKEN,
|
|
3570
5215
|
SwaggerModule,
|
|
3571
5216
|
SwaggerGenerator,
|
|
3572
5217
|
SwaggerExtension,
|
|
@@ -3579,16 +5224,23 @@ export {
|
|
|
3579
5224
|
RoleBasedAccessDecisionManager,
|
|
3580
5225
|
ResponseBuilder,
|
|
3581
5226
|
RequestWrapper,
|
|
5227
|
+
Repository,
|
|
5228
|
+
RateLimit,
|
|
3582
5229
|
Query,
|
|
5230
|
+
Propagation,
|
|
5231
|
+
PrometheusFormatter,
|
|
5232
|
+
PrimaryKey,
|
|
3583
5233
|
PerformanceHarness,
|
|
3584
5234
|
ParamBinder,
|
|
3585
5235
|
Param,
|
|
3586
5236
|
PUT,
|
|
3587
5237
|
POST,
|
|
3588
5238
|
PATCH,
|
|
5239
|
+
OrmService,
|
|
3589
5240
|
OnOpen,
|
|
3590
5241
|
OnMessage,
|
|
3591
5242
|
OnClose,
|
|
5243
|
+
ORM_SERVICE_TOKEN,
|
|
3592
5244
|
OAuth2Service,
|
|
3593
5245
|
OAuth2Controller,
|
|
3594
5246
|
OAuth2AuthenticationProvider,
|
|
@@ -3598,6 +5250,10 @@ export {
|
|
|
3598
5250
|
Module,
|
|
3599
5251
|
MinLength,
|
|
3600
5252
|
MiddlewarePipeline,
|
|
5253
|
+
MetricsModule,
|
|
5254
|
+
MetricsCollector,
|
|
5255
|
+
METRICS_SERVICE_TOKEN,
|
|
5256
|
+
METRICS_OPTIONS_TOKEN,
|
|
3601
5257
|
LoggerModule,
|
|
3602
5258
|
LoggerExtension,
|
|
3603
5259
|
LogLevel2 as LogLevel,
|
|
@@ -3606,6 +5262,7 @@ export {
|
|
|
3606
5262
|
JwtAuthenticationProvider,
|
|
3607
5263
|
JWT_UTIL_TOKEN,
|
|
3608
5264
|
JWTUtil,
|
|
5265
|
+
IsolationLevel,
|
|
3609
5266
|
IsString,
|
|
3610
5267
|
IsOptional,
|
|
3611
5268
|
IsNumber,
|
|
@@ -3621,17 +5278,29 @@ export {
|
|
|
3621
5278
|
GET,
|
|
3622
5279
|
ForbiddenException,
|
|
3623
5280
|
ExceptionFilterRegistry,
|
|
5281
|
+
Entity,
|
|
5282
|
+
DrizzleBaseRepository,
|
|
5283
|
+
DatabaseService2 as DatabaseService,
|
|
5284
|
+
DatabaseModule,
|
|
5285
|
+
DatabaseHealthIndicator,
|
|
5286
|
+
DatabaseExtension,
|
|
5287
|
+
DatabaseConnectionManager,
|
|
3624
5288
|
DELETE,
|
|
5289
|
+
DATABASE_SERVICE_TOKEN,
|
|
5290
|
+
DATABASE_OPTIONS_TOKEN,
|
|
3625
5291
|
ControllerRegistry,
|
|
3626
5292
|
Controller,
|
|
3627
5293
|
Context,
|
|
3628
5294
|
Container,
|
|
5295
|
+
ConnectionPool,
|
|
3629
5296
|
ConfigService,
|
|
3630
5297
|
ConfigModule,
|
|
5298
|
+
Column,
|
|
3631
5299
|
CONFIG_SERVICE_TOKEN,
|
|
3632
5300
|
BunServer,
|
|
3633
5301
|
BodyParser,
|
|
3634
5302
|
Body,
|
|
5303
|
+
BaseRepository,
|
|
3635
5304
|
BadRequestException,
|
|
3636
5305
|
AuthenticationManager,
|
|
3637
5306
|
Auth,
|