@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 { EventEmitterService } from '../../src/events/service';
3
+ import type { EventEmitter, EventModuleOptions } from '../../src/events/types';
4
+
5
+ describe('EventEmitterService', () => {
6
+ let emitter: EventEmitter;
7
+
8
+ beforeEach(() => {
9
+ emitter = new EventEmitterService();
10
+ });
11
+
12
+ describe('on() and emit()', () => {
13
+ test('should register and trigger listener', () => {
14
+ const listener = mock(() => {});
15
+ emitter.on('test.event', listener);
16
+ emitter.emit('test.event', { data: 'hello' });
17
+
18
+ expect(listener).toHaveBeenCalledTimes(1);
19
+ expect(listener).toHaveBeenCalledWith({ data: 'hello' });
20
+ });
21
+
22
+ test('should support multiple listeners for same event', () => {
23
+ const listener1 = mock(() => {});
24
+ const listener2 = mock(() => {});
25
+
26
+ emitter.on('test.event', listener1);
27
+ emitter.on('test.event', listener2);
28
+ emitter.emit('test.event', 'payload');
29
+
30
+ expect(listener1).toHaveBeenCalledTimes(1);
31
+ expect(listener2).toHaveBeenCalledTimes(1);
32
+ });
33
+
34
+ test('should not trigger listener for different event', () => {
35
+ const listener = mock(() => {});
36
+ emitter.on('test.event1', listener);
37
+ emitter.emit('test.event2', 'payload');
38
+
39
+ expect(listener).not.toHaveBeenCalled();
40
+ });
41
+
42
+ test('should support Symbol as event name', () => {
43
+ const eventSymbol = Symbol('test.event');
44
+ const listener = mock(() => {});
45
+
46
+ emitter.on(eventSymbol, listener);
47
+ emitter.emit(eventSymbol, { key: 'value' });
48
+
49
+ expect(listener).toHaveBeenCalledTimes(1);
50
+ expect(listener).toHaveBeenCalledWith({ key: 'value' });
51
+ });
52
+
53
+ test('should return unsubscribe function', () => {
54
+ const listener = mock(() => {});
55
+ const unsubscribe = emitter.on('test.event', listener);
56
+
57
+ emitter.emit('test.event', 'first');
58
+ expect(listener).toHaveBeenCalledTimes(1);
59
+
60
+ unsubscribe();
61
+ emitter.emit('test.event', 'second');
62
+ expect(listener).toHaveBeenCalledTimes(1);
63
+ });
64
+ });
65
+
66
+ describe('once()', () => {
67
+ test('should only trigger listener once', () => {
68
+ const listener = mock(() => {});
69
+ emitter.once('test.event', listener);
70
+
71
+ emitter.emit('test.event', 'first');
72
+ emitter.emit('test.event', 'second');
73
+
74
+ expect(listener).toHaveBeenCalledTimes(1);
75
+ expect(listener).toHaveBeenCalledWith('first');
76
+ });
77
+
78
+ test('should return unsubscribe function', () => {
79
+ const listener = mock(() => {});
80
+ const unsubscribe = emitter.once('test.event', listener);
81
+
82
+ unsubscribe();
83
+ emitter.emit('test.event', 'payload');
84
+
85
+ expect(listener).not.toHaveBeenCalled();
86
+ });
87
+ });
88
+
89
+ describe('off()', () => {
90
+ test('should remove specific listener', () => {
91
+ const listener1 = mock(() => {});
92
+ const listener2 = mock(() => {});
93
+
94
+ emitter.on('test.event', listener1);
95
+ emitter.on('test.event', listener2);
96
+ emitter.off('test.event', listener1);
97
+ emitter.emit('test.event', 'payload');
98
+
99
+ expect(listener1).not.toHaveBeenCalled();
100
+ expect(listener2).toHaveBeenCalledTimes(1);
101
+ });
102
+
103
+ test('should do nothing if listener not found', () => {
104
+ const listener = mock(() => {});
105
+ emitter.off('test.event', listener); // 不抛出错误
106
+ });
107
+ });
108
+
109
+ describe('removeAllListeners()', () => {
110
+ test('should remove all listeners for specific event', () => {
111
+ const listener1 = mock(() => {});
112
+ const listener2 = mock(() => {});
113
+
114
+ emitter.on('event1', listener1);
115
+ emitter.on('event2', listener2);
116
+ emitter.removeAllListeners('event1');
117
+
118
+ emitter.emit('event1', 'payload');
119
+ emitter.emit('event2', 'payload');
120
+
121
+ expect(listener1).not.toHaveBeenCalled();
122
+ expect(listener2).toHaveBeenCalledTimes(1);
123
+ });
124
+
125
+ test('should remove all listeners when no event specified', () => {
126
+ const listener1 = mock(() => {});
127
+ const listener2 = mock(() => {});
128
+
129
+ emitter.on('event1', listener1);
130
+ emitter.on('event2', listener2);
131
+ emitter.removeAllListeners();
132
+
133
+ emitter.emit('event1', 'payload');
134
+ emitter.emit('event2', 'payload');
135
+
136
+ expect(listener1).not.toHaveBeenCalled();
137
+ expect(listener2).not.toHaveBeenCalled();
138
+ });
139
+ });
140
+
141
+ describe('listenerCount()', () => {
142
+ test('should return correct listener count', () => {
143
+ expect(emitter.listenerCount('test.event')).toBe(0);
144
+
145
+ emitter.on('test.event', () => {});
146
+ expect(emitter.listenerCount('test.event')).toBe(1);
147
+
148
+ emitter.on('test.event', () => {});
149
+ expect(emitter.listenerCount('test.event')).toBe(2);
150
+ });
151
+ });
152
+
153
+ describe('eventNames()', () => {
154
+ test('should return all registered event names', () => {
155
+ const symbol = Symbol('symbol.event');
156
+ emitter.on('string.event', () => {});
157
+ emitter.on(symbol, () => {});
158
+
159
+ const names = emitter.eventNames();
160
+ expect(names).toContain('string.event');
161
+ expect(names).toContain(symbol);
162
+ expect(names.length).toBe(2);
163
+ });
164
+
165
+ test('should return empty array when no listeners', () => {
166
+ expect(emitter.eventNames()).toEqual([]);
167
+ });
168
+ });
169
+
170
+ describe('priority', () => {
171
+ test('should execute listeners in priority order (high to low)', () => {
172
+ const order: number[] = [];
173
+
174
+ emitter.on('test.event', () => order.push(1), { priority: 1 });
175
+ emitter.on('test.event', () => order.push(3), { priority: 3 });
176
+ emitter.on('test.event', () => order.push(2), { priority: 2 });
177
+
178
+ emitter.emit('test.event', null);
179
+
180
+ expect(order).toEqual([3, 2, 1]);
181
+ });
182
+
183
+ test('should use default priority 0 when not specified', () => {
184
+ const order: number[] = [];
185
+
186
+ emitter.on('test.event', () => order.push(1)); // priority: 0
187
+ emitter.on('test.event', () => order.push(2), { priority: 1 });
188
+ emitter.on('test.event', () => order.push(3), { priority: -1 });
189
+
190
+ emitter.emit('test.event', null);
191
+
192
+ expect(order).toEqual([2, 1, 3]);
193
+ });
194
+ });
195
+
196
+ describe('emitAsync()', () => {
197
+ test('should wait for all async listeners to complete', async () => {
198
+ const results: number[] = [];
199
+
200
+ emitter.on('test.event', async () => {
201
+ await new Promise((resolve) => setTimeout(resolve, 10));
202
+ results.push(1);
203
+ });
204
+
205
+ emitter.on('test.event', async () => {
206
+ await new Promise((resolve) => setTimeout(resolve, 5));
207
+ results.push(2);
208
+ });
209
+
210
+ await emitter.emitAsync('test.event', null);
211
+
212
+ expect(results.length).toBe(2);
213
+ expect(results).toContain(1);
214
+ expect(results).toContain(2);
215
+ });
216
+
217
+ test('should handle sync listeners in emitAsync', async () => {
218
+ const listener = mock(() => {});
219
+ emitter.on('test.event', listener);
220
+
221
+ await emitter.emitAsync('test.event', 'payload');
222
+
223
+ expect(listener).toHaveBeenCalledTimes(1);
224
+ });
225
+
226
+ test('should remove once listeners after emitAsync', async () => {
227
+ const listener = mock(() => {});
228
+ emitter.once('test.event', listener);
229
+
230
+ await emitter.emitAsync('test.event', 'first');
231
+ await emitter.emitAsync('test.event', 'second');
232
+
233
+ expect(listener).toHaveBeenCalledTimes(1);
234
+ });
235
+ });
236
+
237
+ describe('error handling', () => {
238
+ test('should continue execution when listener throws sync error', () => {
239
+ const consoleSpy = mock(() => {});
240
+ const originalError = console.error;
241
+ console.error = consoleSpy;
242
+
243
+ const listener1 = mock(() => {
244
+ throw new Error('Test error');
245
+ });
246
+ const listener2 = mock(() => {});
247
+
248
+ emitter.on('test.event', listener1);
249
+ emitter.on('test.event', listener2);
250
+ emitter.emit('test.event', 'payload');
251
+
252
+ expect(listener1).toHaveBeenCalledTimes(1);
253
+ expect(listener2).toHaveBeenCalledTimes(1);
254
+ expect(consoleSpy).toHaveBeenCalled();
255
+
256
+ console.error = originalError;
257
+ });
258
+
259
+ test('should use custom error handler when provided', () => {
260
+ const errorHandler = mock(() => {});
261
+ const emitterWithErrorHandler = new EventEmitterService({
262
+ onError: errorHandler,
263
+ });
264
+
265
+ emitterWithErrorHandler.on('test.event', () => {
266
+ throw new Error('Custom error');
267
+ });
268
+ emitterWithErrorHandler.emit('test.event', 'payload');
269
+
270
+ expect(errorHandler).toHaveBeenCalledTimes(1);
271
+ expect(errorHandler.mock.calls[0]?.[0]).toBeInstanceOf(Error);
272
+ });
273
+ });
274
+
275
+ describe('maxListeners warning', () => {
276
+ test('should warn when exceeding maxListeners', () => {
277
+ const consoleSpy = mock(() => {});
278
+ const originalWarn = console.warn;
279
+ console.warn = consoleSpy;
280
+
281
+ const emitterWithLimit = new EventEmitterService({ maxListeners: 2 });
282
+
283
+ emitterWithLimit.on('test.event', () => {});
284
+ emitterWithLimit.on('test.event', () => {});
285
+ emitterWithLimit.on('test.event', () => {}); // 超过限制
286
+
287
+ expect(consoleSpy).toHaveBeenCalled();
288
+ expect(consoleSpy.mock.calls[0]?.[0]).toContain('Max listeners');
289
+
290
+ console.warn = originalWarn;
291
+ });
292
+ });
293
+
294
+ describe('globalPrefix', () => {
295
+ test('should add global prefix to event names', () => {
296
+ const emitterWithPrefix = new EventEmitterService({
297
+ globalPrefix: 'app',
298
+ });
299
+ const listener = mock(() => {});
300
+
301
+ emitterWithPrefix.on('user.created', listener);
302
+ emitterWithPrefix.emit('user.created', 'payload');
303
+
304
+ expect(listener).toHaveBeenCalledTimes(1);
305
+ });
306
+ });
307
+ });
308
+
309
+ describe('EventEmitterService wildcard', () => {
310
+ let emitter: EventEmitter;
311
+
312
+ beforeEach(() => {
313
+ emitter = new EventEmitterService({ wildcard: true });
314
+ });
315
+
316
+ describe('single wildcard (*)', () => {
317
+ test('should match single segment', () => {
318
+ const listener = mock(() => {});
319
+ emitter.on('user.*', listener);
320
+
321
+ emitter.emit('user.created', 'payload1');
322
+ emitter.emit('user.updated', 'payload2');
323
+
324
+ expect(listener).toHaveBeenCalledTimes(2);
325
+ });
326
+
327
+ test('should not match multiple segments', () => {
328
+ const listener = mock(() => {});
329
+ emitter.on('user.*', listener);
330
+
331
+ emitter.emit('user.profile.updated', 'payload');
332
+
333
+ expect(listener).not.toHaveBeenCalled();
334
+ });
335
+ });
336
+
337
+ describe('double wildcard (**)', () => {
338
+ test('should match any number of segments', () => {
339
+ const listener = mock(() => {});
340
+ emitter.on('user.**', listener);
341
+
342
+ emitter.emit('user.created', 'payload1');
343
+ emitter.emit('user.profile.updated', 'payload2');
344
+ emitter.emit('user.settings.privacy.changed', 'payload3');
345
+
346
+ expect(listener).toHaveBeenCalledTimes(3);
347
+ });
348
+
349
+ test('should match at end of pattern', () => {
350
+ const listener = mock(() => {});
351
+ emitter.on('app.**', listener);
352
+
353
+ emitter.emit('app.start', 'payload');
354
+
355
+ expect(listener).toHaveBeenCalledTimes(1);
356
+ });
357
+ });
358
+
359
+ describe('mixed patterns', () => {
360
+ test('should handle exact match alongside wildcards', () => {
361
+ const exactListener = mock(() => {});
362
+ const wildcardListener = mock(() => {});
363
+
364
+ emitter.on('user.created', exactListener);
365
+ emitter.on('user.*', wildcardListener);
366
+
367
+ emitter.emit('user.created', 'payload');
368
+
369
+ expect(exactListener).toHaveBeenCalledTimes(1);
370
+ expect(wildcardListener).toHaveBeenCalledTimes(1);
371
+ });
372
+ });
373
+ });