@dangao/bun-server 1.0.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/dist/controller/controller.d.ts +1 -1
  2. package/dist/controller/controller.d.ts.map +1 -1
  3. package/dist/core/application.d.ts.map +1 -1
  4. package/dist/database/database-extension.d.ts.map +1 -1
  5. package/dist/database/database-module.d.ts.map +1 -1
  6. package/dist/database/orm/transaction-decorator.d.ts +1 -0
  7. package/dist/database/orm/transaction-decorator.d.ts.map +1 -1
  8. package/dist/database/orm/transaction-interceptor.d.ts +12 -3
  9. package/dist/database/orm/transaction-interceptor.d.ts.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +678 -310
  13. package/dist/interceptor/base-interceptor.d.ts +94 -0
  14. package/dist/interceptor/base-interceptor.d.ts.map +1 -0
  15. package/dist/interceptor/builtin/cache-interceptor.d.ts +69 -0
  16. package/dist/interceptor/builtin/cache-interceptor.d.ts.map +1 -0
  17. package/dist/interceptor/builtin/index.d.ts +4 -0
  18. package/dist/interceptor/builtin/index.d.ts.map +1 -0
  19. package/dist/interceptor/builtin/log-interceptor.d.ts +56 -0
  20. package/dist/interceptor/builtin/log-interceptor.d.ts.map +1 -0
  21. package/dist/interceptor/builtin/permission-interceptor.d.ts +70 -0
  22. package/dist/interceptor/builtin/permission-interceptor.d.ts.map +1 -0
  23. package/dist/interceptor/index.d.ts +7 -0
  24. package/dist/interceptor/index.d.ts.map +1 -0
  25. package/dist/interceptor/interceptor-chain.d.ts +22 -0
  26. package/dist/interceptor/interceptor-chain.d.ts.map +1 -0
  27. package/dist/interceptor/interceptor-registry.d.ts +59 -0
  28. package/dist/interceptor/interceptor-registry.d.ts.map +1 -0
  29. package/dist/interceptor/metadata.d.ts +12 -0
  30. package/dist/interceptor/metadata.d.ts.map +1 -0
  31. package/dist/interceptor/types.d.ts +42 -0
  32. package/dist/interceptor/types.d.ts.map +1 -0
  33. package/dist/middleware/decorators.d.ts +2 -1
  34. package/dist/middleware/decorators.d.ts.map +1 -1
  35. package/dist/router/decorators.d.ts.map +1 -1
  36. package/dist/router/registry.d.ts +2 -1
  37. package/dist/router/registry.d.ts.map +1 -1
  38. package/dist/router/route.d.ts +3 -2
  39. package/dist/router/route.d.ts.map +1 -1
  40. package/dist/router/router.d.ts +2 -1
  41. package/dist/router/router.d.ts.map +1 -1
  42. package/dist/websocket/decorators.d.ts +2 -1
  43. package/dist/websocket/decorators.d.ts.map +1 -1
  44. package/package.json +5 -3
  45. package/readme.md +163 -2
  46. package/src/auth/controller.ts +148 -0
  47. package/src/auth/decorators.ts +81 -0
  48. package/src/auth/index.ts +12 -0
  49. package/src/auth/jwt.ts +169 -0
  50. package/src/auth/oauth2.ts +244 -0
  51. package/src/auth/types.ts +248 -0
  52. package/src/cache/cache-module.ts +67 -0
  53. package/src/cache/decorators.ts +202 -0
  54. package/src/cache/index.ts +27 -0
  55. package/src/cache/service.ts +151 -0
  56. package/src/cache/types.ts +420 -0
  57. package/src/config/config-module.ts +76 -0
  58. package/src/config/index.ts +8 -0
  59. package/src/config/service.ts +93 -0
  60. package/src/config/types.ts +27 -0
  61. package/src/controller/controller.ts +278 -0
  62. package/src/controller/decorators.ts +84 -0
  63. package/src/controller/index.ts +7 -0
  64. package/src/controller/metadata.ts +27 -0
  65. package/src/controller/param-binder.ts +157 -0
  66. package/src/core/application.ts +239 -0
  67. package/src/core/context.ts +228 -0
  68. package/src/core/index.ts +4 -0
  69. package/src/core/server.ts +128 -0
  70. package/src/core/types.ts +2 -0
  71. package/src/database/connection-manager.ts +239 -0
  72. package/src/database/connection-pool.ts +322 -0
  73. package/src/database/database-extension.ts +83 -0
  74. package/src/database/database-module.ts +121 -0
  75. package/src/database/health-indicator.ts +51 -0
  76. package/src/database/index.ts +47 -0
  77. package/src/database/orm/decorators.ts +155 -0
  78. package/src/database/orm/drizzle-repository.ts +39 -0
  79. package/src/database/orm/index.ts +23 -0
  80. package/src/database/orm/repository-decorator.ts +39 -0
  81. package/src/database/orm/repository.ts +103 -0
  82. package/src/database/orm/service.ts +49 -0
  83. package/src/database/orm/transaction-decorator.ts +76 -0
  84. package/src/database/orm/transaction-interceptor.ts +263 -0
  85. package/src/database/orm/transaction-manager.ts +276 -0
  86. package/src/database/orm/transaction-types.ts +140 -0
  87. package/src/database/orm/types.ts +99 -0
  88. package/src/database/service.ts +221 -0
  89. package/src/database/types.ts +171 -0
  90. package/src/di/container.ts +398 -0
  91. package/src/di/decorators.ts +228 -0
  92. package/src/di/index.ts +4 -0
  93. package/src/di/module-registry.ts +188 -0
  94. package/src/di/module.ts +65 -0
  95. package/src/di/types.ts +67 -0
  96. package/src/error/error-codes.ts +222 -0
  97. package/src/error/filter.ts +43 -0
  98. package/src/error/handler.ts +66 -0
  99. package/src/error/http-exception.ts +115 -0
  100. package/src/error/i18n.ts +217 -0
  101. package/src/error/index.ts +16 -0
  102. package/src/extensions/index.ts +5 -0
  103. package/src/extensions/logger-extension.ts +31 -0
  104. package/src/extensions/logger-module.ts +69 -0
  105. package/src/extensions/types.ts +14 -0
  106. package/src/files/index.ts +5 -0
  107. package/src/files/static-middleware.ts +53 -0
  108. package/src/files/storage.ts +67 -0
  109. package/src/files/types.ts +33 -0
  110. package/src/files/upload-middleware.ts +45 -0
  111. package/src/health/controller.ts +76 -0
  112. package/src/health/health-module.ts +51 -0
  113. package/src/health/index.ts +12 -0
  114. package/src/health/types.ts +28 -0
  115. package/src/index.ts +292 -0
  116. package/src/interceptor/base-interceptor.ts +203 -0
  117. package/src/interceptor/builtin/cache-interceptor.ts +169 -0
  118. package/src/interceptor/builtin/index.ts +28 -0
  119. package/src/interceptor/builtin/log-interceptor.ts +178 -0
  120. package/src/interceptor/builtin/permission-interceptor.ts +173 -0
  121. package/src/interceptor/index.ts +26 -0
  122. package/src/interceptor/interceptor-chain.ts +79 -0
  123. package/src/interceptor/interceptor-registry.ts +132 -0
  124. package/src/interceptor/metadata.ts +40 -0
  125. package/src/interceptor/types.ts +52 -0
  126. package/src/metrics/collector.ts +209 -0
  127. package/src/metrics/controller.ts +40 -0
  128. package/src/metrics/index.ts +15 -0
  129. package/src/metrics/metrics-module.ts +58 -0
  130. package/src/metrics/middleware.ts +46 -0
  131. package/src/metrics/prometheus.ts +79 -0
  132. package/src/metrics/types.ts +103 -0
  133. package/src/middleware/builtin/cors.ts +60 -0
  134. package/src/middleware/builtin/error-handler.ts +90 -0
  135. package/src/middleware/builtin/file-upload.ts +42 -0
  136. package/src/middleware/builtin/index.ts +14 -0
  137. package/src/middleware/builtin/logger.ts +91 -0
  138. package/src/middleware/builtin/rate-limit.ts +252 -0
  139. package/src/middleware/builtin/static-file.ts +88 -0
  140. package/src/middleware/decorators.ts +92 -0
  141. package/src/middleware/index.ts +11 -0
  142. package/src/middleware/middleware.ts +13 -0
  143. package/src/middleware/pipeline.ts +93 -0
  144. package/src/queue/decorators.ts +110 -0
  145. package/src/queue/index.ts +26 -0
  146. package/src/queue/queue-module.ts +64 -0
  147. package/src/queue/service.ts +302 -0
  148. package/src/queue/types.ts +341 -0
  149. package/src/request/body-parser.ts +133 -0
  150. package/src/request/file-handler.ts +46 -0
  151. package/src/request/index.ts +5 -0
  152. package/src/request/request.ts +107 -0
  153. package/src/request/response.ts +150 -0
  154. package/src/router/decorators.ts +123 -0
  155. package/src/router/index.ts +6 -0
  156. package/src/router/registry.ts +99 -0
  157. package/src/router/route.ts +141 -0
  158. package/src/router/router.ts +242 -0
  159. package/src/router/types.ts +27 -0
  160. package/src/security/access-decision-manager.ts +34 -0
  161. package/src/security/authentication-manager.ts +47 -0
  162. package/src/security/context.ts +92 -0
  163. package/src/security/filter.ts +162 -0
  164. package/src/security/index.ts +8 -0
  165. package/src/security/providers/index.ts +3 -0
  166. package/src/security/providers/jwt-provider.ts +60 -0
  167. package/src/security/providers/oauth2-provider.ts +70 -0
  168. package/src/security/security-module.ts +145 -0
  169. package/src/security/types.ts +165 -0
  170. package/src/session/decorators.ts +45 -0
  171. package/src/session/index.ts +19 -0
  172. package/src/session/middleware.ts +143 -0
  173. package/src/session/service.ts +218 -0
  174. package/src/session/session-module.ts +69 -0
  175. package/src/session/types.ts +373 -0
  176. package/src/swagger/decorators.ts +133 -0
  177. package/src/swagger/generator.ts +234 -0
  178. package/src/swagger/index.ts +7 -0
  179. package/src/swagger/swagger-extension.ts +41 -0
  180. package/src/swagger/swagger-module.ts +83 -0
  181. package/src/swagger/types.ts +188 -0
  182. package/src/swagger/ui.ts +98 -0
  183. package/src/testing/harness.ts +96 -0
  184. package/src/validation/decorators.ts +95 -0
  185. package/src/validation/errors.ts +28 -0
  186. package/src/validation/index.ts +14 -0
  187. package/src/validation/types.ts +35 -0
  188. package/src/validation/validator.ts +63 -0
  189. package/src/websocket/decorators.ts +53 -0
  190. package/src/websocket/index.ts +12 -0
  191. package/src/websocket/registry.ts +133 -0
  192. package/tests/cache/cache-module.test.ts +212 -0
  193. package/tests/config/config-module.test.ts +151 -0
  194. package/tests/controller/controller.test.ts +189 -0
  195. package/tests/controller/path-combination.test.ts +207 -0
  196. package/tests/core/application.test.ts +57 -0
  197. package/tests/core/context-body.test.ts +44 -0
  198. package/tests/core/context.test.ts +86 -0
  199. package/tests/core/edge-cases.test.ts +432 -0
  200. package/tests/database/database-module.test.ts +385 -0
  201. package/tests/database/orm.test.ts +164 -0
  202. package/tests/database/postgres-mysql-integration.test.ts +395 -0
  203. package/tests/database/transaction.test.ts +238 -0
  204. package/tests/di/container.test.ts +264 -0
  205. package/tests/di/module.test.ts +128 -0
  206. package/tests/error/error-codes.test.ts +121 -0
  207. package/tests/error/error-handler.test.ts +68 -0
  208. package/tests/error/error-handling.test.ts +254 -0
  209. package/tests/error/http-exception.test.ts +37 -0
  210. package/tests/error/i18n-integration.test.ts +175 -0
  211. package/tests/extensions/logger-extension.test.ts +40 -0
  212. package/tests/files/static-middleware.test.ts +67 -0
  213. package/tests/files/upload-middleware.test.ts +43 -0
  214. package/tests/health/health-module.test.ts +116 -0
  215. package/tests/integration/application-router.test.ts +85 -0
  216. package/tests/integration/body-parsing.test.ts +88 -0
  217. package/tests/integration/cache-e2e.test.ts +114 -0
  218. package/tests/integration/oauth2-e2e.test.ts +615 -0
  219. package/tests/integration/session-e2e.test.ts +207 -0
  220. package/tests/interceptor/builtin/cache-interceptor.test.ts +137 -0
  221. package/tests/interceptor/builtin/permission-interceptor.test.ts +182 -0
  222. package/tests/interceptor/interceptor-advanced-integration.test.ts +592 -0
  223. package/tests/interceptor/interceptor-arg-modification.test.ts +76 -0
  224. package/tests/interceptor/interceptor-chain.test.ts +199 -0
  225. package/tests/interceptor/interceptor-integration.test.ts +230 -0
  226. package/tests/interceptor/interceptor-registry.test.ts +200 -0
  227. package/tests/interceptor/perf/interceptor-performance.test.ts +341 -0
  228. package/tests/metrics/metrics-module.test.ts +178 -0
  229. package/tests/middleware/builtin.test.ts +206 -0
  230. package/tests/middleware/file-upload.test.ts +41 -0
  231. package/tests/middleware/middleware.test.ts +120 -0
  232. package/tests/middleware/pipeline.test.ts +72 -0
  233. package/tests/middleware/rate-limit.test.ts +314 -0
  234. package/tests/middleware/static-file.test.ts +62 -0
  235. package/tests/perf/harness.test.ts +48 -0
  236. package/tests/perf/optimization.test.ts +183 -0
  237. package/tests/perf/regression.test.ts +120 -0
  238. package/tests/queue/queue-module.test.ts +217 -0
  239. package/tests/request/body-parser.test.ts +96 -0
  240. package/tests/request/response.test.ts +99 -0
  241. package/tests/router/decorators.test.ts +46 -0
  242. package/tests/router/registry.test.ts +51 -0
  243. package/tests/router/route.test.ts +71 -0
  244. package/tests/router/router-normalization.test.ts +106 -0
  245. package/tests/router/router.test.ts +133 -0
  246. package/tests/security/access-decision-manager.test.ts +84 -0
  247. package/tests/security/authentication-manager.test.ts +81 -0
  248. package/tests/security/context.test.ts +302 -0
  249. package/tests/security/filter.test.ts +225 -0
  250. package/tests/security/jwt-provider.test.ts +106 -0
  251. package/tests/security/oauth2-provider.test.ts +269 -0
  252. package/tests/security/security-module.test.ts +143 -0
  253. package/tests/session/session-module.test.ts +307 -0
  254. package/tests/stress/di-stress.test.ts +30 -0
  255. package/tests/swagger/decorators.test.ts +153 -0
  256. package/tests/swagger/generator.test.ts +202 -0
  257. package/tests/swagger/swagger-extension.test.ts +72 -0
  258. package/tests/swagger/swagger-module.test.ts +79 -0
  259. package/tests/utils/test-port.ts +10 -0
  260. package/tests/validation/controller-validation.test.ts +64 -0
  261. package/tests/validation/validation.test.ts +42 -0
  262. package/tests/websocket/gateway.test.ts +68 -0
