@dangao/bun-server 1.7.1 → 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.
- package/README.md +129 -21
- package/dist/di/decorators.d.ts +37 -0
- package/dist/di/decorators.d.ts.map +1 -1
- package/dist/di/index.d.ts +1 -1
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/module-registry.d.ts +17 -0
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/events/decorators.d.ts +52 -0
- package/dist/events/decorators.d.ts.map +1 -0
- package/dist/events/event-module.d.ts +97 -0
- package/dist/events/event-module.d.ts.map +1 -0
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/service.d.ts +76 -0
- package/dist/events/service.d.ts.map +1 -0
- package/dist/events/types.d.ts +184 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1511 -11
- package/dist/security/filter.d.ts +23 -0
- package/dist/security/filter.d.ts.map +1 -1
- package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
- package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
- package/dist/security/guards/builtin/index.d.ts +3 -0
- package/dist/security/guards/builtin/index.d.ts.map +1 -0
- package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
- package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
- package/dist/security/guards/decorators.d.ts +50 -0
- package/dist/security/guards/decorators.d.ts.map +1 -0
- package/dist/security/guards/execution-context.d.ts +56 -0
- package/dist/security/guards/execution-context.d.ts.map +1 -0
- package/dist/security/guards/guard-registry.d.ts +67 -0
- package/dist/security/guards/guard-registry.d.ts.map +1 -0
- package/dist/security/guards/index.d.ts +7 -0
- package/dist/security/guards/index.d.ts.map +1 -0
- package/dist/security/guards/reflector.d.ts +57 -0
- package/dist/security/guards/reflector.d.ts.map +1 -0
- package/dist/security/guards/types.d.ts +126 -0
- package/dist/security/guards/types.d.ts.map +1 -0
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/security-module.d.ts +20 -0
- package/dist/security/security-module.d.ts.map +1 -1
- package/dist/validation/class-validator.d.ts +108 -0
- package/dist/validation/class-validator.d.ts.map +1 -0
- package/dist/validation/custom-validator.d.ts +130 -0
- package/dist/validation/custom-validator.d.ts.map +1 -0
- package/dist/validation/errors.d.ts +22 -2
- package/dist/validation/errors.d.ts.map +1 -1
- package/dist/validation/index.d.ts +7 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/rules/array.d.ts +33 -0
- package/dist/validation/rules/array.d.ts.map +1 -0
- package/dist/validation/rules/common.d.ts +90 -0
- package/dist/validation/rules/common.d.ts.map +1 -0
- package/dist/validation/rules/conditional.d.ts +30 -0
- package/dist/validation/rules/conditional.d.ts.map +1 -0
- package/dist/validation/rules/index.d.ts +5 -0
- package/dist/validation/rules/index.d.ts.map +1 -0
- package/dist/validation/rules/object.d.ts +30 -0
- package/dist/validation/rules/object.d.ts.map +1 -0
- package/dist/validation/types.d.ts +52 -1
- package/dist/validation/types.d.ts.map +1 -1
- package/docs/events.md +494 -0
- package/docs/guards.md +376 -0
- package/docs/guide.md +309 -1
- package/docs/request-lifecycle.md +444 -0
- package/docs/validation.md +407 -0
- package/docs/zh/events.md +494 -0
- package/docs/zh/guards.md +376 -0
- package/docs/zh/guide.md +309 -1
- package/docs/zh/request-lifecycle.md +444 -0
- package/docs/zh/validation.md +407 -0
- package/package.json +1 -1
- package/src/di/decorators.ts +46 -0
- package/src/di/index.ts +10 -1
- package/src/di/module-registry.ts +39 -0
- package/src/events/decorators.ts +103 -0
- package/src/events/event-module.ts +272 -0
- package/src/events/index.ts +32 -0
- package/src/events/service.ts +352 -0
- package/src/events/types.ts +223 -0
- package/src/index.ts +133 -1
- package/src/security/filter.ts +88 -8
- package/src/security/guards/builtin/auth-guard.ts +68 -0
- package/src/security/guards/builtin/index.ts +3 -0
- package/src/security/guards/builtin/roles-guard.ts +165 -0
- package/src/security/guards/decorators.ts +124 -0
- package/src/security/guards/execution-context.ts +152 -0
- package/src/security/guards/guard-registry.ts +164 -0
- package/src/security/guards/index.ts +7 -0
- package/src/security/guards/reflector.ts +99 -0
- package/src/security/guards/types.ts +144 -0
- package/src/security/index.ts +1 -0
- package/src/security/security-module.ts +72 -2
- package/src/validation/class-validator.ts +322 -0
- package/src/validation/custom-validator.ts +289 -0
- package/src/validation/errors.ts +50 -2
- package/src/validation/index.ts +103 -1
- package/src/validation/rules/array.ts +118 -0
- package/src/validation/rules/common.ts +286 -0
- package/src/validation/rules/conditional.ts +52 -0
- package/src/validation/rules/index.ts +51 -0
- package/src/validation/rules/object.ts +86 -0
- package/src/validation/types.ts +61 -1
- package/tests/auth/auth-decorators.test.ts +241 -0
- package/tests/auth/oauth2-service.test.ts +318 -0
- package/tests/cache/cache-decorators-extended.test.ts +272 -0
- package/tests/cache/cache-interceptors.test.ts +534 -0
- package/tests/cache/cache-service-proxy.test.ts +246 -0
- package/tests/cache/memory-cache-store.test.ts +155 -0
- package/tests/cache/redis-cache-store.test.ts +199 -0
- package/tests/config/config-center-integration.test.ts +334 -0
- package/tests/config/config-module-extended.test.ts +165 -0
- package/tests/controller/param-binder.test.ts +333 -0
- package/tests/di/global-module.test.ts +487 -0
- package/tests/error/error-handler.test.ts +166 -57
- package/tests/error/i18n-extended.test.ts +105 -0
- package/tests/events/event-decorators.test.ts +173 -0
- package/tests/events/event-emitter.test.ts +373 -0
- package/tests/events/event-listener-scanner.test.ts +114 -0
- package/tests/events/event-module.test.ts +204 -0
- package/tests/extensions/logger-module.test.ts +158 -0
- package/tests/files/file-storage.test.ts +136 -0
- package/tests/interceptor/base-interceptor.test.ts +605 -0
- package/tests/interceptor/builtin/cache-interceptor.test.ts +233 -86
- package/tests/interceptor/builtin/log-interceptor.test.ts +469 -0
- package/tests/interceptor/builtin/permission-interceptor.test.ts +219 -120
- package/tests/interceptor/interceptor-chain.test.ts +241 -189
- package/tests/interceptor/interceptor-metadata.test.ts +221 -0
- package/tests/microservice/circuit-breaker.test.ts +221 -0
- package/tests/microservice/service-client-decorators.test.ts +86 -0
- package/tests/microservice/service-client-interceptors.test.ts +274 -0
- package/tests/microservice/service-registry-decorators.test.ts +147 -0
- package/tests/microservice/tracer.test.ts +213 -0
- package/tests/microservice/tracing-collectors.test.ts +168 -0
- package/tests/middleware/builtin/middleware-builtin-extended.test.ts +237 -0
- package/tests/middleware/builtin/rate-limit.test.ts +257 -0
- package/tests/middleware/middleware-decorators.test.ts +222 -0
- package/tests/middleware/middleware-pipeline.test.ts +160 -0
- package/tests/queue/queue-decorators.test.ts +139 -0
- package/tests/queue/queue-service.test.ts +191 -0
- package/tests/request/body-parser-extended.test.ts +291 -0
- package/tests/request/request-wrapper.test.ts +319 -0
- package/tests/router/router-decorators.test.ts +260 -0
- package/tests/router/router-extended.test.ts +298 -0
- package/tests/security/guards/guards-integration.test.ts +371 -0
- package/tests/security/guards/guards.test.ts +775 -0
- package/tests/security/guards/reflector.test.ts +188 -0
- package/tests/security/security-filter.test.ts +182 -0
- package/tests/security/security-module-extended.test.ts +133 -0
- package/tests/security/security-module.test.ts +2 -2
- package/tests/session/memory-session-store.test.ts +172 -0
- package/tests/session/session-decorators.test.ts +163 -0
- package/tests/swagger/ui.test.ts +212 -0
- package/tests/validation/class-validator.test.ts +349 -0
- package/tests/validation/custom-validator.test.ts +335 -0
- package/tests/validation/rules.test.ts +543 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
|
|
4
|
+
import { ParamBinder } from '../../src/controller/param-binder';
|
|
5
|
+
import {
|
|
6
|
+
Body,
|
|
7
|
+
Query,
|
|
8
|
+
Param,
|
|
9
|
+
Header,
|
|
10
|
+
Context as ContextDecorator,
|
|
11
|
+
QueryMap,
|
|
12
|
+
HeaderMap,
|
|
13
|
+
} from '../../src/controller/decorators';
|
|
14
|
+
import { Context } from '../../src/core/context';
|
|
15
|
+
import { Container } from '../../src/di/container';
|
|
16
|
+
|
|
17
|
+
describe('ParamBinder', () => {
|
|
18
|
+
let container: Container;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
container = new Container();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('bind', () => {
|
|
25
|
+
test('should bind @Body parameter', async () => {
|
|
26
|
+
class TestController {
|
|
27
|
+
public testMethod(@Body() body: unknown): void {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const request = new Request('http://localhost/test', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
body: JSON.stringify({ name: 'test' }),
|
|
34
|
+
});
|
|
35
|
+
const context = new Context(request, container);
|
|
36
|
+
|
|
37
|
+
const params = await ParamBinder.bind(
|
|
38
|
+
TestController.prototype,
|
|
39
|
+
'testMethod',
|
|
40
|
+
context,
|
|
41
|
+
container,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(params[0]).toEqual({ name: 'test' });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should bind @Body with key parameter', async () => {
|
|
48
|
+
class TestController {
|
|
49
|
+
public testMethod(@Body('name') name: string): void {}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const request = new Request('http://localhost/test', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: { 'Content-Type': 'application/json' },
|
|
55
|
+
body: JSON.stringify({ name: 'alice', age: 25 }),
|
|
56
|
+
});
|
|
57
|
+
const context = new Context(request, container);
|
|
58
|
+
|
|
59
|
+
const params = await ParamBinder.bind(
|
|
60
|
+
TestController.prototype,
|
|
61
|
+
'testMethod',
|
|
62
|
+
context,
|
|
63
|
+
container,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(params[0]).toBe('alice');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('should bind @Query parameter', async () => {
|
|
70
|
+
class TestController {
|
|
71
|
+
public testMethod(@Query('id') id: string): void {}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const request = new Request('http://localhost/test?id=123');
|
|
75
|
+
const context = new Context(request, container);
|
|
76
|
+
|
|
77
|
+
const params = await ParamBinder.bind(
|
|
78
|
+
TestController.prototype,
|
|
79
|
+
'testMethod',
|
|
80
|
+
context,
|
|
81
|
+
container,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(params[0]).toBe('123');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('should bind @Param parameter', async () => {
|
|
88
|
+
class TestController {
|
|
89
|
+
public testMethod(@Param('id') id: string): void {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const request = new Request('http://localhost/users/456');
|
|
93
|
+
const context = new Context(request, container);
|
|
94
|
+
context.params = { id: '456' };
|
|
95
|
+
|
|
96
|
+
const params = await ParamBinder.bind(
|
|
97
|
+
TestController.prototype,
|
|
98
|
+
'testMethod',
|
|
99
|
+
context,
|
|
100
|
+
container,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(params[0]).toBe('456');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('should bind @Header parameter', async () => {
|
|
107
|
+
class TestController {
|
|
108
|
+
public testMethod(@Header('x-custom') custom: string): void {}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const request = new Request('http://localhost/test', {
|
|
112
|
+
headers: { 'X-Custom': 'custom-value' },
|
|
113
|
+
});
|
|
114
|
+
const context = new Context(request, container);
|
|
115
|
+
|
|
116
|
+
const params = await ParamBinder.bind(
|
|
117
|
+
TestController.prototype,
|
|
118
|
+
'testMethod',
|
|
119
|
+
context,
|
|
120
|
+
container,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(params[0]).toBe('custom-value');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('should bind @Context parameter', async () => {
|
|
127
|
+
class TestController {
|
|
128
|
+
public testMethod(@ContextDecorator() ctx: Context): void {}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const request = new Request('http://localhost/test');
|
|
132
|
+
const context = new Context(request, container);
|
|
133
|
+
|
|
134
|
+
const params = await ParamBinder.bind(
|
|
135
|
+
TestController.prototype,
|
|
136
|
+
'testMethod',
|
|
137
|
+
context,
|
|
138
|
+
container,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// 返回的是 context 或 AsyncLocalStorage 中的 context
|
|
142
|
+
expect(params[0]).toBeDefined();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('should bind multiple parameters in correct order', async () => {
|
|
146
|
+
class TestController {
|
|
147
|
+
public testMethod(
|
|
148
|
+
@Query('name') name: string,
|
|
149
|
+
@Query('age') age: string,
|
|
150
|
+
@Header('x-token') token: string,
|
|
151
|
+
): void {}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const request = new Request('http://localhost/test?name=alice&age=25', {
|
|
155
|
+
headers: { 'X-Token': 'abc123' },
|
|
156
|
+
});
|
|
157
|
+
const context = new Context(request, container);
|
|
158
|
+
|
|
159
|
+
const params = await ParamBinder.bind(
|
|
160
|
+
TestController.prototype,
|
|
161
|
+
'testMethod',
|
|
162
|
+
context,
|
|
163
|
+
container,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(params[0]).toBe('alice');
|
|
167
|
+
expect(params[1]).toBe('25');
|
|
168
|
+
expect(params[2]).toBe('abc123');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('should return empty array for method without decorators', async () => {
|
|
172
|
+
class TestController {
|
|
173
|
+
public testMethod(arg: string): void {}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const request = new Request('http://localhost/test');
|
|
177
|
+
const context = new Context(request, container);
|
|
178
|
+
|
|
179
|
+
const params = await ParamBinder.bind(
|
|
180
|
+
TestController.prototype,
|
|
181
|
+
'testMethod',
|
|
182
|
+
context,
|
|
183
|
+
container,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
expect(params).toEqual([]);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('should handle @QueryMap parameter', async () => {
|
|
190
|
+
class TestController {
|
|
191
|
+
public testMethod(@QueryMap() query: Record<string, string>): void {}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const request = new Request('http://localhost/test?foo=bar&baz=qux');
|
|
195
|
+
const context = new Context(request, container);
|
|
196
|
+
|
|
197
|
+
const params = await ParamBinder.bind(
|
|
198
|
+
TestController.prototype,
|
|
199
|
+
'testMethod',
|
|
200
|
+
context,
|
|
201
|
+
container,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
expect(params[0]).toEqual({ foo: 'bar', baz: 'qux' });
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('should handle @QueryMap with transform', async () => {
|
|
208
|
+
class TestController {
|
|
209
|
+
public testMethod(
|
|
210
|
+
@QueryMap({
|
|
211
|
+
transform: (map) => ({ ...map, transformed: true }),
|
|
212
|
+
})
|
|
213
|
+
query: Record<string, unknown>,
|
|
214
|
+
): void {}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const request = new Request('http://localhost/test?foo=bar');
|
|
218
|
+
const context = new Context(request, container);
|
|
219
|
+
|
|
220
|
+
const params = await ParamBinder.bind(
|
|
221
|
+
TestController.prototype,
|
|
222
|
+
'testMethod',
|
|
223
|
+
context,
|
|
224
|
+
container,
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
expect((params[0] as any).transformed).toBe(true);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test('should handle @HeaderMap parameter', async () => {
|
|
231
|
+
class TestController {
|
|
232
|
+
public testMethod(@HeaderMap() headers: Record<string, string>): void {}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const request = new Request('http://localhost/test', {
|
|
236
|
+
headers: { 'X-Custom': 'value1', 'X-Another': 'value2' },
|
|
237
|
+
});
|
|
238
|
+
const context = new Context(request, container);
|
|
239
|
+
|
|
240
|
+
const params = await ParamBinder.bind(
|
|
241
|
+
TestController.prototype,
|
|
242
|
+
'testMethod',
|
|
243
|
+
context,
|
|
244
|
+
container,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
expect((params[0] as any)['x-custom']).toBe('value1');
|
|
248
|
+
expect((params[0] as any)['x-another']).toBe('value2');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('should handle @HeaderMap with pick', async () => {
|
|
252
|
+
class TestController {
|
|
253
|
+
public testMethod(
|
|
254
|
+
@HeaderMap({ pick: ['x-custom'] })
|
|
255
|
+
headers: Record<string, string>,
|
|
256
|
+
): void {}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const request = new Request('http://localhost/test', {
|
|
260
|
+
headers: { 'X-Custom': 'value1', 'X-Another': 'value2' },
|
|
261
|
+
});
|
|
262
|
+
const context = new Context(request, container);
|
|
263
|
+
|
|
264
|
+
const params = await ParamBinder.bind(
|
|
265
|
+
TestController.prototype,
|
|
266
|
+
'testMethod',
|
|
267
|
+
context,
|
|
268
|
+
container,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
expect((params[0] as any)['x-custom']).toBe('value1');
|
|
272
|
+
expect((params[0] as any)['x-another']).toBeUndefined();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('should handle missing body key', async () => {
|
|
276
|
+
class TestController {
|
|
277
|
+
public testMethod(@Body('missing') value: string): void {}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const request = new Request('http://localhost/test', {
|
|
281
|
+
method: 'POST',
|
|
282
|
+
headers: { 'Content-Type': 'application/json' },
|
|
283
|
+
body: JSON.stringify({ name: 'test' }),
|
|
284
|
+
});
|
|
285
|
+
const context = new Context(request, container);
|
|
286
|
+
|
|
287
|
+
const params = await ParamBinder.bind(
|
|
288
|
+
TestController.prototype,
|
|
289
|
+
'testMethod',
|
|
290
|
+
context,
|
|
291
|
+
container,
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(params[0]).toBeUndefined();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('should return null for missing query param', async () => {
|
|
298
|
+
class TestController {
|
|
299
|
+
public testMethod(@Query('missing') value: string): void {}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const request = new Request('http://localhost/test');
|
|
303
|
+
const context = new Context(request, container);
|
|
304
|
+
|
|
305
|
+
const params = await ParamBinder.bind(
|
|
306
|
+
TestController.prototype,
|
|
307
|
+
'testMethod',
|
|
308
|
+
context,
|
|
309
|
+
container,
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(params[0]).toBeNull();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('should return undefined for missing path param', async () => {
|
|
316
|
+
class TestController {
|
|
317
|
+
public testMethod(@Param('missing') value: string): void {}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const request = new Request('http://localhost/test');
|
|
321
|
+
const context = new Context(request, container);
|
|
322
|
+
|
|
323
|
+
const params = await ParamBinder.bind(
|
|
324
|
+
TestController.prototype,
|
|
325
|
+
'testMethod',
|
|
326
|
+
context,
|
|
327
|
+
container,
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
expect(params[0]).toBeUndefined();
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|