@dangao/bun-server 1.7.1 → 1.8.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.
Files changed (116) hide show
  1. package/README.md +129 -21
  2. package/dist/di/decorators.d.ts +37 -0
  3. package/dist/di/decorators.d.ts.map +1 -1
  4. package/dist/di/index.d.ts +1 -1
  5. package/dist/di/index.d.ts.map +1 -1
  6. package/dist/di/module-registry.d.ts +17 -0
  7. package/dist/di/module-registry.d.ts.map +1 -1
  8. package/dist/events/decorators.d.ts +52 -0
  9. package/dist/events/decorators.d.ts.map +1 -0
  10. package/dist/events/event-module.d.ts +97 -0
  11. package/dist/events/event-module.d.ts.map +1 -0
  12. package/dist/events/index.d.ts +5 -0
  13. package/dist/events/index.d.ts.map +1 -0
  14. package/dist/events/service.d.ts +76 -0
  15. package/dist/events/service.d.ts.map +1 -0
  16. package/dist/events/types.d.ts +184 -0
  17. package/dist/events/types.d.ts.map +1 -0
  18. package/dist/index.d.ts +5 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1511 -11
  21. package/dist/security/filter.d.ts +23 -0
  22. package/dist/security/filter.d.ts.map +1 -1
  23. package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
  24. package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
  25. package/dist/security/guards/builtin/index.d.ts +3 -0
  26. package/dist/security/guards/builtin/index.d.ts.map +1 -0
  27. package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
  28. package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
  29. package/dist/security/guards/decorators.d.ts +50 -0
  30. package/dist/security/guards/decorators.d.ts.map +1 -0
  31. package/dist/security/guards/execution-context.d.ts +56 -0
  32. package/dist/security/guards/execution-context.d.ts.map +1 -0
  33. package/dist/security/guards/guard-registry.d.ts +67 -0
  34. package/dist/security/guards/guard-registry.d.ts.map +1 -0
  35. package/dist/security/guards/index.d.ts +7 -0
  36. package/dist/security/guards/index.d.ts.map +1 -0
  37. package/dist/security/guards/reflector.d.ts +57 -0
  38. package/dist/security/guards/reflector.d.ts.map +1 -0
  39. package/dist/security/guards/types.d.ts +126 -0
  40. package/dist/security/guards/types.d.ts.map +1 -0
  41. package/dist/security/index.d.ts +1 -0
  42. package/dist/security/index.d.ts.map +1 -1
  43. package/dist/security/security-module.d.ts +20 -0
  44. package/dist/security/security-module.d.ts.map +1 -1
  45. package/dist/validation/class-validator.d.ts +108 -0
  46. package/dist/validation/class-validator.d.ts.map +1 -0
  47. package/dist/validation/custom-validator.d.ts +130 -0
  48. package/dist/validation/custom-validator.d.ts.map +1 -0
  49. package/dist/validation/errors.d.ts +22 -2
  50. package/dist/validation/errors.d.ts.map +1 -1
  51. package/dist/validation/index.d.ts +7 -1
  52. package/dist/validation/index.d.ts.map +1 -1
  53. package/dist/validation/rules/array.d.ts +33 -0
  54. package/dist/validation/rules/array.d.ts.map +1 -0
  55. package/dist/validation/rules/common.d.ts +90 -0
  56. package/dist/validation/rules/common.d.ts.map +1 -0
  57. package/dist/validation/rules/conditional.d.ts +30 -0
  58. package/dist/validation/rules/conditional.d.ts.map +1 -0
  59. package/dist/validation/rules/index.d.ts +5 -0
  60. package/dist/validation/rules/index.d.ts.map +1 -0
  61. package/dist/validation/rules/object.d.ts +30 -0
  62. package/dist/validation/rules/object.d.ts.map +1 -0
  63. package/dist/validation/types.d.ts +52 -1
  64. package/dist/validation/types.d.ts.map +1 -1
  65. package/docs/events.md +494 -0
  66. package/docs/guards.md +376 -0
  67. package/docs/guide.md +309 -1
  68. package/docs/request-lifecycle.md +444 -0
  69. package/docs/validation.md +407 -0
  70. package/docs/zh/events.md +494 -0
  71. package/docs/zh/guards.md +376 -0
  72. package/docs/zh/guide.md +309 -1
  73. package/docs/zh/request-lifecycle.md +444 -0
  74. package/docs/zh/validation.md +407 -0
  75. package/package.json +1 -1
  76. package/src/di/decorators.ts +46 -0
  77. package/src/di/index.ts +10 -1
  78. package/src/di/module-registry.ts +39 -0
  79. package/src/events/decorators.ts +103 -0
  80. package/src/events/event-module.ts +272 -0
  81. package/src/events/index.ts +32 -0
  82. package/src/events/service.ts +352 -0
  83. package/src/events/types.ts +223 -0
  84. package/src/index.ts +133 -1
  85. package/src/security/filter.ts +88 -8
  86. package/src/security/guards/builtin/auth-guard.ts +68 -0
  87. package/src/security/guards/builtin/index.ts +3 -0
  88. package/src/security/guards/builtin/roles-guard.ts +165 -0
  89. package/src/security/guards/decorators.ts +124 -0
  90. package/src/security/guards/execution-context.ts +152 -0
  91. package/src/security/guards/guard-registry.ts +164 -0
  92. package/src/security/guards/index.ts +7 -0
  93. package/src/security/guards/reflector.ts +99 -0
  94. package/src/security/guards/types.ts +144 -0
  95. package/src/security/index.ts +1 -0
  96. package/src/security/security-module.ts +72 -2
  97. package/src/validation/class-validator.ts +322 -0
  98. package/src/validation/custom-validator.ts +289 -0
  99. package/src/validation/errors.ts +50 -2
  100. package/src/validation/index.ts +103 -1
  101. package/src/validation/rules/array.ts +118 -0
  102. package/src/validation/rules/common.ts +286 -0
  103. package/src/validation/rules/conditional.ts +52 -0
  104. package/src/validation/rules/index.ts +51 -0
  105. package/src/validation/rules/object.ts +86 -0
  106. package/src/validation/types.ts +61 -1
  107. package/tests/di/global-module.test.ts +487 -0
  108. package/tests/events/event-decorators.test.ts +173 -0
  109. package/tests/events/event-emitter.test.ts +373 -0
  110. package/tests/events/event-module.test.ts +373 -0
  111. package/tests/security/guards/guards-integration.test.ts +371 -0
  112. package/tests/security/guards/guards.test.ts +775 -0
  113. package/tests/security/security-module.test.ts +2 -2
  114. package/tests/validation/class-validator.test.ts +349 -0
  115. package/tests/validation/custom-validator.test.ts +335 -0
  116. package/tests/validation/rules.test.ts +543 -0
