@dangao/bun-server 0.1.5 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/controller/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,uBAAuB,eAAuB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAW,IACzB,QAAQ,WAAW,CAAC,OAAO,CAAC,UAI9C;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2D;IACvF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA8C;IAEnF,OAAO;IAIP;;OAEG;WACW,WAAW,IAAI,kBAAkB;IAO/C;;;OAGG;IACI,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI;IAiInF;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAepB;;;OAGG;IACI,YAAY,IAAI,SAAS;IAIhC;;;OAGG;IACI,wBAAwB,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE;IAIzD;;OAEG;IACI,KAAK,IAAI,IAAI;CAKrB"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/controller/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,uBAAuB,eAAuB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAW,IACzB,QAAQ,WAAW,CAAC,OAAO,CAAC,UAI9C;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2D;IACvF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA8C;IAEnF,OAAO;IAIP;;OAEG;WACW,WAAW,IAAI,kBAAkB;IAO/C;;;OAGG;IACI,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI;IAgHnF;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAepB;;;OAGG;IACI,YAAY,IAAI,SAAS;IAIhC;;;OAGG;IACI,wBAAwB,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE;IAIzD;;OAEG;IACI,KAAK,IAAI,IAAI;CAKrB"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 错误码定义
3
+ * 格式:模块_错误类型_具体错误
4
+ * 例如:AUTH_INVALID_TOKEN, VALIDATION_REQUIRED_FIELD
5
+ */
6
+ export declare enum ErrorCode {
7
+ INTERNAL_ERROR = "INTERNAL_ERROR",
8
+ INVALID_REQUEST = "INVALID_REQUEST",
9
+ RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND",
10
+ METHOD_NOT_ALLOWED = "METHOD_NOT_ALLOWED",
11
+ AUTH_REQUIRED = "AUTH_REQUIRED",
12
+ AUTH_INVALID_TOKEN = "AUTH_INVALID_TOKEN",
13
+ AUTH_TOKEN_EXPIRED = "AUTH_TOKEN_EXPIRED",
14
+ AUTH_INSUFFICIENT_PERMISSIONS = "AUTH_INSUFFICIENT_PERMISSIONS",
15
+ VALIDATION_FAILED = "VALIDATION_FAILED",
16
+ VALIDATION_REQUIRED_FIELD = "VALIDATION_REQUIRED_FIELD",
17
+ VALIDATION_INVALID_FORMAT = "VALIDATION_INVALID_FORMAT",
18
+ VALIDATION_OUT_OF_RANGE = "VALIDATION_OUT_OF_RANGE",
19
+ OAUTH2_INVALID_CLIENT = "OAUTH2_INVALID_CLIENT",
20
+ OAUTH2_INVALID_GRANT = "OAUTH2_INVALID_GRANT",
21
+ OAUTH2_INVALID_SCOPE = "OAUTH2_INVALID_SCOPE",
22
+ OAUTH2_INVALID_REDIRECT_URI = "OAUTH2_INVALID_REDIRECT_URI",
23
+ OAUTH2_UNSUPPORTED_GRANT_TYPE = "OAUTH2_UNSUPPORTED_GRANT_TYPE"
24
+ }
25
+ /**
26
+ * 错误码到 HTTP 状态码的映射
27
+ */
28
+ export declare const ERROR_CODE_TO_STATUS: Record<ErrorCode, number>;
29
+ /**
30
+ * 错误码的默认消息(英文)
31
+ */
32
+ export declare const ERROR_CODE_MESSAGES: Record<ErrorCode, string>;
33
+ //# sourceMappingURL=error-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/error/error-codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,oBAAY,SAAS;IAEnB,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,kBAAkB,uBAAuB;IACzC,kBAAkB,uBAAuB;IAGzC,aAAa,kBAAkB;IAC/B,kBAAkB,uBAAuB;IACzC,kBAAkB,uBAAuB;IACzC,6BAA6B,kCAAkC;IAG/D,iBAAiB,sBAAsB;IACvC,yBAAyB,8BAA8B;IACvD,yBAAyB,8BAA8B;IACvD,uBAAuB,4BAA4B;IAGnD,qBAAqB,0BAA0B;IAC/C,oBAAoB,yBAAyB;IAC7C,oBAAoB,yBAAyB;IAC7C,2BAA2B,gCAAgC;IAC3D,6BAA6B,kCAAkC;CAChE;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAkB1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAkBzD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/error/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK/C;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6BrF"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/error/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiDrF"}
@@ -1,24 +1,30 @@
1
+ import { ErrorCode } from './error-codes';
1
2
  /**
2
3
  * HTTP 异常基类
3
4
  */
4
5
  export declare class HttpException extends Error {
5
6
  readonly status: number;
7
+ readonly code?: ErrorCode;
6
8
  readonly details?: unknown;
7
- constructor(status: number, message: string, details?: unknown);
9
+ constructor(status: number, message: string, details?: unknown, code?: ErrorCode);
10
+ /**
11
+ * 创建带错误码的异常
12
+ */
13
+ static withCode(code: ErrorCode, message?: string, details?: unknown): HttpException;
8
14
  }
9
15
  export declare class BadRequestException extends HttpException {
10
- constructor(message?: string, details?: unknown);
16
+ constructor(message?: string, details?: unknown, code?: ErrorCode);
11
17
  }
12
18
  export declare class UnauthorizedException extends HttpException {
13
- constructor(message?: string, details?: unknown);
19
+ constructor(message?: string, details?: unknown, code?: ErrorCode);
14
20
  }
15
21
  export declare class ForbiddenException extends HttpException {
16
- constructor(message?: string, details?: unknown);
22
+ constructor(message?: string, details?: unknown, code?: ErrorCode);
17
23
  }
18
24
  export declare class NotFoundException extends HttpException {
19
- constructor(message?: string, details?: unknown);
25
+ constructor(message?: string, details?: unknown, code?: ErrorCode);
20
26
  }
