@dangao/bun-server 1.8.0 → 1.8.1

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 (45) hide show
  1. package/package.json +1 -1
  2. package/tests/auth/auth-decorators.test.ts +241 -0
  3. package/tests/auth/oauth2-service.test.ts +318 -0
  4. package/tests/cache/cache-decorators-extended.test.ts +272 -0
  5. package/tests/cache/cache-interceptors.test.ts +534 -0
  6. package/tests/cache/cache-service-proxy.test.ts +246 -0
  7. package/tests/cache/memory-cache-store.test.ts +155 -0
  8. package/tests/cache/redis-cache-store.test.ts +199 -0
  9. package/tests/config/config-center-integration.test.ts +334 -0
  10. package/tests/config/config-module-extended.test.ts +165 -0
  11. package/tests/controller/param-binder.test.ts +333 -0
  12. package/tests/error/error-handler.test.ts +166 -57
  13. package/tests/error/i18n-extended.test.ts +105 -0
  14. package/tests/events/event-listener-scanner.test.ts +114 -0
  15. package/tests/events/event-module.test.ts +133 -302
  16. package/tests/extensions/logger-module.test.ts +158 -0
  17. package/tests/files/file-storage.test.ts +136 -0
  18. package/tests/interceptor/base-interceptor.test.ts +605 -0
  19. package/tests/interceptor/builtin/cache-interceptor.test.ts +233 -86
  20. package/tests/interceptor/builtin/log-interceptor.test.ts +469 -0
  21. package/tests/interceptor/builtin/permission-interceptor.test.ts +219 -120
  22. package/tests/interceptor/interceptor-chain.test.ts +241 -189
  23. package/tests/interceptor/interceptor-metadata.test.ts +221 -0
  24. package/tests/microservice/circuit-breaker.test.ts +221 -0
  25. package/tests/microservice/service-client-decorators.test.ts +86 -0
  26. package/tests/microservice/service-client-interceptors.test.ts +274 -0
  27. package/tests/microservice/service-registry-decorators.test.ts +147 -0
  28. package/tests/microservice/tracer.test.ts +213 -0
  29. package/tests/microservice/tracing-collectors.test.ts +168 -0
  30. package/tests/middleware/builtin/middleware-builtin-extended.test.ts +237 -0
  31. package/tests/middleware/builtin/rate-limit.test.ts +257 -0
  32. package/tests/middleware/middleware-decorators.test.ts +222 -0
  33. package/tests/middleware/middleware-pipeline.test.ts +160 -0
  34. package/tests/queue/queue-decorators.test.ts +139 -0
  35. package/tests/queue/queue-service.test.ts +191 -0
  36. package/tests/request/body-parser-extended.test.ts +291 -0
  37. package/tests/request/request-wrapper.test.ts +319 -0
  38. package/tests/router/router-decorators.test.ts +260 -0
  39. package/tests/router/router-extended.test.ts +298 -0
  40. package/tests/security/guards/reflector.test.ts +188 -0
  41. package/tests/security/security-filter.test.ts +182 -0
  42. package/tests/security/security-module-extended.test.ts +133 -0
  43. package/tests/session/memory-session-store.test.ts +172 -0
  44. package/tests/session/session-decorators.test.ts +163 -0
  45. package/tests/swagger/ui.test.ts +212 -0
@@ -1,199 +1,251 @@
1
+ import { describe, expect, test, beforeEach } from 'bun:test';
1
2
  import 'reflect-metadata';
2
- import { describe, expect, test } from 'bun:test';
3
- import { InterceptorChain } from '../../src/interceptor';
4
- import type { Interceptor } from '../../src/interceptor';
3
+
4
+ import { InterceptorChain } from '../../src/interceptor/interceptor-chain';
5
+ import type { Interceptor } from '../../src/interceptor/types';
5
6
  import { Container } from '../../src/di/container';
6
7
  import { Context } from '../../src/core/context';
7
8
 