@@ -0,0 +1,169 @@
1
+ import 'reflect-metadata';
2
+ import { BaseInterceptor } from '../base-interceptor';
3
+ import type { Container } from '../../di/container';
4
+ import type { Context } from '../../core/context';
5
+
6
+ /**
7
+ * 缓存元数据键
8
+ */
9
+ export const CACHE_METADATA_KEY = Symbol('@dangao/bun-server:interceptor:cache');
10
+
11
+ /**
12
+ * 缓存配置选项
13
+ */
14
+ export interface CacheOptions {
15
+ /**
16
+ * 缓存时间(毫秒)
17
+ * @default 60000 (1分钟)
18
+ */
19
+ ttl?: number;
20
+ /**
21
+ * 自定义缓存键(可选)
22
+ * 如果不提供,将使用方法名和参数生成键
23
+ */
24
+ key?: string;
25
+ }
26
+
27
+ /**
28
+ * 缓存装饰器
29
+ * 标记方法需要缓存结果
30
+ * @param options - 缓存配置选项
31
+ */
32
+ export function Cache(options: CacheOptions = {}): MethodDecorator {
33
+ return (target, propertyKey, descriptor) => {
34
+ const metadata = {
35
+ ttl: options.ttl ?? 60000,
36
+ key: options.key,
37
+ };
38
+ Reflect.defineMetadata(CACHE_METADATA_KEY, metadata, target, propertyKey);
39
+ };
40
+ }
41
+
42
+ /**
43
+ * 获取缓存元数据
44
+ */
45
+ export function getCacheMetadata(
46
+ target: unknown,
47
+ propertyKey: string | symbol,
48
+ ): CacheOptions | undefined {
49
+ if (typeof target === 'object' && target !== null) {
50
+ return Reflect.getMetadata(CACHE_METADATA_KEY, target, propertyKey);
51
+ }
52
+ return undefined;
53
+ }
54
+
55
+ /**
56
+ * 缓存拦截器
57
+ * 实现方法结果缓存功能
58
+ */
59
+ export class CacheInterceptor extends BaseInterceptor {
60
+ /**
61
+ * 内存缓存存储
62
+ * key: 缓存键
63
+ * value: { data: 缓存数据, expires: 过期时间戳 }
64
+ */
65
+ private static cache = new Map<
66
+ string,
67
+ { data: unknown; expires: number }
68
+ >();
69
+
70
+ /**
71
+ * 执行拦截器逻辑
72
+ */
73
+ public async execute<T>(
74
+ target: unknown,
75
+ propertyKey: string | symbol,
76
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
77
+ args: unknown[],
78
+ container: Container,
79
+ context?: Context,
80
+ ): Promise<T> {
81
+ const metadata = this.getMetadata<CacheOptions>(
82
+ target,
83
+ propertyKey,
84
+ CACHE_METADATA_KEY,
85
+ );
86
+
87
+ if (!metadata) {
88
+ // 没有缓存元数据,直接执行原方法
89
+ return await Promise.resolve(originalMethod.apply(target, args));
90
+ }
91
+
92
+ // 生成缓存键
93
+ const cacheKey = this.generateCacheKey(
94
+ target,
95
+ propertyKey,
96
+ args,
97
+ metadata.key,
98
+ );
99
+
100
+ // 检查缓存
101
+ const cached = CacheInterceptor.cache.get(cacheKey);
102
+ if (cached && cached.expires > Date.now()) {
103
+ // 缓存命中,返回缓存数据
104
+ return cached.data as T;
105
+ }
106
+
107
+ // 执行原方法
108
+ const result = await Promise.resolve(originalMethod.apply(target, args));
109
+
110
+ // 缓存结果
111
+ CacheInterceptor.cache.set(cacheKey, {
112
+ data: result,
113
+ expires: Date.now() + metadata.ttl!,
114
+ });
115
+
116
+ return result;
117
+ }
118
+
119
+ /**
120
+ * 生成缓存键
121
+ */
122
+ private generateCacheKey(
123
+ target: unknown,
124
+ propertyKey: string | symbol,
125
+ args: unknown[],
126
+ customKey?: string,
127
+ ): string {
128
+ if (customKey) {
129
+ return customKey;
130
+ }
131
+
132
+ // 使用类名、方法名和参数生成键
133
+ const className = typeof target === 'object' && target !== null
134
+ ? (target as any).constructor?.name || 'Unknown'
135
+ : 'Unknown';
136
+ const methodName = String(propertyKey);
137
+ const argsKey = JSON.stringify(args);
138
+
139
+ return `${className}:${methodName}:${argsKey}`;
140
+ }
141
+
142
+ /**
143
+ * 清除所有缓存
144
+ */
145
+ public static clearCache(): void {
146
+ CacheInterceptor.cache.clear();
147
+ }
148
+
149
+ /**
150
+ * 清除指定键的缓存
151
+ */
152
+ public static clearCacheKey(key: string): void {
153
+ CacheInterceptor.cache.delete(key);
154
+ }
155
+
156
+ /**
157
+ * 获取缓存统计信息
158
+ */
159
+ public static getCacheStats(): {
160
+ size: number;
161
+ keys: string[];
162
+ } {
163
+ return {
164
+ size: CacheInterceptor.cache.size,
165
+ keys: Array.from(CacheInterceptor.cache.keys()),
166
+ };
167
+ }
168
+ }
169
+
@@ -0,0 +1,28 @@
1
+ // Cache interceptor
2
+ export {
3
+ Cache,
4
+ CacheInterceptor,
5
+ CACHE_METADATA_KEY,
6
+ getCacheMetadata,
7
+ type CacheOptions,
8
+ } from './cache-interceptor';
9
+
10
+ // Permission interceptor
11
+ export {
12
+ Permission,
13
+ PermissionInterceptor,
14
+ PERMISSION_METADATA_KEY,
15
+ getPermissionMetadata,
16
+ type PermissionOptions,
17
+ type PermissionService,
18
+ } from './permission-interceptor';
19
+
20
+ // Log interceptor
21
+ export {
22
+ Log,
23
+ LogInterceptor,
24
+ LOG_METADATA_KEY,
25
+ getLogMetadata,
26
+ type LogOptions,
27
+ } from './log-interceptor';
28
+
@@ -0,0 +1,178 @@
1
+ import 'reflect-metadata';
2
+ import { BaseInterceptor } from '../base-interceptor';
3
+ import type { Container } from '../../di/container';
4
+ import type { Context } from '../../core/context';
5
+ import { LOGGER_TOKEN } from '../../extensions';
6
+ import type { Logger } from '@dangao/logsmith';
7
+
8
+ /**
9
+ * 日志元数据键
10
+ */
11
+ export const LOG_METADATA_KEY = Symbol('@dangao/bun-server:interceptor:log');
12
+
13
+ /**
14
+ * 日志配置选项
15
+ */
16
+ export interface LogOptions {
17
+ /**
18
+ * 日志级别
19
+ * @default 'info'
20
+ */
21
+ level?: 'debug' | 'info' | 'warn' | 'error';
22
+
23
+ /**
24
+ * 自定义日志消息(可选)
25
+ * 如果不提供,将使用方法名
26
+ */
27
+ message?: string;
28
+
29
+ /**
30
+ * 是否记录方法参数
31
+ * @default false
32
+ */
33
+ logArgs?: boolean;
34
+
35
+ /**
36
+ * 是否记录返回值
37
+ * @default false
38
+ */
39
+ logResult?: boolean;
40
+
41
+ /**
42
+ * 是否记录执行时间
43
+ * @default true
44
+ */
45
+ logDuration?: boolean;
46
+ }
47
+
48
+ /**
49
+ * 日志装饰器
50
+ * 标记方法需要记录日志
51
+ * @param options - 日志配置选项
52
+ */
53
+ export function Log(options: LogOptions = {}): MethodDecorator {
54
+ return (target, propertyKey, descriptor) => {
55
+ const metadata: LogOptions = {
56
+ level: options.level || 'info',
57
+ message: options.message,
58
+ logArgs: options.logArgs ?? false,
59
+ logResult: options.logResult ?? false,
60
+ logDuration: options.logDuration ?? true,
61
+ };
62
+ Reflect.defineMetadata(LOG_METADATA_KEY, metadata, target, propertyKey);
63
+ };
64
+ }
65
+
66
+ /**
67
+ * 获取日志元数据
68
+ */
69
+ export function getLogMetadata(
70
+ target: unknown,
71
+ propertyKey: string | symbol,
72
+ ): LogOptions | undefined {
73
+ if (typeof target === 'object' && target !== null) {
74
+ return Reflect.getMetadata(LOG_METADATA_KEY, target, propertyKey);
75
+ }
76
+ return undefined;
77
+ }
78
+
79
+ /**
80
+ * 日志拦截器
81
+ * 记录方法执行日志,包括执行时间、参数和返回值
82
+ */
83
+ export class LogInterceptor extends BaseInterceptor {
84
+ public async execute<T>(
85
+ target: unknown,
86
+ propertyKey: string | symbol,
87
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
88
+ args: unknown[],
89
+ container: Container,
90
+ context?: Context,
91
+ ): Promise<T> {
92
+ const options = this.getMetadata<LogOptions>(target, propertyKey, LOG_METADATA_KEY) || {};
93
+ const level = options.level || 'info';
94
+ const methodName = String(propertyKey);
95
+ const logMessage = options.message || `Executing ${methodName}`;
96
+ const logArgs = options.logArgs ?? false;
97
+ const logResult = options.logResult ?? false;
98
+ const logDuration = options.logDuration ?? true;
99
+
100
+ // Try to resolve logger from container
101
+ let logger: Logger | undefined;
102
+ try {
103
+ logger = container.resolve<Logger>(LOGGER_TOKEN);
104
+ } catch {
105
+ // Logger not available, use console
106
+ }
107
+
108
+ const log = (msg: string, data?: unknown) => {
109
+ if (logger) {
110
+ switch (level) {
111
+ case 'debug':
112
+ logger.debug(msg, data);
113
+ break;
114
+ case 'info':
115
+ logger.info(msg, data);
116
+ break;
117
+ case 'warn':
118
+ logger.warn(msg, data);
119
+ break;
120
+ case 'error':
121
+ logger.error(msg, data);
122
+ break;
123
+ }
124
+ } else {
125
+ console.log(`[${level.toUpperCase()}] ${msg}`, data || '');
126
+ }
127
+ };
128
+
129
+ const startTime = logDuration ? performance.now() : undefined;
130
+
131
+ // Log start
132
+ if (logArgs && args.length > 0) {
133
+ log(`${logMessage} - Start`, { args });
134
+ } else {
135
+ log(`${logMessage} - Start`);
136
+ }
137
+
138
+ try {
139
+ // Execute original method
140
+ const result = await Promise.resolve(originalMethod.apply(target, args));
141
+
142
+ // Calculate duration
143
+ const duration = startTime ? performance.now() - startTime : undefined;
144
+
145
+ // Log completion
146
+ const logData: Record<string, unknown> = {};
147
+ if (duration !== undefined) {
148
+ logData.duration = `${duration.toFixed(2)}ms`;
149
+ }
150
+ if (logResult) {
151
+ logData.result = result;
152
+ }
153
+
154
+ if (Object.keys(logData).length > 0) {
155
+ log(`${logMessage} - Completed`, logData);
156
+ } else {
157
+ log(`${logMessage} - Completed`);
158
+ }
159
+
160
+ return result;
161
+ } catch (error) {
162
+ // Calculate duration even on error
163
+ const duration = startTime ? performance.now() - startTime : undefined;
164
+
165
+ // Log error
166
+ const errorMessage = error instanceof Error ? error.message : String(error);
167
+ const logData: Record<string, unknown> = { error: errorMessage };
168
+ if (duration !== undefined) {
169
+ logData.duration = `${duration.toFixed(2)}ms`;
170
+ }
171
+
172
+ log(`${logMessage} - Failed`, logData);
173
+
174
+ throw error;
175
+ }
176
+ }
177
+ }
178
+
@@ -0,0 +1,173 @@
1
+ import 'reflect-metadata';
2
+ import { BaseInterceptor } from '../base-interceptor';
3
+ import type { Container } from '../../di/container';
4
+ import type { Context } from '../../core/context';
5
+ import { ForbiddenException } from '../../error';
6
+
7
+ /**
8
+ * 权限元数据键
9
+ */
10
+ export const PERMISSION_METADATA_KEY = Symbol('@dangao/bun-server:interceptor:permission');
11
+
12
+ /**
13
+ * 权限配置选项
14
+ */
15
+ export interface PermissionOptions {
16
+ /**
17
+ * 资源名称
18
+ */
19
+ resource: string;
20
+ /**
21
+ * 操作名称(如:read, write, delete)
22
+ */
23
+ action: string;
24
+ /**
25
+ * 是否允许匿名访问
26
+ * @default false
27
+ */
28
+ allowAnonymous?: boolean;
29
+ }
30
+
31
+ /**
32
+ * 权限服务接口
33
+ * 用户需要实现此接口来提供权限检查逻辑
34
+ */
35
+ export interface PermissionService {
36
+ /**
37
+ * 检查权限
38
+ * @param userId - 用户 ID(从请求头或上下文获取)
39
+ * @param resource - 资源名称
40
+ * @param action - 操作名称
41
+ * @returns 是否有权限
42
+ */
43
+ check(userId: string | null, resource: string, action: string): Promise<boolean>;
44
+ }
45
+
46
+ /**
47
+ * 权限装饰器
48
+ * 标记方法需要权限检查
49
+ * @param options - 权限配置选项
50
+ */
51
+ export function Permission(options: PermissionOptions): MethodDecorator {
52
+ return (target, propertyKey, descriptor) => {
53
+ const metadata = {
54
+ resource: options.resource,
55
+ action: options.action,
56
+ allowAnonymous: options.allowAnonymous ?? false,
57
+ };
58
+ Reflect.defineMetadata(PERMISSION_METADATA_KEY, metadata, target, propertyKey);
59
+ };
60
+ }
61
+
62
+ /**
63
+ * 获取权限元数据
64
+ */
65
+ export function getPermissionMetadata(
66
+ target: unknown,
67
+ propertyKey: string | symbol,
68
+ ): PermissionOptions | undefined {
69
+ if (typeof target === 'object' && target !== null) {
70
+ return Reflect.getMetadata(PERMISSION_METADATA_KEY, target, propertyKey);
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ /**
76
+ * 权限拦截器
77
+ * 实现权限检查功能
78
+ */
79
+ export class PermissionInterceptor extends BaseInterceptor {
80
+ /**
81
+ * 权限服务 Token
82
+ * 用户需要在 DI 容器中注册 PermissionService 实现
83
+ */
84
+ public static readonly PERMISSION_SERVICE_TOKEN = Symbol(
85
+ '@dangao/bun-server:interceptor:permission:service',
86
+ );
87
+
88
+ /**
89
+ * 执行拦截器逻辑
90
+ */
91
+ public async execute<T>(
92
+ target: unknown,
93
+ propertyKey: string | symbol,
94
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
95
+ args: unknown[],
96
+ container: Container,
97
+ context?: Context,
98
+ ): Promise<T> {
99
+ const metadata = this.getMetadata<PermissionOptions>(
100
+ target,
101
+ propertyKey,
102
+ PERMISSION_METADATA_KEY,
103
+ );
104
+
105
+ if (!metadata) {
106
+ // 没有权限元数据,直接执行原方法
107
+ return await Promise.resolve(originalMethod.apply(target, args));
108
+ }
109
+
110
+ // 如果允许匿名访问,直接执行
111
+ if (metadata.allowAnonymous) {
112
+ return await Promise.resolve(originalMethod.apply(target, args));
113
+ }
114
+
115
+ // 获取用户 ID(从请求头或上下文)
116
+ const userId = this.getUserId(context);
117
+
118
+ // 尝试获取权限服务
119
+ let permissionService: PermissionService | undefined;
120
+ try {
121
+ permissionService = this.resolveService<PermissionService>(
122
+ container,
123
+ PermissionInterceptor.PERMISSION_SERVICE_TOKEN,
124
+ );
125
+ } catch (error) {
126
+ // 如果权限服务未注册,抛出错误
127
+ throw new Error(
128
+ 'PermissionService not found. Please register PermissionService in DI container.',
129
+ );
130
+ }
131
+
132
+ // 检查权限
133
+ const hasPermission = await permissionService.check(
134
+ userId,
135
+ metadata.resource,
136
+ metadata.action,
137
+ );
138
+
139
+ if (!hasPermission) {
140
+ throw new ForbiddenException(
141
+ `Permission denied: ${metadata.action} on ${metadata.resource}`,
142
+ );
143
+ }
144
+
145
+ // 权限检查通过,执行原方法
146
+ return await Promise.resolve(originalMethod.apply(target, args));
147
+ }
148
+
149
+ /**
150
+ * 从上下文获取用户 ID
151
+ */
152
+ private getUserId(context: Context | undefined): string | null {
153
+ if (!context) {
154
+ return null;
155
+ }
156
+
157
+ // 优先从 Authorization header 获取(Bearer token)
158
+ const authHeader = this.getHeader(context, 'Authorization');
159
+ if (authHeader && authHeader.startsWith('Bearer ')) {
160
+ // 这里可以解析 JWT token 获取用户 ID
161
+ // 简化实现:从 X-User-Id header 获取
162
+ }
163
+
164
+ // 从 X-User-Id header 获取
165
+ const userId = this.getHeader(context, 'X-User-Id');
166
+ if (userId) {
167
+ return userId;
168
+ }
169
+
170
+ return null;
171
+ }
172
+ }
173
+
@@ -0,0 +1,26 @@
1
+ export { type Interceptor, type InterceptorMetadata, INTERCEPTOR_REGISTRY_TOKEN } from './types';
2
+ export { InterceptorRegistry, type InterceptorRegistry as InterceptorRegistryType } from './interceptor-registry';
3
+ export { InterceptorChain } from './interceptor-chain';
4
+ export { scanInterceptorMetadata } from './metadata';
5
+ export { BaseInterceptor } from './base-interceptor';
6
+
7
+ // Built-in interceptors
8
+ export {
9
+ Cache,
10
+ CacheInterceptor,
11
+ CACHE_METADATA_KEY,
12
+ getCacheMetadata,
13
+ type CacheOptions,
14
+ Permission,
15
+ PermissionInterceptor,
16
+ PERMISSION_METADATA_KEY,
17
+ getPermissionMetadata,
18
+ type PermissionOptions,
19
+ type PermissionService,
20
+ Log,
21
+ LogInterceptor,
22
+ LOG_METADATA_KEY,
23
+ getLogMetadata,
24
+ type LogOptions,
25
+ } from './builtin';
26
+
@@ -0,0 +1,79 @@
1
+ import type { Interceptor } from './types';
2
+ import type { Container } from '../di/container';
3
+ import type { Context } from '../core/context';
4
+
5
+ /**
6
+ * 拦截器链执行器
7
+ * 负责按优先级顺序执行多个拦截器
8
+ */
9
+ export class InterceptorChain {
10
+ /**
11
+ * 执行拦截器链
12
+ * @param interceptors - 拦截器列表(已按优先级排序)
13
+ * @param target - 目标对象
14
+ * @param propertyKey - 方法名
15
+ * @param originalMethod - 原始方法
16
+ * @param args - 方法参数
17
+ * @param container - DI 容器
18
+ * @param context - 请求上下文(可选)
19
+ * @returns 方法执行结果
20
+ */
21
+ public static async execute<T>(
22
+ interceptors: Interceptor[],
23
+ target: unknown,
24
+ propertyKey: string | symbol,
25
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
26
+ args: unknown[],
27
+ container: Container,
28
+ context?: Context,
29
+ ): Promise<T> {
30
+ if (interceptors.length === 0) {
31
+ // 没有拦截器,直接执行原方法
32
+ return await Promise.resolve(originalMethod.apply(target, args));
33
+ }
34
+
35
+ // 构建执行链
36
+ let index = 0;
37
+ let currentArgs = args; // Track arguments that might be modified by interceptors
38
+
39
+ const next = async (modifiedArgs?: unknown[]): Promise<T> => {
40
+ // 如果拦截器传递了新参数,使用新参数;否则使用当前参数
41
+ if (modifiedArgs && modifiedArgs.length > 0) {
42
+ currentArgs = modifiedArgs;
43
+ }
44
+
45
+ if (index >= interceptors.length) {
46
+ // 所有拦截器执行完毕,执行原方法(使用可能被修改的参数)
47
+ return await Promise.resolve(originalMethod.apply(target, currentArgs));
48
+ }
49
+
50
+ const interceptor = interceptors[index++];
51
+
52
+ // 执行当前拦截器,传递 next 作为下一个执行函数
53
+ // 注意:拦截器接口要求 originalMethod 的类型是 (...args: unknown[]) => T | Promise<T>
54
+ // 这允许原始方法可以是同步(返回 T)或异步(返回 Promise<T>)
55
+ // 虽然 next 函数是异步的(总是返回 Promise<T>),但我们保持类型签名为 T | Promise<T>
56
+ // 以符合拦截器接口的要求。拦截器应该使用 Promise.resolve() 来统一处理同步和异步返回值
57
+ const wrappedNext = (...nextArgs: unknown[]): T | Promise<T> => {
58
+ // 如果拦截器传递了新参数,传递给 next;否则传递 undefined(使用当前参数)
59
+ // next 是异步函数,总是返回 Promise<T>,但类型签名允许 T | Promise<T>
60
+ const result = next(nextArgs.length > 0 ? nextArgs : undefined);
61
+ // 类型断言:虽然 result 总是 Promise<T>,但类型系统允许我们将其视为 T | Promise<T>
62
+ // 因为 Promise<T> 在运行时可以表示同步值(通过 Promise.resolve(syncValue))
63
+ return result as T | Promise<T>;
64
+ };
65
+
66
+ return await interceptor.execute(
67
+ target,
68
+ propertyKey,
69
+ wrappedNext,
70
+ currentArgs, // Pass current args to the interceptor
71
+ container,
72
+ context,
73
+ );
74
+ };
75
+
76
+ return await next();
77
+ }
78
+ }
79
+