21
27
  export declare class InternalServerErrorException extends HttpException {
22
- constructor(message?: string, details?: unknown);
28
+ constructor(message?: string, details?: unknown, code?: ErrorCode);
23
29
  }
24
30
  //# sourceMappingURL=http-exception.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-exception.d.ts","sourceRoot":"","sources":["../../src/error/http-exception.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAMtE;AAED,qBAAa,mBAAoB,SAAQ,aAAa;gBACjC,OAAO,GAAE,MAAsB,EAAE,OAAO,CAAC,EAAE,OAAO;CAGtE;AAED,qBAAa,qBAAsB,SAAQ,aAAa;gBACnC,OAAO,GAAE,MAAuB,EAAE,OAAO,CAAC,EAAE,OAAO;CAGvE;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBAChC,OAAO,GAAE,MAAoB,EAAE,OAAO,CAAC,EAAE,OAAO;CAGpE;AAED,qBAAa,iBAAkB,SAAQ,aAAa;gBAC/B,OAAO,GAAE,MAAoB,EAAE,OAAO,CAAC,EAAE,OAAO;CAGpE;AAED,qBAAa,4BAA6B,SAAQ,aAAa;gBAC1C,OAAO,GAAE,MAAgC,EAAE,OAAO,CAAC,EAAE,OAAO;CAGhF"}