@@ -0,0 +1,373 @@
1
+ import { describe, expect, test, beforeEach, mock } from 'bun:test';
2
+ import 'reflect-metadata';
3
+ import { EventModule, EventListenerScanner } from '../../src/events/event-module';
4
+ import { EventEmitterService } from '../../src/events/service';
5
+ import { OnEvent, getOnEventMetadata, isEventListenerClass } from '../../src/events/decorators';
6
+ import { Container } from '../../src/di/container';
7
+ import { Injectable } from '../../src/di/decorators';
8
+ import { MODULE_METADATA_KEY } from '../../src/di/module';
9
+ import { ModuleRegistry } from '../../src/di/module-registry';
10
+ import {
11
+ EVENT_EMITTER_TOKEN,
12
+ EVENT_OPTIONS_TOKEN,
13
+ type EventEmitter,
14
+ } from '../../src/events/types';
15
+
16
+ describe('EventModule', () => {
17
+ beforeEach(() => {
18
+ // 清除模块元数据
19
+ Reflect.deleteMetadata(MODULE_METADATA_KEY, EventModule);
20
+ });
21
+
22
+ describe('forRoot()', () => {
23
+ test('should register event emitter service', () => {
24
+ EventModule.forRoot();
25
+
26
+ const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
27
+ expect(metadata.providers).toBeDefined();
28
+ expect(metadata.providers.length).toBeGreaterThanOrEqual(2);
29
+
30
+ const emitterProvider = metadata.providers.find(
31
+ (p: any) => p.provide === EVENT_EMITTER_TOKEN,
32
+ );
33
+ expect(emitterProvider).toBeDefined();
34
+ expect(emitterProvider.useValue).toBeInstanceOf(EventEmitterService);
35
+ });
36
+
37
+ test('should register options', () => {
38
+ const options = { wildcard: true, maxListeners: 50 };
39
+ EventModule.forRoot(options);
40
+
41
+ const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
42
+ const optionsProvider = metadata.providers.find(
43
+ (p: any) => p.provide === EVENT_OPTIONS_TOKEN,
44
+ );
45
+
46
+ expect(optionsProvider).toBeDefined();
47
+ expect(optionsProvider.useValue).toEqual(options);
48
+ });
49
+
50
+ test('should export event emitter token', () => {
51
+ EventModule.forRoot();
52
+
53
+ const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
54
+ expect(metadata.exports).toContain(EVENT_EMITTER_TOKEN);
55
+ });
56
+
57
+ test('should apply options to event emitter', () => {
58
+ EventModule.forRoot({ wildcard: true, globalPrefix: 'test' });
59
+
60
+ const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
61
+ const emitterProvider = metadata.providers.find(
62
+ (p: any) => p.provide === EVENT_EMITTER_TOKEN,
63
+ );
64
+
65
+ // EventEmitterService 内部存储了选项
66
+ expect(emitterProvider.useValue).toBeInstanceOf(EventEmitterService);
67
+ });
68
+ });
69
+
70
+ describe('getEventEmitter()', () => {
71
+ test('should return event emitter from container', () => {
72
+ EventModule.forRoot();
73
+
74
+ const container = new Container();
75
+ const emitterService = new EventEmitterService();
76
+ // 使用 registerInstance 方法注册实例(对应 useValue)
77
+ container.registerInstance(EVENT_EMITTER_TOKEN, emitterService);
78
+
79
+ const result = EventModule.getEventEmitter(container);
80
+ expect(result).toBe(emitterService);
81
+ });
82
+
83
+ test('should return undefined when not registered', () => {
84
+ const container = new Container();
85
+ // getEventEmitter 现在会捕获错误并返回 undefined
86
+ const result = EventModule.getEventEmitter(container);
87
+ expect(result).toBeUndefined();
88
+ });
89
+ });
90
+ });
91
+
92
+ describe('EventListenerScanner', () => {
93
+ let container: Container;
94
+ let eventEmitter: EventEmitterService;
95
+ let scanner: EventListenerScanner;
96
+
97
+ beforeEach(() => {
98
+ container = new Container();
99
+ eventEmitter = new EventEmitterService();
100
+ scanner = new EventListenerScanner(eventEmitter, container);
101
+ });
102
+
103
+ test('should scan and register event listeners', () => {
104
+ const handler = mock(() => {});
105
+
106
+ @Injectable()
107
+ class TestService {
108
+ @OnEvent('test.event')
109
+ public handleEvent(payload: unknown): void {
110
+ handler(payload);
111
+ }
112
+ }
113
+
114
+ // 注册服务到容器
115
+ container.register(TestService, { useClass: TestService });
116
+
117
+ // 扫描并注册监听器
118
+ scanner.scanAndRegister([TestService]);
119
+
120
+ // 触发事件
121
+ eventEmitter.emit('test.event', { data: 'test' });
122
+
123
+ expect(handler).toHaveBeenCalledTimes(1);
124
+ expect(handler).toHaveBeenCalledWith({ data: 'test' });
125
+ });
126
+
127
+ test('should register multiple listeners from same class', () => {
128
+ const handler1 = mock(() => {});
129
+ const handler2 = mock(() => {});
130
+
131
+ @Injectable()
132
+ class TestService {
133
+ @OnEvent('event1')
134
+ public handleEvent1(payload: unknown): void {
135
+ handler1(payload);
136
+ }
137
+
138
+ @OnEvent('event2')
139
+ public handleEvent2(payload: unknown): void {
140
+ handler2(payload);
141
+ }
142
+ }
143
+
144
+ container.register(TestService, { useClass: TestService });
145
+ scanner.scanAndRegister([TestService]);
146
+
147
+ eventEmitter.emit('event1', 'payload1');
148
+ eventEmitter.emit('event2', 'payload2');
149
+
150
+ expect(handler1).toHaveBeenCalledWith('payload1');
151
+ expect(handler2).toHaveBeenCalledWith('payload2');
152
+ });
153
+
154
+ test('should respect listener priority', () => {
155
+ const order: number[] = [];
156
+
157
+ @Injectable()
158
+ class TestService {
159
+ @OnEvent('test.event', { priority: 1 })
160
+ public lowPriority(): void {
161
+ order.push(1);
162
+ }
163
+
164
+ @OnEvent('test.event', { priority: 10 })
165
+ public highPriority(): void {
166
+ order.push(10);
167
+ }
168
+ }
169
+
170
+ container.register(TestService, { useClass: TestService });
171
+ scanner.scanAndRegister([TestService]);
172
+
173
+ eventEmitter.emit('test.event', null);
174
+
175
+ expect(order).toEqual([10, 1]);
176
+ });
177
+
178
+ test('should skip non-listener classes', () => {
179
+ @Injectable()
180
+ class RegularService {
181
+ public doSomething(): void {}
182
+ }
183
+
184
+ container.register(RegularService, { useClass: RegularService });
185
+
186
+ // 不应该抛出错误
187
+ expect(() => scanner.scanAndRegister([RegularService])).not.toThrow();
188
+ });
189
+
190
+ test('should handle unregistered listener class gracefully', () => {
191
+ @Injectable()
192
+ class UnregisteredService {
193
+ @OnEvent('test.event')
194
+ public handleEvent(): void {}
195
+ }
196
+
197
+ // 容器会尝试解析未注册的类,这里会自动创建实例(无参数构造函数)
198
+ // 所以不会抛出错误,也不会触发警告
199
+ expect(() => scanner.scanAndRegister([UnregisteredService])).not.toThrow();
200
+ });
201
+ });
202
+
203
+ describe('EventModule integration', () => {
204
+ beforeEach(() => {
205
+ Reflect.deleteMetadata(MODULE_METADATA_KEY, EventModule);
206
+ });
207
+
208
+ test('should work with initializeListeners via ModuleRegistry', () => {
209
+ const handler = mock(() => {});
210
+
211
+ @Injectable()
212
+ class NotificationService {
213
+ @OnEvent('user.created')
214
+ public sendWelcomeEmail(payload: { email: string }): void {
215
+ handler(payload);
216
+ }
217
+ }
218
+
219
+ // 配置模块
220
+ EventModule.forRoot();
221
+
222
+ // 模拟模块注册流程
223
+ const registry = ModuleRegistry.getInstance();
224
+ const rootContainer = new Container();
225
+
226
+ // 手动创建 EventModule 的模块引用
227
+ const eventModuleContainer = new Container({ parent: rootContainer });
228
+ const emitter = new EventEmitterService();
229
+ eventModuleContainer.registerInstance(EVENT_EMITTER_TOKEN, emitter);
230
+
231
+ // 注册 NotificationService 到同一个容器
232
+ eventModuleContainer.register(NotificationService, { implementation: NotificationService });
233
+
234
+ // 模拟 ModuleRegistry 的 getModuleRef 返回
235
+ const originalGetModuleRef = registry.getModuleRef.bind(registry);
236
+ registry.getModuleRef = (moduleClass: any) => {
237
+ if (moduleClass === EventModule) {
238
+ return {
239
+ moduleClass: EventModule,
240
+ container: eventModuleContainer,
241
+ metadata: { providers: [], exports: [], imports: [], controllers: [] },
242
+ controllersRegistered: false,
243
+ attachedParents: new Set(),
244
+ extensions: [],
245
+ middlewares: [],
246
+ isGlobal: false,
247
+ } as any;
248
+ }
249
+ return originalGetModuleRef(moduleClass);
250
+ };
251
+
252
+ // 初始化监听器
253
+ EventModule.initializeListeners(eventModuleContainer, [NotificationService]);
254
+
255
+ // 发布事件
256
+ emitter.emit('user.created', { email: 'test@example.com' });
257
+
258
+ expect(handler).toHaveBeenCalledWith({ email: 'test@example.com' });
259
+
260
+ // 恢复原始方法
261
+ registry.getModuleRef = originalGetModuleRef;
262
+ });
263
+
264
+ test('should support async event handlers', async () => {
265
+ const results: string[] = [];
266
+
267
+ @Injectable()
268
+ class AsyncService {
269
+ @OnEvent('async.event', { async: true })
270
+ public async handleAsync(payload: string): Promise<void> {
271
+ await new Promise((resolve) => setTimeout(resolve, 10));
272
+ results.push(payload);
273
+ }
274
+ }
275
+
276
+ const container = new Container();
277
+ const emitter = new EventEmitterService();
278
+ container.register(EVENT_EMITTER_TOKEN, { useValue: emitter });
279
+ container.register(AsyncService, { useClass: AsyncService });
280
+
281
+ const scanner = new EventListenerScanner(emitter, container);
282
+ scanner.scanAndRegister([AsyncService]);
283
+
284
+ await emitter.emitAsync('async.event', 'async-payload');
285
+
286
+ expect(results).toContain('async-payload');
287
+ });
288
+
289
+ test('should handle Symbol events with decorators', () => {
290
+ const USER_UPDATED = Symbol('user.updated');
291
+ const handler = mock(() => {});
292
+
293
+ @Injectable()
294
+ class UserEventService {
295
+ @OnEvent(USER_UPDATED)
296
+ public handleUserUpdated(payload: unknown): void {
297
+ handler(payload);
298
+ }
299
+ }
300
+
301
+ const container = new Container();
302
+ const emitter = new EventEmitterService();
303
+ container.register(EVENT_EMITTER_TOKEN, { useValue: emitter });
304
+ container.register(UserEventService, { useClass: UserEventService });
305
+
306
+ const scanner = new EventListenerScanner(emitter, container);
307
+ scanner.scanAndRegister([UserEventService]);
308
+
309
+ emitter.emit(USER_UPDATED, { userId: '123' });
310
+
311
+ expect(handler).toHaveBeenCalledWith({ userId: '123' });
312
+ });
313
+ });
314
+
315
+ describe('EventModule with registerListeners', () => {
316
+ beforeEach(() => {
317
+ Reflect.deleteMetadata(MODULE_METADATA_KEY, EventModule);
318
+ ModuleRegistry.getInstance().clear();
319
+ });
320
+
321
+ test('should collect listeners via registerListeners', () => {
322
+ const handler = mock(() => {});
323
+
324
+ @Injectable()
325
+ class CollectedService {
326
+ @OnEvent('collected.event')
327
+ public handleEvent(payload: unknown): void {
328
+ handler(payload);
329
+ }
330
+ }
331
+
332
+ EventModule.forRoot();
333
+ EventModule.registerListeners([CollectedService]);
334
+
335
+ // 模拟模块注册流程
336
+ const registry = ModuleRegistry.getInstance();
337
+ const rootContainer = new Container();
338
+
339
+ // 手动创建 EventModule 的模块引用
340
+ const eventModuleContainer = new Container({ parent: rootContainer });
341
+ const emitter = new EventEmitterService();
342
+ eventModuleContainer.registerInstance(EVENT_EMITTER_TOKEN, emitter);
343
+ eventModuleContainer.register(CollectedService, { implementation: CollectedService });
344
+
345
+ // 模拟 ModuleRegistry 的 getModuleRef 返回
346
+ const originalGetModuleRef = registry.getModuleRef.bind(registry);
347
+ registry.getModuleRef = (moduleClass: any) => {
348
+ if (moduleClass === EventModule) {
349
+ return {
350
+ moduleClass: EventModule,
351
+ container: eventModuleContainer,
352
+ metadata: { providers: [], exports: [], imports: [], controllers: [] },
353
+ controllersRegistered: false,
354
+ attachedParents: new Set(),
355
+ extensions: [],
356
+ middlewares: [],
357
+ isGlobal: false,
358
+ } as any;
359
+ }
360
+ return originalGetModuleRef(moduleClass);
361
+ };
362
+
363
+ // initializeListeners 会包含通过 registerListeners 注册的类
364
+ EventModule.initializeListeners(eventModuleContainer);
365
+
366
+ emitter.emit('collected.event', 'test');
367
+
368
+ expect(handler).toHaveBeenCalledWith('test');
369
+
370
+ // 恢复原始方法
371
+ registry.getModuleRef = originalGetModuleRef;
372
+ });
373
+ });