8
9
  describe('InterceptorChain', () => {
9
- test('should execute method directly when no interceptors', async () => {
10
- const container = new Container();
11
- const target = {};
12
- const propertyKey = 'testMethod';
13
- const originalMethod = () => 'result';
14
-
15
- const result = await InterceptorChain.execute(
16
- [],
17
- target,
18
- propertyKey,
19
- originalMethod,
20
- [],
21
- container,
22
- );
23
-
24
- expect(result).toBe('result');
25
- });
26
-
27
- test('should execute single interceptor', async () => {
28
- const container = new Container();
29
- const target = {};
30
- const propertyKey = 'testMethod';
31
- const originalMethod = () => 'result';
32
- let executed = false;
33
-
34
- const interceptor: Interceptor = {
35
- async execute(target, propertyKey, originalMethod, args, container, context) {
36
- executed = true;
37
- return await Promise.resolve(originalMethod.apply(target, args));
38
- },
39
- };
40
-
41
- const result = await InterceptorChain.execute(
42
- [interceptor],
43
- target,
44
- propertyKey,
45
- originalMethod,
46
- [],
47
- container,
48
- );
49
-
50
- expect(executed).toBe(true);
51
- expect(result).toBe('result');
52
- });
53
-
54
- test('should execute multiple interceptors in order', async () => {
55
- const container = new Container();
56
- const target = {};
57
- const propertyKey = 'testMethod';
58
- const originalMethod = () => 'result';
59
- const executionOrder: string[] = [];
60
-
61
- const interceptor1: Interceptor = {
62
- async execute(target, propertyKey, originalMethod, args, container, context) {
63
- executionOrder.push('interceptor1-before');
64
- const result = await Promise.resolve(originalMethod.apply(target, args));
65
- executionOrder.push('interceptor1-after');
66
- return result;
67
- },
68
- };
69
-
70
- const interceptor2: Interceptor = {
71
- async execute(target, propertyKey, originalMethod, args, container, context) {
72
- executionOrder.push('interceptor2-before');
73
- const result = await Promise.resolve(originalMethod.apply(target, args));
74
- executionOrder.push('interceptor2-after');
75
- return result;
76
- },
77
- };
78
-
79
- const result = await InterceptorChain.execute(
80
- [interceptor1, interceptor2],
81
- target,
82
- propertyKey,
83
- originalMethod,
84
- [],
85
- container,
86
- );
87
-
88
- expect(result).toBe('result');
89
- // 执行顺序:interceptor1 -> interceptor2 -> method -> interceptor2 -> interceptor1
90
- expect(executionOrder).toEqual([
91
- 'interceptor1-before',
92
- 'interceptor2-before',
93
- 'interceptor2-after',
94
- 'interceptor1-after',
95
- ]);
96
- });
10
+ let container: Container;
11
+ let context: Context;
97
12
 
98
- test('should handle async method', async () => {
99
- const container = new Container();
100
- const target = {};
101
- const propertyKey = 'testMethod';
102
- const originalMethod = async () => {
103
- await new Promise((resolve) => setTimeout(resolve, 10));
104
- return 'async-result';
105
- };
106
-
107
- const interceptor: Interceptor = {
108
- async execute(target, propertyKey, originalMethod, args, container, context) {
109
- return await Promise.resolve(originalMethod.apply(target, args));
110
- },
111
- };
112
-
113
- const result = await InterceptorChain.execute(
114
- [interceptor],
115
- target,
116
- propertyKey,
117
- originalMethod,
118
- [],
119
- container,
120
- );
121
-
122
- expect(result).toBe('async-result');
13
+ beforeEach(() => {
14
+ container = new Container();
15
+ const request = new Request('http://localhost/test');
16
+ context = new Context(request, container);
123
17
  });
124
18
 
125
- test('should propagate errors', async () => {
126
- const container = new Container();
127
- const target = {};
128
- const propertyKey = 'testMethod';
129
- const originalMethod = () => {
130
- throw new Error('test error');
131
- };
132
-
133
- const interceptor: Interceptor = {
134
- async execute(target, propertyKey, originalMethod, args, container, context) {
135
- return await Promise.resolve(originalMethod.apply(target, args));
136
- },
137
- };
138
-
139
- await expect(
140
- InterceptorChain.execute([interceptor], target, propertyKey, originalMethod, [], container),
141
- ).rejects.toThrow('test error');
142
- });
143
-
144
- test('should pass context to interceptors', async () => {
145
- const container = new Container();
146
- const target = {};
147
- const propertyKey = 'testMethod';
148
- const originalMethod = () => 'result';
149
- const context = new Context(new Request('http://localhost/test'));
150
- let receivedContext: Context | undefined;
151
-
152
- const interceptor: Interceptor = {
153
- async execute(target, propertyKey, originalMethod, args, container, ctx) {
154
- receivedContext = ctx;
155
- return await Promise.resolve(originalMethod.apply(target, args));
156
- },
157
- };
158
-
159
- await InterceptorChain.execute(
160
- [interceptor],
161
- target,
162
- propertyKey,
163
- originalMethod,
164
- [],
165
- container,
166
- context,
167
- );
168
-
169
- expect(receivedContext).toBe(context);
170
- });
171
-
172
- test('should pass args to interceptors', async () => {
173
- const container = new Container();
174
- const target = {};
175
- const propertyKey = 'testMethod';
176
- const originalMethod = (a: string, b: number) => `${a}-${b}`;
177
- let receivedArgs: unknown[] = [];
178
-
179
- const interceptor: Interceptor = {
180
- async execute(target, propertyKey, originalMethod, args, container, context) {
181
- receivedArgs = args;
182
- return await Promise.resolve(originalMethod.apply(target, args));
183
- },
184
- };
185
-
186
- const result = await InterceptorChain.execute(
187
- [interceptor],
188
- target,
189
- propertyKey,
190
- originalMethod,
191
- ['test', 123],
192
- container,
193
- );
194
-
195
- expect(receivedArgs).toEqual(['test', 123]);
196
- expect(result).toBe('test-123');
19
+ describe('execute', () => {
20
+ test('should execute original method when no interceptors', async () => {
21
+ let methodCalled = false;
22
+ const originalMethod = () => {
23
+ methodCalled = true;
24
+ return 'result';
25
+ };
26
+
27
+ const result = await InterceptorChain.execute(
28
+ [],
29
+ {},
30
+ 'testMethod',
31
+ originalMethod,
32
+ [],
33
+ container,
34
+ context,
35
+ );
36
+
37
+ expect(methodCalled).toBe(true);
38
+ expect(result).toBe('result');
39
+ });
40
+
41
+ test('should execute single interceptor', async () => {
42
+ const calls: string[] = [];
43
+
44
+ const interceptor: Interceptor = {
45
+ priority: 0,
46
+ execute: async (target, propertyKey, next, args, container, context) => {
47
+ calls.push('before');
48
+ const result = await next();
49
+ calls.push('after');
50
+ return result;
51
+ },
52
+ };
53
+
54
+ const result = await InterceptorChain.execute(
55
+ [interceptor],
56
+ {},
57
+ 'testMethod',
58
+ () => {
59
+ calls.push('method');
60
+ return 'result';
61
+ },
62
+ [],
63
+ container,
64
+ context,
65
+ );
66
+
67
+ expect(calls).toEqual(['before', 'method', 'after']);
68
+ expect(result).toBe('result');
69
+ });
70
+
71
+ test('should execute interceptors in order', async () => {
72
+ const calls: number[] = [];
73
+
74
+ const interceptor1: Interceptor = {
75
+ priority: 1,
76
+ execute: async (target, propertyKey, next) => {
77
+ calls.push(1);
78
+ const result = await next();
79
+ calls.push(-1);
80
+ return result;
81
+ },
82
+ };
83
+
84
+ const interceptor2: Interceptor = {
85
+ priority: 2,
86
+ execute: async (target, propertyKey, next) => {
87
+ calls.push(2);
88
+ const result = await next();
89
+ calls.push(-2);
90
+ return result;
91
+ },
92
+ };
93
+
94
+ await InterceptorChain.execute(
95
+ [interceptor1, interceptor2],
96
+ {},
97
+ 'testMethod',
98
+ () => {
99
+ calls.push(0);
100
+ return 'result';
101
+ },
102
+ [],
103
+ container,
104
+ context,
105
+ );
106
+
107
+ expect(calls).toEqual([1, 2, 0, -2, -1]);
108
+ });
109
+
110
+ test('should allow interceptor to modify return value', async () => {
111
+ const interceptor: Interceptor = {
112
+ priority: 0,
113
+ execute: async (target, propertyKey, next) => {
114
+ const result = await next();
115
+ return `modified-${result}`;
116
+ },
117
+ };
118
+
119
+ const result = await InterceptorChain.execute(
120
+ [interceptor],
121
+ {},
122
+ 'testMethod',
123
+ () => 'original',
124
+ [],
125
+ container,
126
+ context,
127
+ );
128
+
129
+ expect(result).toBe('modified-original');
130
+ });
131
+
132
+ test('should pass arguments to interceptors', async () => {
133
+ let receivedArgs: unknown[] = [];
134
+
135
+ const interceptor: Interceptor = {
136
+ priority: 0,
137
+ execute: async (target, propertyKey, next, args) => {
138
+ receivedArgs = args;
139
+ return await next();
140
+ },
141
+ };
142
+
143
+ await InterceptorChain.execute(
144
+ [interceptor],
145
+ {},
146
+ 'testMethod',
147
+ (a: number, b: string) => `${a}-${b}`,
148
+ [42, 'hello'],
149
+ container,
150
+ context,
151
+ );
152
+
153
+ expect(receivedArgs).toEqual([42, 'hello']);
154
+ });
155
+
156
+ test('should handle async original method', async () => {
157
+ const interceptor: Interceptor = {
158
+ priority: 0,
159
+ execute: async (target, propertyKey, next) => {
160
+ return await next();
161
+ },
162
+ };
163
+
164
+ const result = await InterceptorChain.execute(
165
+ [interceptor],
166
+ {},
167
+ 'testMethod',
168
+ async () => {
169
+ await new Promise((r) => setTimeout(r, 10));
170
+ return 'async-result';
171
+ },
172
+ [],
173
+ container,
174
+ context,
175
+ );
176
+
177
+ expect(result).toBe('async-result');
178
+ });
179
+
180
+ test('should propagate errors from original method', async () => {
181
+ const interceptor: Interceptor = {
182
+ priority: 0,
183
+ execute: async (target, propertyKey, next) => {
184
+ return await next();
185
+ },
186
+ };
187
+
188
+ await expect(
189
+ InterceptorChain.execute(
190
+ [interceptor],
191
+ {},
192
+ 'testMethod',
193
+ () => {
194
+ throw new Error('Method error');
195
+ },
196
+ [],
197
+ container,
198
+ context,
199
+ ),
200
+ ).rejects.toThrow('Method error');
201
+ });
202
+
203
+ test('should propagate errors from interceptor', async () => {
204
+ const interceptor: Interceptor = {
205
+ priority: 0,
206
+ execute: async () => {
207
+ throw new Error('Interceptor error');
208
+ },
209
+ };
210
+
211
+ await expect(
212
+ InterceptorChain.execute(
213
+ [interceptor],
214
+ {},
215
+ 'testMethod',
216
+ () => 'result',
217
+ [],
218
+ container,
219
+ context,
220
+ ),
221
+ ).rejects.toThrow('Interceptor error');
222
+ });
223
+
224
+ test('should allow interceptor to modify arguments', async () => {
225
+ let finalArgs: unknown[] = [];
226
+
227
+ const interceptor: Interceptor = {
228
+ priority: 0,
229
+ execute: async (target, propertyKey, next, args) => {
230
+ // Modify arguments by calling next with new args
231
+ return await next(...['modified', 42]);
232
+ },
233
+ };
234
+
235
+ const result = await InterceptorChain.execute(
236
+ [interceptor],
237
+ {},
238
+ 'testMethod',
239
+ (...args: unknown[]) => {
240
+ finalArgs = args;
241
+ return 'done';
242
+ },
243
+ ['original', 0],
244
+ container,
245
+ context,
246
+ );
247
+
248
+ expect(finalArgs).toEqual(['modified', 42]);
249
+ });
197
250
  });
198
251
  });
199
-
@@ -0,0 +1,221 @@
1
+ import { describe, expect, test, beforeEach } from 'bun:test';
2
+ import 'reflect-metadata';
3
+
4
+ import { scanInterceptorMetadata } from '../../src/interceptor/metadata';
5
+ import { InterceptorRegistry } from '../../src/interceptor/interceptor-registry';
6
+ import type { Interceptor } from '../../src/interceptor/types';
7
+ import type { Container } from '../../src/di/container';
8
+ import type { Context } from '../../src/core/context';
9
+
10
+ // 创建测试用的拦截器
11
+ class TestInterceptor1 implements Interceptor {
12
+ public async execute<T>(
13
+ target: unknown,
14
+ propertyKey: string | symbol,
15
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
16
+ args: unknown[],
17
+ container: Container,
18
+ context?: Context,
19
+ ): Promise<T> {
20
+ return await Promise.resolve(originalMethod.apply(target, args));
21
+ }
22
+ }
23
+
24
+ class TestInterceptor2 implements Interceptor {
25
+ public async execute<T>(
26
+ target: unknown,
27
+ propertyKey: string | symbol,
28
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
29
+ args: unknown[],
30
+ container: Container,
31
+ context?: Context,
32
+ ): Promise<T> {
33
+ return await Promise.resolve(originalMethod.apply(target, args));
34
+ }
35
+ }
36
+
37
+ // 测试用的元数据键
38
+ const TEST_METADATA_KEY_1 = Symbol('test:interceptor:1');
39
+ const TEST_METADATA_KEY_2 = Symbol('test:interceptor:2');
40
+
41
+ describe('scanInterceptorMetadata', () => {
42
+ let registry: InterceptorRegistry;
43
+ let interceptor1: TestInterceptor1;
44
+ let interceptor2: TestInterceptor2;
45
+
46
+ beforeEach(() => {
47
+ registry = new InterceptorRegistry();
48
+ interceptor1 = new TestInterceptor1();
49
+ interceptor2 = new TestInterceptor2();
50
+ });
51
+
52
+ test('should return empty array when no interceptors registered', () => {
53
+ class TestClass {
54
+ public testMethod(): void {}
55
+ }
56
+
57
+ const interceptors = scanInterceptorMetadata(
58
+ TestClass.prototype,
59
+ 'testMethod',
60
+ registry,
61
+ );
62
+
63
+ expect(interceptors).toEqual([]);
64
+ });
65
+
66
+ test('should return empty array when method has no matching metadata', () => {
67
+ // 注册拦截器
68
+ registry.register(TEST_METADATA_KEY_1, interceptor1);
69
+
70
+ class TestClass {
71
+ public testMethod(): void {}
72
+ }
73
+
74
+ // 方法没有 TEST_METADATA_KEY_1 元数据
75
+ const interceptors = scanInterceptorMetadata(
76
+ TestClass.prototype,
77
+ 'testMethod',
78
+ registry,
79
+ );
80
+
81
+ expect(interceptors).toEqual([]);
82
+ });
83
+
84
+ test('should return interceptor when method has matching metadata', () => {
85
+ // 注册拦截器
86
+ registry.register(TEST_METADATA_KEY_1, interceptor1);
87
+
88
+ class TestClass {
89
+ public testMethod(): void {}
90
+ }
91
+
92
+ // 在方法上设置元数据
93
+ Reflect.defineMetadata(
94
+ TEST_METADATA_KEY_1,
95
+ { value: 'test' },
96
+ TestClass.prototype,
97
+ 'testMethod',
98
+ );
99
+
100
+ const interceptors = scanInterceptorMetadata(
101
+ TestClass.prototype,
102
+ 'testMethod',
103
+ registry,
104
+ );
105
+
106
+ expect(interceptors.length).toBe(1);
107
+ expect(interceptors[0]).toBe(interceptor1);
108
+ });
109
+
110
+ test('should return multiple interceptors sorted by priority', () => {
111
+ // 注册拦截器,interceptor2 优先级更高(数字更小)
112
+ registry.register(TEST_METADATA_KEY_1, interceptor1, { priority: 20 });
113
+ registry.register(TEST_METADATA_KEY_2, interceptor2, { priority: 10 });
114
+
115
+ class TestClass {
116
+ public testMethod(): void {}
117
+ }
118
+
119
+ // 在方法上设置两个元数据
120
+ Reflect.defineMetadata(
121
+ TEST_METADATA_KEY_1,
122
+ { value: 'test1' },
123
+ TestClass.prototype,
124
+ 'testMethod',
125
+ );
126
+ Reflect.defineMetadata(
127
+ TEST_METADATA_KEY_2,
128
+ { value: 'test2' },
129
+ TestClass.prototype,
130
+ 'testMethod',
131
+ );
132
+
133
+ const interceptors = scanInterceptorMetadata(
134
+ TestClass.prototype,
135
+ 'testMethod',
136
+ registry,
137
+ );
138
+
139
+ expect(interceptors.length).toBe(2);
140
+ // 两个拦截器都应该存在
141
+ expect(interceptors).toContain(interceptor1);
142
+ expect(interceptors).toContain(interceptor2);
143
+ });
144
+
145
+ test('should only return interceptors for matching metadata', () => {
146
+ const unmatchedKey = Symbol('unmatched');
147
+ registry.register(TEST_METADATA_KEY_1, interceptor1);
148
+ registry.register(unmatchedKey, interceptor2);
149
+
150
+ class TestClass {
151
+ public testMethod(): void {}
152
+ }
153
+
154
+ // 只设置 TEST_METADATA_KEY_1 元数据
155
+ Reflect.defineMetadata(
156
+ TEST_METADATA_KEY_1,
157
+ { value: 'test' },
158
+ TestClass.prototype,
159
+ 'testMethod',
160
+ );
161
+
162
+ const interceptors = scanInterceptorMetadata(
163
+ TestClass.prototype,
164
+ 'testMethod',
165
+ registry,
166
+ );
167
+
168
+ expect(interceptors.length).toBe(1);
169
+ expect(interceptors[0]).toBe(interceptor1);
170
+ });
171
+
172
+ test('should handle null metadata value', () => {
173
+ registry.register(TEST_METADATA_KEY_1, interceptor1);
174
+
175
+ class TestClass {
176
+ public testMethod(): void {}
177
+ }
178
+
179
+ // 设置 null 值的元数据
180
+ Reflect.defineMetadata(
181
+ TEST_METADATA_KEY_1,
182
+ null,
183
+ TestClass.prototype,
184
+ 'testMethod',
185
+ );
186
+
187
+ const interceptors = scanInterceptorMetadata(
188
+ TestClass.prototype,
189
+ 'testMethod',
190
+ registry,
191
+ );
192
+
193
+ // null 值应该被忽略
194
+ expect(interceptors).toEqual([]);
195
+ });
196
+
197
+ test('should handle symbol property key', () => {
198
+ registry.register(TEST_METADATA_KEY_1, interceptor1);
199
+
200
+ const methodKey = Symbol('symbolMethod');
201
+
202
+ class TestClass {
203
+ public [methodKey](): void {}
204
+ }
205
+
206
+ Reflect.defineMetadata(
207
+ TEST_METADATA_KEY_1,
208
+ { value: 'test' },
209
+ TestClass.prototype,
210
+ methodKey,
211
+ );
212
+
213
+ const interceptors = scanInterceptorMetadata(
214
+ TestClass.prototype,
215
+ methodKey,
216
+ registry,
217
+ );
218
+
219
+ expect(interceptors.length).toBe(1);
220
+ });
221
+ });