1
+ {"version":3,"file":"http-exception.d.ts","sourceRoot":"","sources":["../../src/error/http-exception.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA6C,MAAM,eAAe,CAAC;AAErF;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjC,SAAgB,OAAO,CAAC,EAAE,OAAO,CAAC;gBAGhC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;IASlB;;OAEG;WACW,QAAQ,CACpB,IAAI,EAAE,SAAS,EACf,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,aAAa;CAKjB;AAED,qBAAa,mBAAoB,SAAQ,aAAa;gBAElD,OAAO,GAAE,MAAsB,EAC/B,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;CAInB;AAED,qBAAa,qBAAsB,SAAQ,aAAa;gBAEpD,OAAO,GAAE,MAAuB,EAChC,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;CAInB;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBAEjD,OAAO,GAAE,MAAoB,EAC7B,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;CAInB;AAED,qBAAa,iBAAkB,SAAQ,aAAa;gBAEhD,OAAO,GAAE,MAAoB,EAC7B,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;CAInB;AAED,qBAAa,4BAA6B,SAAQ,aAAa;gBAE3D,OAAO,GAAE,MAAgC,EACzC,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,SAAS;CAInB"}
@@ -0,0 +1,28 @@
1
+ import { ErrorCode } from './error-codes';
2
+ /**
3
+ * 支持的语言
4
+ */
5
+ export type SupportedLanguage = 'en' | 'zh-CN';
6
+ /**
7
+ * 错误消息国际化服务
8
+ */
9
+ export declare class ErrorMessageI18n {
10
+ private static currentLanguage;
11
+ /**
12
+ * 设置当前语言
13
+ */
14
+ static setLanguage(language: SupportedLanguage): void;
15
+ /**
16
+ * 获取当前语言
17
+ */
18
+ static getLanguage(): SupportedLanguage;
19
+ /**
20
+ * 获取错误消息(国际化)
21
+ */
22
+ static getMessage(code: ErrorCode, language?: SupportedLanguage): string;
23
+ /**
24
+ * 从 Accept-Language 头解析语言
25
+ */
26
+ static parseLanguageFromHeader(acceptLanguage?: string | null): SupportedLanguage;
27
+ }
28
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/error/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAuB,MAAM,eAAe,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC;AA+B/C;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,eAAe,CAA2B;IAEzD;;OAEG;WACW,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAI5D;;OAEG;WACW,WAAW,IAAI,iBAAiB;IAI9C;;OAEG;WACW,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM;IAM/E;;OAEG;WACW,uBAAuB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB;CAYzF"}
@@ -2,4 +2,7 @@ export { HttpException, BadRequestException, UnauthorizedException, ForbiddenExc
2
2
  export type { ExceptionFilter } from './filter';
3
3
  export { ExceptionFilterRegistry } from './filter';
4
4
  export { handleError } from './handler';
5
+ export { ErrorCode, ERROR_CODE_MESSAGES, ERROR_CODE_TO_STATUS } from './error-codes';
6
+ export { ErrorMessageI18n } from './i18n';
7
+ export type { SupportedLanguage } from './i18n';
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,14 @@
1
1
  // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
2
12
  var __legacyDecorateClassTS = function(decorators, target, key, desc) {
3
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
14
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -14,6 +24,371 @@ var __legacyMetadataTS = (k, v) => {
14
24
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
15
25
  return Reflect.metadata(k, v);
16
26
  };
27
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
+
29
+ // src/validation/decorators.ts
30
+ import"reflect-metadata";
31
+ function getOrCreateMetadata(target, propertyKey) {
32
+ const existing = Reflect.getMetadata(VALIDATION_METADATA_KEY, target, propertyKey);
33
+ if (existing) {
34
+ return existing;
35
+ }
36
+ const metadata = [];
37
+ Reflect.defineMetadata(VALIDATION_METADATA_KEY, metadata, target, propertyKey);
38
+ return metadata;
39
+ }
40
+ function Validate(...rules) {
41
+ return (target, propertyKey, parameterIndex) => {
42
+ if (!propertyKey) {
43
+ throw new Error("@Validate decorator can only be used on methods");
44
+ }
45
+ if (!rules.length) {
46
+ throw new Error("@Validate requires at least one validation rule");
47
+ }
48
+ const metadata = getOrCreateMetadata(target, propertyKey);
49
+ let entry = metadata.find((item) => item.index === parameterIndex);
50
+ if (!entry) {
51
+ entry = { index: parameterIndex, rules: [] };
52
+ metadata.push(entry);
53
+ }
54
+ entry.rules.push(...rules);
55
+ };
56
+ }
57
+ function IsString(options = {}) {
58
+ return {
59
+ name: "isString",
60
+ message: options.message ?? "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32",
61
+ validate: (value) => typeof value === "string"
62
+ };
63
+ }
64
+ function IsNumber(options = {}) {
65
+ return {
66
+ name: "isNumber",
67
+ message: options.message ?? "\u5FC5\u987B\u662F\u6570\u5B57",
68
+ validate: (value) => typeof value === "number" && !Number.isNaN(value)
69
+ };
70
+ }
71
+ function IsEmail(options = {}) {
72
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
73
+ return {
74
+ name: "isEmail",
75
+ message: options.message ?? "\u5FC5\u987B\u662F\u5408\u6CD5\u7684\u90AE\u7BB1\u5730\u5740",
76
+ validate: (value) => typeof value === "string" && emailRegex.test(value)
77
+ };
78
+ }
79
+ function IsOptional() {
80
+ return {
81
+ name: "isOptional",
82
+ message: "",
83
+ optional: true,
84
+ validate: () => true
85
+ };
86
+ }
87
+ function MinLength(min, options = {}) {
88
+ return {
89
+ name: "minLength",
90
+ message: options.message ?? `\u957F\u5EA6\u4E0D\u80FD\u5C0F\u4E8E ${min}`,
91
+ validate: (value) => typeof value === "string" && value.length >= min
92
+ };
93
+ }
94
+ function getValidationMetadata(target, propertyKey) {
95
+ return Reflect.getMetadata(VALIDATION_METADATA_KEY, target, propertyKey) || [];
96
+ }
97
+ var VALIDATION_METADATA_KEY;
98
+ var init_decorators = __esm(() => {
99
+ VALIDATION_METADATA_KEY = Symbol("validation:param");
100
+ });
101
+
102
+ // src/validation/errors.ts
103
+ var ValidationError;
104
+ var init_errors = __esm(() => {
105
+ ValidationError = class ValidationError extends Error {
106
+ issues;
107
+ constructor(message, issues) {
108
+ super(message);
109
+ this.name = "ValidationError";
110
+ this.issues = issues;
111
+ }
112
+ };
113
+ });
114
+
115
+ // src/validation/validator.ts
116
+ function shouldSkip(rule, value) {
117
+ return rule.optional === true && (value === undefined || value === null);
118
+ }
119
+ function validateRule(rule, value, index) {
120
+ if (shouldSkip(rule, value)) {
121
+ return null;
122
+ }
123
+ const passed = rule.validate(value);
124
+ if (passed) {
125
+ return null;
126
+ }
127
+ return {
128
+ index,
129
+ rule: rule.name,
130
+ message: rule.message
131
+ };
132
+ }
133
+ function validateParameters(params, metadata) {
134
+ if (!metadata.length) {
135
+ return;
136
+ }
137
+ const issues = [];
138
+ for (const item of metadata) {
139
+ const value = params[item.index];
140
+ let skipped = false;
141
+ for (const rule of item.rules) {
142
+ if (rule.optional && (value === undefined || value === null)) {
143
+ skipped = true;
144
+ break;
145
+ }
146
+ const issue = validateRule(rule, value, item.index);
147
+ if (issue) {
148
+ issues.push(issue);
149
+ }
150
+ }
151
+ if (skipped) {
152
+ continue;
153
+ }
154
+ }
155
+ if (issues.length > 0) {
156
+ throw new ValidationError("Validation failed", issues);
157
+ }
158
+ }
159
+ var init_validator = __esm(() => {
160
+ init_errors();
161
+ });
162
+
163
+ // src/validation/index.ts
164
+ var init_validation = __esm(() => {
165
+ init_decorators();
166
+ init_validator();
167
+ init_errors();
168
+ });
169
+
170
+ // src/error/error-codes.ts
171
+ var ERROR_CODE_TO_STATUS, ERROR_CODE_MESSAGES;
172
+ var init_error_codes = __esm(() => {
173
+ ERROR_CODE_TO_STATUS = {
174
+ ["INTERNAL_ERROR" /* INTERNAL_ERROR */]: 500,
175
+ ["INVALID_REQUEST" /* INVALID_REQUEST */]: 400,
176
+ ["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: 404,
177
+ ["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: 405,
178
+ ["AUTH_REQUIRED" /* AUTH_REQUIRED */]: 401,
179
+ ["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: 401,
180
+ ["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: 401,
181
+ ["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: 403,
182
+ ["VALIDATION_FAILED" /* VALIDATION_FAILED */]: 400,
183
+ ["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: 400,
184
+ ["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: 400,
185
+ ["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: 400,
186
+ ["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: 400,
187
+ ["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: 400,
188
+ ["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: 400,
189
+ ["OAUTH2_INVALID_REDIRECT_URI" /* OAUTH2_INVALID_REDIRECT_URI */]: 400,
190
+ ["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: 400
191
+ };
192
+ ERROR_CODE_MESSAGES = {
193
+ ["INTERNAL_ERROR" /* INTERNAL_ERROR */]: "Internal Server Error",
194
+ ["INVALID_REQUEST" /* INVALID_REQUEST */]: "Invalid Request",
195
+ ["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "Resource Not Found",
196
+ ["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: "Method Not Allowed",
197
+ ["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "Authentication Required",
198
+ ["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "Invalid Authentication Token",
199
+ ["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: "Authentication Token Expired",
200
+ ["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: "Insufficient Permissions",
201
+ ["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "Validation Failed",
202
+ ["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: "Required Field Missing",
203
+ ["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: "Invalid Format",
204
+ ["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: "Value Out of Range",
205
+ ["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: "Invalid Client",
206
+ ["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: "Invalid Grant",
207
+ ["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: "Invalid Scope",
208
+ ["OAUTH2_INVALID_REDIRECT_URI" /* OAUTH2_INVALID_REDIRECT_URI */]: "Invalid Redirect URI",
209
+ ["OAUTH2_UNSUPPORTED_GRANT_TYPE" /* OAUTH2_UNSUPPORTED_GRANT_TYPE */]: "Unsupported Grant Type"
210
+ };
211
+ });
212
+
213
+ // src/error/http-exception.ts
214
+ var HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, InternalServerErrorException;
215
+ var init_http_exception = __esm(() => {
216
+ init_error_codes();
217
+ HttpException = class HttpException extends Error {
218
+ status;
219
+ code;
220
+ details;
221
+ constructor(status, message, details, code) {
222
+ super(message);
223
+ this.name = this.constructor.name;
224
+ this.status = status;
225
+ this.code = code;
226
+ this.details = details;
227
+ }
228
+ static withCode(code, message, details) {
229
+ const status = ERROR_CODE_TO_STATUS[code] || 500;
230
+ const finalMessage = message || ERROR_CODE_MESSAGES[code] || "Internal Server Error";
231
+ return new HttpException(status, finalMessage, details, code);
232
+ }
233
+ };
234
+ BadRequestException = class BadRequestException extends HttpException {
235
+ constructor(message = "Bad Request", details, code) {
236
+ super(400, message, details, code);
237
+ }
238
+ };
239
+ UnauthorizedException = class UnauthorizedException extends HttpException {
240
+ constructor(message = "Unauthorized", details, code) {
241
+ super(401, message, details, code);
242
+ }
243
+ };
244
+ ForbiddenException = class ForbiddenException extends HttpException {
245
+ constructor(message = "Forbidden", details, code) {
246
+ super(403, message, details, code);
247
+ }
248
+ };
249
+ NotFoundException = class NotFoundException extends HttpException {
250
+ constructor(message = "Not Found", details, code) {
251
+ super(404, message, details, code);
252
+ }
253
+ };
254
+ InternalServerErrorException = class InternalServerErrorException extends HttpException {
255
+ constructor(message = "Internal Server Error", details, code) {
256
+ super(500, message, details, code);
257
+ }
258
+ };
259
+ });
260
+
261
+ // src/error/filter.ts
262
+ class ExceptionFilterRegistry {
263
+ static instance;
264
+ filters = [];
265
+ constructor() {}
266
+ static getInstance() {
267
+ if (!ExceptionFilterRegistry.instance) {
268
+ ExceptionFilterRegistry.instance = new ExceptionFilterRegistry;
269
+ }
270
+ return ExceptionFilterRegistry.instance;
271
+ }
272
+ register(filter) {
273
+ this.filters.push(filter);
274
+ }
275
+ clear() {
276
+ this.filters.length = 0;
277
+ }
278
+ async execute(error, context) {
279
+ for (const filter of this.filters) {
280
+ const result = await filter.catch(error, context);
281
+ if (result) {
282
+ return result;
283
+ }
284
+ }
285
+ return;
286
+ }
287
+ }
288
+
289
+ // src/error/i18n.ts
290
+ class ErrorMessageI18n {
291
+ static currentLanguage = "en";
292
+ static setLanguage(language) {
293
+ this.currentLanguage = language;
294
+ }
295
+ static getLanguage() {
296
+ return this.currentLanguage;
297
+ }
298
+ static getMessage(code, language) {
299
+ const lang = language || this.currentLanguage;
300
+ const messages = ERROR_MESSAGES_I18N[lang];
301
+ return messages?.[code] || ERROR_CODE_MESSAGES[code] || "Internal Server Error";
302
+ }
303
+ static parseLanguageFromHeader(acceptLanguage) {
304
+ if (!acceptLanguage) {
305
+ return "en";
306
+ }
307
+ if (acceptLanguage.includes("zh-CN") || acceptLanguage.includes("zh")) {
308
+ return "zh-CN";
309
+ }
310
+ return "en";
311
+ }
312
+ }
313
+ var ERROR_MESSAGES_I18N;
314
+ var init_i18n = __esm(() => {
315
+ init_error_codes();
316
+ ERROR_MESSAGES_I18N = {
317
+ en: {
318
+ ...ERROR_CODE_MESSAGES
319
+ },
320
+ "zh-CN": {
321
+ ["INTERNAL_ERROR" /* INTERNAL_ERROR */]: "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF",
322
+ ["INVALID_REQUEST" /* INVALID_REQUEST */]: "\u65E0\u6548\u7684\u8BF7\u6C42",
323
+ ["RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */]: "\u8D44\u6E90\u672A\u627E\u5230",
324
+ ["METHOD_NOT_ALLOWED" /* METHOD_NOT_ALLOWED */]: "\u65B9\u6CD5\u4E0D\u5141\u8BB8",
325
+ ["AUTH_REQUIRED" /* AUTH_REQUIRED */]: "\u9700\u8981\u8BA4\u8BC1",
326
+ ["AUTH_INVALID_TOKEN" /* AUTH_INVALID_TOKEN */]: "\u65E0\u6548\u7684\u8BA4\u8BC1\u4EE4\u724C",
327
+ ["AUTH_TOKEN_EXPIRED" /* AUTH_TOKEN_EXPIRED */]: "\u8BA4\u8BC1\u4EE4\u724C\u5DF2\u8FC7\u671F",
328
+ ["AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */]: "\u6743\u9650\u4E0D\u8DB3",
329
+ ["VALIDATION_FAILED" /* VALIDATION_FAILED */]: "\u9A8C\u8BC1\u5931\u8D25",
330
+ ["VALIDATION_REQUIRED_FIELD" /* VALIDATION_REQUIRED_FIELD */]: "\u5FC5\u586B\u5B57\u6BB5\u7F3A\u5931",
331
+ ["VALIDATION_INVALID_FORMAT" /* VALIDATION_INVALID_FORMAT */]: "\u683C\u5F0F\u65E0\u6548",
332
+ ["VALIDATION_OUT_OF_RANGE" /* VALIDATION_OUT_OF_RANGE */]: "\u503C\u8D85\u51FA\u8303\u56F4",
333
+ ["OAUTH2_INVALID_CLIENT" /* OAUTH2_INVALID_CLIENT */]: "\u65E0\u6548\u7684\u5BA2\u6237\u7AEF",
334
+ ["OAUTH2_INVALID_GRANT" /* OAUTH2_INVALID_GRANT */]: "\u65E0\u6548\u7684\u6388\u6743",
335
+ ["OAUTH2_INVALID_SCOPE" /* OAUTH2_INVALID_SCOPE */]: "\u65E0\u6548\u7684\u4F5C\u7528\u57DF",
336
+ ["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"
338
+ }
339
+ };
340
+ });
341
+
342
+ // src/error/handler.ts
343
+ var exports_handler = {};
344
+ __export(exports_handler, {
345
+ handleError: () => handleError
346
+ });
347
+ async function handleError(error, context) {
348
+ const registry = ExceptionFilterRegistry.getInstance();
349
+ const filterResponse = await registry.execute(error, context);
350
+ if (filterResponse) {
351
+ return filterResponse;
352
+ }
353
+ if (error instanceof HttpException) {
354
+ context.setStatus(error.status);
355
+ let errorMessage = error.message;
356
+ if (error.code) {
357
+ const acceptLanguage = context.getHeader("accept-language");
358
+ const language = ErrorMessageI18n.parseLanguageFromHeader(acceptLanguage);
359
+ errorMessage = ErrorMessageI18n.getMessage(error.code, language);
360
+ }
361
+ const responseBody = {
362
+ error: errorMessage
363
+ };
364
+ if (error.code) {
365
+ responseBody.code = error.code;
366
+ }
367
+ if (error.details !== undefined) {
368
+ responseBody.details = error.details;
369
+ }
370
+ return context.createResponse(responseBody);
371
+ }
372
+ if (error instanceof ValidationError) {
373
+ context.setStatus(400);
374
+ return context.createResponse({
375
+ error: error.message,
376
+ code: "VALIDATION_FAILED",
377
+ issues: error.issues
378
+ });
379
+ }
380
+ const message = error instanceof Error ? error.message : String(error);
381
+ context.setStatus(500);
382
+ return context.createResponse({
383
+ error: "Internal Server Error",
384
+ details: message
385
+ });
386
+ }
387
+ var init_handler = __esm(() => {
388
+ init_http_exception();
389
+ init_validation();
390
+ init_i18n();
391
+ });
17
392
 
18
393
  // src/request/body-parser.ts
19
394
  class BodyParser {
@@ -1022,229 +1397,18 @@ function createRequestLoggingMiddleware(options = {}) {
1022
1397
  }
1023
1398
  };
1024
1399
  }
1025
- // src/validation/decorators.ts
1026
- import"reflect-metadata";
1027
- var VALIDATION_METADATA_KEY = Symbol("validation:param");
1028
- function getOrCreateMetadata(target, propertyKey) {
1029
- const existing = Reflect.getMetadata(VALIDATION_METADATA_KEY, target, propertyKey);
1030
- if (existing) {
1031
- return existing;
1032
- }
1033
- const metadata = [];
1034
- Reflect.defineMetadata(VALIDATION_METADATA_KEY, metadata, target, propertyKey);
1035
- return metadata;
1036
- }
1037
- function Validate(...rules) {
1038
- return (target, propertyKey, parameterIndex) => {
1039
- if (!propertyKey) {
1040
- throw new Error("@Validate decorator can only be used on methods");
1041
- }
1042
- if (!rules.length) {
1043
- throw new Error("@Validate requires at least one validation rule");
1044
- }
1045
- const metadata = getOrCreateMetadata(target, propertyKey);
1046
- let entry = metadata.find((item) => item.index === parameterIndex);
1047
- if (!entry) {
1048
- entry = { index: parameterIndex, rules: [] };
1049
- metadata.push(entry);
1050
- }
1051
- entry.rules.push(...rules);
1052
- };
1053
- }
1054
- function IsString(options = {}) {
1055
- return {
1056
- name: "isString",
1057
- message: options.message ?? "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32",
1058
- validate: (value) => typeof value === "string"
1059
- };
1060
- }
1061
- function IsNumber(options = {}) {
1062
- return {
1063
- name: "isNumber",
1064
- message: options.message ?? "\u5FC5\u987B\u662F\u6570\u5B57",
1065
- validate: (value) => typeof value === "number" && !Number.isNaN(value)
1066
- };
1067
- }
1068
- function IsEmail(options = {}) {
1069
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1070
- return {
1071
- name: "isEmail",
1072
- message: options.message ?? "\u5FC5\u987B\u662F\u5408\u6CD5\u7684\u90AE\u7BB1\u5730\u5740",
1073
- validate: (value) => typeof value === "string" && emailRegex.test(value)
1074
- };
1075
- }
1076
- function IsOptional() {
1077
- return {
1078
- name: "isOptional",
1079
- message: "",
1080
- optional: true,
1081
- validate: () => true
1082
- };
1083
- }
1084
- function MinLength(min, options = {}) {
1085
- return {
1086
- name: "minLength",
1087
- message: options.message ?? `\u957F\u5EA6\u4E0D\u80FD\u5C0F\u4E8E ${min}`,
1088
- validate: (value) => typeof value === "string" && value.length >= min
1089
- };
1090
- }
1091
- function getValidationMetadata(target, propertyKey) {
1092
- return Reflect.getMetadata(VALIDATION_METADATA_KEY, target, propertyKey) || [];
1093
- }
1094
- // src/validation/errors.ts
1095
- class ValidationError extends Error {
1096
- issues;
1097
- constructor(message, issues) {
1098
- super(message);
1099
- this.name = "ValidationError";
1100
- this.issues = issues;
1101
- }
1102
- }
1103
-
1104
- // src/validation/validator.ts
1105
- function shouldSkip(rule, value) {
1106
- return rule.optional === true && (value === undefined || value === null);
1107
- }
1108
- function validateRule(rule, value, index) {
1109
- if (shouldSkip(rule, value)) {
1110
- return null;
1111
- }
1112
- const passed = rule.validate(value);
1113
- if (passed) {
1114
- return null;
1115
- }
1116
- return {
1117
- index,
1118
- rule: rule.name,
1119
- message: rule.message
1120
- };
1121
- }
1122
- function validateParameters(params, metadata) {
1123
- if (!metadata.length) {
1124
- return;
1125
- }
1126
- const issues = [];
1127
- for (const item of metadata) {
1128
- const value = params[item.index];
1129
- let skipped = false;
1130
- for (const rule of item.rules) {
1131
- if (rule.optional && (value === undefined || value === null)) {
1132
- skipped = true;
1133
- break;
1134
- }
1135
- const issue = validateRule(rule, value, item.index);
1136
- if (issue) {
1137
- issues.push(issue);
1138
- }
1139
- }
1140
- if (skipped) {
1141
- continue;
1142
- }
1143
- }
1144
- if (issues.length > 0) {
1145
- throw new ValidationError("Validation failed", issues);
1146
- }
1147
- }
1148
1400
  // src/middleware/builtin/error-handler.ts
1401
+ init_validation();
1149
1402
  import { LoggerManager as LoggerManager5 } from "@dangao/logsmith";
1150
1403
 
1151
- // src/error/http-exception.ts
1152
- class HttpException extends Error {
1153
- status;
1154
- details;
1155
- constructor(status, message, details) {
1156
- super(message);
1157
- this.name = this.constructor.name;
1158
- this.status = status;
1159
- this.details = details;
1160
- }
1161
- }
1162
-
1163
- class BadRequestException extends HttpException {
1164
- constructor(message = "Bad Request", details) {
1165
- super(400, message, details);
1166
- }
1167
- }
1168
-
1169
- class UnauthorizedException extends HttpException {
1170
- constructor(message = "Unauthorized", details) {
1171
- super(401, message, details);
1172
- }
1173
- }
1404
+ // src/error/index.ts
1405
+ init_http_exception();
1406
+ init_handler();
1407
+ init_error_codes();
1408
+ init_i18n();
1174
1409
 
1175
- class ForbiddenException extends HttpException {
1176
- constructor(message = "Forbidden", details) {
1177
- super(403, message, details);
1178
- }
1179
- }
1180
-
1181
- class NotFoundException extends HttpException {
1182
- constructor(message = "Not Found", details) {
1183
- super(404, message, details);
1184
- }
1185
- }
1186
-
1187
- class InternalServerErrorException extends HttpException {
1188
- constructor(message = "Internal Server Error", details) {
1189
- super(500, message, details);
1190
- }
1191
- }
1192
- // src/error/filter.ts
1193
- class ExceptionFilterRegistry {
1194
- static instance;
1195
- filters = [];
1196
- constructor() {}
1197
- static getInstance() {
1198
- if (!ExceptionFilterRegistry.instance) {
1199
- ExceptionFilterRegistry.instance = new ExceptionFilterRegistry;
1200
- }
1201
- return ExceptionFilterRegistry.instance;
1202
- }
1203
- register(filter) {
1204
- this.filters.push(filter);
1205
- }
1206
- clear() {
1207
- this.filters.length = 0;
1208
- }
1209
- async execute(error, context) {
1210
- for (const filter of this.filters) {
1211
- const result = await filter.catch(error, context);
1212
- if (result) {
1213
- return result;
1214
- }
1215
- }
1216
- return;
1217
- }
1218
- }
1219
- // src/error/handler.ts
1220
- async function handleError(error, context) {
1221
- const registry = ExceptionFilterRegistry.getInstance();
1222
- const filterResponse = await registry.execute(error, context);
1223
- if (filterResponse) {
1224
- return filterResponse;
1225
- }
1226
- if (error instanceof HttpException) {
1227
- context.setStatus(error.status);
1228
- return context.createResponse({
1229
- error: error.message,
1230
- details: error.details
1231
- });
1232
- }
1233
- if (error instanceof ValidationError) {
1234
- context.setStatus(400);
1235
- return context.createResponse({
1236
- error: error.message,
1237
- issues: error.issues
1238
- });
1239
- }
1240
- const message = error instanceof Error ? error.message : String(error);
1241
- context.setStatus(500);
1242
- return context.createResponse({
1243
- error: "Internal Server Error",
1244
- details: message
1245
- });
1246
- }
1247
1410
  // src/middleware/builtin/error-handler.ts
1411
+ init_handler();
1248
1412
  function createErrorHandlingMiddleware(options = {}) {
1249
1413
  const log = options.logger ?? ((error, context) => {
1250
1414
  LoggerManager5.getLogger().error("[Error]", { ...context, error });
@@ -1274,13 +1438,7 @@ function createErrorHandlingMiddleware(options = {}) {
1274
1438
  });
1275
1439
  }
1276
1440
  if (error instanceof HttpException) {
1277
- if (!expose) {
1278
- return await handleError(error, context);
1279
- }
1280
- return context.createResponse({
1281
- error: error.message,
1282
- details: error.details
1283
- }, { status: error.status });
1441
+ return await handleError(error, context);
1284
1442
  }
1285
1443
  if (error instanceof Error && !expose) {
1286
1444
  return await handleError(error, context);
@@ -1455,6 +1613,7 @@ function createStaticFileMiddleware(options) {
1455
1613
  };
1456
1614
  }
1457
1615
  // src/controller/controller.ts
1616
+ init_validation();
1458
1617
  var CONTROLLER_METADATA_KEY = Symbol("controller");
1459
1618
  function Controller(path = "") {
1460
1619
  return function(target) {
@@ -1538,23 +1697,8 @@ class ControllerRegistry {
1538
1697
  }
1539
1698
  return context.createResponse(responseData);
1540
1699
  } catch (error) {
1541
- if (error instanceof ValidationError) {
1542
- context.setStatus(400);
1543
- return context.createResponse({
1544
- error: error.message,
1545
- issues: error.issues
1546
- });
1547
- }
1548
- if (error instanceof HttpException) {
1549
- context.setStatus(error.status);
1550
- return context.createResponse({
1551
- error: error.message,
1552
- details: error.details
1553
- });
1554
- }
1555
- context.setStatus(500);
1556
- const errorMessage = error instanceof Error ? error.message : String(error);
1557
- return context.createResponse({ error: errorMessage });
1700
+ const { handleError: handleError2 } = await Promise.resolve().then(() => (init_handler(), exports_handler));
1701
+ return await handleError2(error, context);
1558
1702
  }
1559
1703
  };
1560
1704
  const middlewares = [...classMiddlewares];
@@ -2079,6 +2223,8 @@ class ResponseBuilder {
2079
2223
  });
2080
2224
  }
2081
2225
  }
2226
+ // src/index.ts
2227
+ init_validation();
2082
2228
  // src/extensions/logger-module.ts
2083
2229
  class LoggerModule {
2084
2230
  static forRoot(options = {}) {
@@ -2490,8 +2636,8 @@ class SecurityContextHolder {
2490
2636
  return context;
2491
2637
  }
2492
2638
  static runWithContext(callback) {
2493
- const existing = this.storage.getStore() ?? new SecurityContextImpl;
2494
- return this.storage.run(existing, callback);
2639
+ const context = new SecurityContextImpl;
2640
+ return this.storage.run(context, callback);
2495
2641
  }
2496
2642
  static clearContext() {
2497
2643
  const context = this.storage.getStore();
@@ -2531,6 +2677,10 @@ class RoleBasedAccessDecisionManager {
2531
2677
  return requiredAuthorities.some((required) => userAuthorities.includes(required));
2532
2678
  }
2533
2679
  }
2680
+ // src/security/filter.ts
2681
+ init_http_exception();
2682
+ init_error_codes();
2683
+
2534
2684
  // src/auth/decorators.ts
2535
2685
  import"reflect-metadata";
2536
2686
  var AUTH_METADATA_KEY = Symbol("@dangao/bun-server:auth");
@@ -2601,19 +2751,19 @@ function createSecurityFilter(config) {
2601
2751
  if (requiresAuth(controllerTarget, method)) {
2602
2752
  const authentication = securityContext.authentication;
2603
2753
  if (!authentication || !authentication.authenticated) {
2604
- throw new UnauthorizedException("Authentication required");
2754
+ throw new UnauthorizedException("Authentication required", undefined, "AUTH_REQUIRED" /* AUTH_REQUIRED */);
2605
2755
  }
2606
2756
  const requiredRoles = getRequiredRoles(controllerTarget, method);
2607
2757
  if (requiredRoles.length > 0) {
2608
2758
  const hasAccess = accessDecisionManager.decide(authentication, requiredRoles);
2609
2759
  if (!hasAccess) {
2610
2760
  const userRoles = authentication.authorities || [];
2611
- throw new ForbiddenException(`Insufficient permissions. Required roles: ${requiredRoles.join(", ")}, User roles: ${userRoles.join(", ")}`);
2761
+ throw new ForbiddenException(`Insufficient permissions. Required roles: ${requiredRoles.join(", ")}, User roles: ${userRoles.join(", ")}`, { requiredRoles, userRoles }, "AUTH_INSUFFICIENT_PERMISSIONS" /* AUTH_INSUFFICIENT_PERMISSIONS */);
2612
2762
  }
2613
2763
  }
2614
2764
  }
2615
2765
  } else if (defaultAuthRequired && !securityContext.isAuthenticated()) {
2616
- throw new UnauthorizedException("Authentication required");
2766
+ throw new UnauthorizedException("Authentication required", undefined, "AUTH_REQUIRED" /* AUTH_REQUIRED */);
2617
2767
  }
2618
2768
  ctx.security = securityContext;
2619
2769
  ctx.auth = {
@@ -2634,7 +2784,7 @@ function extractTokenFromHeader(ctx) {
2634
2784
  return null;
2635
2785
  }
2636
2786
  const parts = authHeader.split(" ");
2637
- if (parts.length !== 2 || parts[0] !== "Bearer") {
2787
+ if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
2638
2788
  return null;
2639
2789
  }
2640
2790
  return parts[1];
@@ -2680,9 +2830,11 @@ class JwtAuthenticationProvider {
2680
2830
  // src/security/providers/oauth2-provider.ts
2681
2831
  class OAuth2AuthenticationProvider {
2682
2832
  oauth2Service;
2833
+ jwtUtil;
2683
2834
  supportedTypes = ["oauth2", "authorization_code"];
2684
- constructor(oauth2Service) {
2835
+ constructor(oauth2Service, jwtUtil) {
2685
2836
  this.oauth2Service = oauth2Service;
2837
+ this.jwtUtil = jwtUtil;
2686
2838
  }
2687
2839
  supports(type) {
2688
2840
  return this.supportedTypes.includes(type.toLowerCase());
@@ -2696,15 +2848,14 @@ class OAuth2AuthenticationProvider {
2696
2848
  if (!tokenResponse) {
2697
2849
  return null;
2698
2850
  }
2699
- const userInfo = {
2700
- id: "user-1",
2701
- username: "user",
2702
- roles: ["user"]
2703
- };
2851
+ const payload = this.jwtUtil.verify(tokenResponse.accessToken);
2852
+ if (!payload || !payload.sub) {
2853
+ return null;
2854
+ }
2704
2855
  const principal = {
2705
- id: userInfo.id,
2706
- username: userInfo.username,
2707
- roles: userInfo.roles
2856
+ id: payload.sub,
2857
+ username: payload.username || payload.sub,
2858
+ roles: payload.roles || []
2708
2859
  };
2709
2860
  return {
2710
2861
  authenticated: true,
@@ -3088,7 +3239,7 @@ class SecurityModule {
3088
3239
  const oauth2Service = new OAuth2Service(jwtUtil, config.oauth2Clients || [], {}, userProvider);
3089
3240
  const authenticationManager = new AuthenticationManager;
3090
3241
  authenticationManager.registerProvider(new JwtAuthenticationProvider(jwtUtil));
3091
- authenticationManager.registerProvider(new OAuth2AuthenticationProvider(oauth2Service));
3242
+ authenticationManager.registerProvider(new OAuth2AuthenticationProvider(oauth2Service, jwtUtil));
3092
3243
  const securityFilter = createSecurityFilter({
3093
3244
  authenticationManager,
3094
3245
  excludePaths: [
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAMhD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE7E;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,mBAAwB,GAChC,UAAU,CAoEZ"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAOhD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE7E;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,mBAAwB,GAChC,UAAU,CA4DZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/security/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1E;;GAEG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,eAAe,CAA+B;IAEtD;;OAEG;IACH,IAAW,cAAc,IAAI,cAAc,GAAG,IAAI,CAEjD;IAED;;OAEG;IACI,iBAAiB,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI;IAIrE;;OAEG;IACI,eAAe,IAAI,OAAO;IAIjC;;OAEG;IACI,YAAY,IAAI,SAAS,GAAG,IAAI;IAIvC;;OAEG;IACI,cAAc,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACI,KAAK,IAAI,IAAI;CAGrB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAgD;IAE/E;;OAEG;WACW,UAAU,IAAI,mBAAmB;IAS/C;;;OAGG;WACW,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IAKrD;;OAEG;WACW,YAAY,IAAI,IAAI;CAMnC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/security/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1E;;GAEG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,eAAe,CAA+B;IAEtD;;OAEG;IACH,IAAW,cAAc,IAAI,cAAc,GAAG,IAAI,CAEjD;IAED;;OAEG;IACI,iBAAiB,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI;IAIrE;;OAEG;IACI,eAAe,IAAI,OAAO;IAIjC;;OAEG;IACI,YAAY,IAAI,SAAS,GAAG,IAAI;IAIvC;;OAEG;IACI,cAAc,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACI,KAAK,IAAI,IAAI;CAGrB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAgD;IAE/E;;OAEG;WACW,UAAU,IAAI,mBAAmB;IAS/C;;;OAGG;WACW,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IAMrD;;OAEG;WACW,YAAY,IAAI,IAAI;CAMnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/security/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,SAAS,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D;;OAEG;IACH,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C;;OAEG;IACH,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;CAChD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CA2F7E"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/security/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,SAAS,CAAC;AAQrE;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D;;OAEG;IACH,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C;;OAEG;IACH,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;CAChD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CAqG7E"}
@@ -1,12 +1,14 @@
1
1
  import type { Authentication, AuthenticationProvider, AuthenticationRequest } from '../types';
2
2
  import { OAuth2Service } from '../../auth/oauth2';
3
+ import { JWTUtil } from '../../auth/jwt';
3
4
  /**
4
5
  * OAuth2 认证提供者
5
6
  */
6
7
  export declare class OAuth2AuthenticationProvider implements AuthenticationProvider {
7
8
  private readonly oauth2Service;
9
+ private readonly jwtUtil;
8
10
  readonly supportedTypes: string[];
9
- constructor(oauth2Service: OAuth2Service);
11
+ constructor(oauth2Service: OAuth2Service, jwtUtil: JWTUtil);
10
12
  /**
11
13
  * 是否支持该认证类型
12
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"oauth2-provider.d.ts","sourceRoot":"","sources":["../../../src/security/providers/oauth2-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD;;GAEG;AACH,qBAAa,4BAA6B,YAAW,sBAAsB;IAGtD,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFjD,SAAgB,cAAc,WAAoC;gBAE9B,aAAa,EAAE,aAAa;IAEhE;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACU,YAAY,CACvB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAqClC"}
1
+ {"version":3,"file":"oauth2-provider.d.ts","sourceRoot":"","sources":["../../../src/security/providers/oauth2-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC;;GAEG;AACH,qBAAa,4BAA6B,YAAW,sBAAsB;IAIvE,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,SAAgB,cAAc,WAAoC;gBAG/C,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,OAAO;IAGnC;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACU,YAAY,CACvB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAmClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"security-module.d.ts","sourceRoot":"","sources":["../../src/security/security-module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,GAAG,EAAE,SAAS,CAAC;IACf;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B;;OAEG;IACH,YAAY,CAAC,EAAE;QACb,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;KACpD,CAAC;IACF;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,qBAKa,cAAc;IACzB;;;OAGG;WACW,OAAO,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,cAAc;CA+E3E"}
1
+ {"version":3,"file":"security-module.d.ts","sourceRoot":"","sources":["../../src/security/security-module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,GAAG,EAAE,SAAS,CAAC;IACf;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B;;OAEG;IACH,YAAY,CAAC,EAAE;QACb,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;KACpD,CAAC;IACF;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,qBAKa,cAAc;IACzB;;;OAGG;WACW,OAAO,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,cAAc;CAiF3E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",