@dangao/bun-server 3.2.0 → 3.3.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 (131) hide show
  1. package/dist/ai/types.d.ts +4 -0
  2. package/dist/ai/types.d.ts.map +1 -1
  3. package/dist/auth/types.d.ts +4 -0
  4. package/dist/auth/types.d.ts.map +1 -1
  5. package/dist/cache/interceptors.d.ts +3 -3
  6. package/dist/cache/interceptors.d.ts.map +1 -1
  7. package/dist/cache/service.d.ts +6 -6
  8. package/dist/cache/service.d.ts.map +1 -1
  9. package/dist/cache/types.d.ts +12 -12
  10. package/dist/cache/types.d.ts.map +1 -1
  11. package/dist/config/service.d.ts +6 -4
  12. package/dist/config/service.d.ts.map +1 -1
  13. package/dist/core/application.d.ts +4 -0
  14. package/dist/core/application.d.ts.map +1 -1
  15. package/dist/core/context.d.ts +4 -2
  16. package/dist/core/context.d.ts.map +1 -1
  17. package/dist/database/sqlite-adapter.d.ts +4 -2
  18. package/dist/database/sqlite-adapter.d.ts.map +1 -1
  19. package/dist/di/container.d.ts +2 -0
  20. package/dist/di/container.d.ts.map +1 -1
  21. package/dist/di/module-registry.d.ts.map +1 -1
  22. package/dist/di/module.d.ts +11 -1
  23. package/dist/di/module.d.ts.map +1 -1
  24. package/dist/di/types.d.ts +1 -1
  25. package/dist/di/types.d.ts.map +1 -1
  26. package/dist/error/handler.d.ts.map +1 -1
  27. package/dist/error/http-exception.d.ts +8 -8
  28. package/dist/error/http-exception.d.ts.map +1 -1
  29. package/dist/error/index.d.ts +1 -0
  30. package/dist/error/index.d.ts.map +1 -1
  31. package/dist/events/service.d.ts +2 -2
  32. package/dist/events/service.d.ts.map +1 -1
  33. package/dist/events/types.d.ts +12 -3
  34. package/dist/events/types.d.ts.map +1 -1
  35. package/dist/index.js +63 -25
  36. package/dist/index.node.mjs +63 -25
  37. package/dist/interceptor/base-interceptor.d.ts +3 -3
  38. package/dist/interceptor/base-interceptor.d.ts.map +1 -1
  39. package/dist/interceptor/builtin/log-interceptor.d.ts +1 -1
  40. package/dist/interceptor/builtin/log-interceptor.d.ts.map +1 -1
  41. package/dist/interceptor/builtin/permission-interceptor.d.ts +1 -1
  42. package/dist/interceptor/builtin/permission-interceptor.d.ts.map +1 -1
  43. package/dist/interceptor/interceptor-chain.d.ts +1 -1
  44. package/dist/interceptor/interceptor-chain.d.ts.map +1 -1
  45. package/dist/interceptor/interceptor-registry.d.ts +3 -1
  46. package/dist/interceptor/interceptor-registry.d.ts.map +1 -1
  47. package/dist/interceptor/types.d.ts +6 -1
  48. package/dist/interceptor/types.d.ts.map +1 -1
  49. package/dist/microservice/service-client/types.d.ts +1 -0
  50. package/dist/microservice/service-client/types.d.ts.map +1 -1
  51. package/dist/microservice/tracing/tracer.d.ts +1 -0
  52. package/dist/microservice/tracing/tracer.d.ts.map +1 -1
  53. package/dist/middleware/builtin/file-upload.d.ts +2 -0
  54. package/dist/middleware/builtin/file-upload.d.ts.map +1 -1
  55. package/dist/middleware/builtin/rate-limit.d.ts +9 -1
  56. package/dist/middleware/builtin/rate-limit.d.ts.map +1 -1
  57. package/dist/queue/service.d.ts +2 -2
  58. package/dist/queue/service.d.ts.map +1 -1
  59. package/dist/queue/types.d.ts +25 -1
  60. package/dist/queue/types.d.ts.map +1 -1
  61. package/dist/router/decorators.d.ts +1 -2
  62. package/dist/router/decorators.d.ts.map +1 -1
  63. package/dist/security/guards/types.d.ts +1 -0
  64. package/dist/security/guards/types.d.ts.map +1 -1
  65. package/dist/security/types.d.ts +1 -1
  66. package/dist/security/types.d.ts.map +1 -1
  67. package/dist/session/types.d.ts +8 -0
  68. package/dist/session/types.d.ts.map +1 -1
  69. package/dist/swagger/decorators.d.ts +1 -1
  70. package/dist/swagger/decorators.d.ts.map +1 -1
  71. package/dist/swagger/types.d.ts +1 -1
  72. package/dist/swagger/types.d.ts.map +1 -1
  73. package/dist/testing/harness.d.ts +1 -1
  74. package/dist/testing/harness.d.ts.map +1 -1
  75. package/dist/testing/test-client.d.ts +1 -1
  76. package/dist/testing/test-client.d.ts.map +1 -1
  77. package/dist/testing/testing-module.d.ts +2 -2
  78. package/dist/testing/testing-module.d.ts.map +1 -1
  79. package/dist/validation/errors.d.ts +5 -1
  80. package/dist/validation/errors.d.ts.map +1 -1
  81. package/package.json +3 -3
  82. package/src/ai/types.ts +5 -0
  83. package/src/auth/types.ts +4 -1
  84. package/src/cache/interceptors.ts +6 -6
  85. package/src/cache/service-proxy.ts +2 -2
  86. package/src/cache/service.ts +17 -8
  87. package/src/cache/types.ts +12 -12
  88. package/src/config/service.ts +8 -6
  89. package/src/core/application.ts +7 -1
  90. package/src/core/context.ts +6 -3
  91. package/src/database/sqlite-adapter.ts +4 -3
  92. package/src/di/container.ts +13 -0
  93. package/src/di/module-registry.ts +2 -3
  94. package/src/di/module.ts +21 -2
  95. package/src/di/types.ts +1 -2
  96. package/src/error/handler.ts +3 -4
  97. package/src/error/http-exception.ts +11 -11
  98. package/src/error/index.ts +1 -1
  99. package/src/events/service.ts +4 -2
  100. package/src/events/types.ts +14 -3
  101. package/src/interceptor/base-interceptor.ts +5 -6
  102. package/src/interceptor/builtin/log-interceptor.ts +2 -3
  103. package/src/interceptor/builtin/permission-interceptor.ts +2 -3
  104. package/src/interceptor/interceptor-chain.ts +6 -7
  105. package/src/interceptor/interceptor-registry.ts +5 -3
  106. package/src/interceptor/types.ts +9 -4
  107. package/src/microservice/service-client/types.ts +1 -1
  108. package/src/microservice/tracing/tracer.ts +15 -3
  109. package/src/middleware/builtin/file-upload.ts +3 -2
  110. package/src/middleware/builtin/rate-limit.ts +22 -5
  111. package/src/queue/service.ts +1 -1
  112. package/src/queue/types.ts +40 -1
  113. package/src/router/decorators.ts +2 -3
  114. package/src/security/guards/types.ts +2 -1
  115. package/src/security/types.ts +1 -2
  116. package/src/session/service.ts +1 -1
  117. package/src/session/types.ts +10 -0
  118. package/src/swagger/decorators.ts +15 -4
  119. package/src/swagger/generator.ts +2 -3
  120. package/src/swagger/types.ts +1 -2
  121. package/src/testing/harness.ts +1 -2
  122. package/src/testing/test-client.ts +2 -2
  123. package/src/testing/testing-module.ts +5 -5
  124. package/src/validation/errors.ts +6 -2
  125. package/tests/bun-test-shim.d.ts +11 -0
  126. package/tests/controller/context-decorator.test.ts +1 -2
  127. package/tests/di/module.test.ts +199 -1
  128. package/tests/events/event-emitter.test.ts +2 -2
  129. package/tests/global.d.ts +30 -0
  130. package/tests/queue/queue-service.test.ts +14 -0
  131. package/tests/testing/testing-module.test.ts +20 -0
@@ -155,7 +155,7 @@ describe('@Context() Decorator', () => {
155
155
  // 这个测试验证 ContextService 可以在服务层使用
156
156
  const { ContextService, CONTEXT_SERVICE_TOKEN } = await import('../../src/core/context-service');
157
157
  const container = app.getContainer();
158
- const contextService = container.resolve<ContextService>(CONTEXT_SERVICE_TOKEN);
158
+ const contextService = container.resolve<InstanceType<typeof ContextService>>(CONTEXT_SERVICE_TOKEN);
159
159
 
160
160
  @Controller('/api/test')
161
161
  class TestController {
@@ -180,4 +180,3 @@ describe('@Context() Decorator', () => {
180
180
  expect(data.method).toBe('GET');
181
181
  });
182
182
  });
183
-
@@ -5,6 +5,7 @@ import { Controller, ControllerRegistry } from '../../src/controller/controller'
5
5
  import { GET } from '../../src/router/decorators';
6
6
  import { Module } from '../../src/di/module';
7
7
  import { ModuleRegistry } from '../../src/di/module-registry';
8
+ import { Container } from '../../src/di/container';
8
9
  import { RouteRegistry } from '../../src/router/registry';
9
10
  import { Injectable, Inject } from '../../src/di/decorators';
10
11
  import { Context } from '../../src/core/context';
@@ -177,6 +178,204 @@ describe('ModuleRegistry', () => {
177
178
  expect(() => ref.container.resolve(ALIAS)).toThrow(/Provider not found/);
178
179
  });
179
180
 
181
+ test('FactoryProvider inject passes resolved dependencies to useFactory', () => {
182
+ const TOKEN = Symbol.for('test.factory.inject.basic');
183
+
184
+ @Injectable()
185
+ class Dep {
186
+ public greet(): string {
187
+ return 'hello';
188
+ }
189
+ }
190
+
191
+ @Module({
192
+ providers: [
193
+ Dep,
194
+ {
195
+ provide: TOKEN,
196
+ useFactory: (dep: Dep) => ({
197
+ dep,
198
+ message: dep.greet(),
199
+ }),
200
+ inject: [Dep],
201
+ },
202
+ ],
203
+ })
204
+ class TestModule {}
205
+
206
+ const app = new Application();
207
+ app.registerModule(TestModule);
208
+
209
+ const ref = ModuleRegistry.getInstance().getModuleRef(TestModule)!;
210
+ const dep = ref.container.resolve(Dep);
211
+ const result = ref.container.resolve<{ dep: Dep; message: string }>(TOKEN);
212
+
213
+ expect(result.dep).toBe(dep);
214
+ expect(result.message).toBe('hello');
215
+ });
216
+
217
+ test('FactoryProvider without inject or with empty inject still passes Container to useFactory', () => {
218
+ const TOKEN = Symbol.for('test.factory.inject.compat');
219
+ const EMPTY_INJECT_TOKEN = Symbol.for('test.factory.inject.compat.empty');
220
+
221
+ @Injectable()
222
+ class Dep {
223
+ public readonly value = 'manual';
224
+ }
225
+
226
+ @Module({
227
+ providers: [
228
+ Dep,
229
+ {
230
+ provide: TOKEN,
231
+ useFactory: (container: Container) => ({
232
+ isContainer: container instanceof Container,
233
+ dep: container.resolve(Dep),
234
+ }),
235
+ },
236
+ {
237
+ provide: EMPTY_INJECT_TOKEN,
238
+ useFactory: (container: Container) => ({
239
+ isContainer: container instanceof Container,
240
+ dep: container.resolve(Dep),
241
+ }),
242
+ inject: [],
243
+ },
244
+ ],
245
+ })
246
+ class TestModule {}
247
+
248
+ const app = new Application();
249
+ app.registerModule(TestModule);
250
+
251
+ const ref = ModuleRegistry.getInstance().getModuleRef(TestModule)!;
252
+ const dep = ref.container.resolve(Dep);
253
+ const result = ref.container.resolve<{ isContainer: boolean; dep: Dep }>(TOKEN);
254
+ const emptyInjectResult = ref.container.resolve<{ isContainer: boolean; dep: Dep }>(
255
+ EMPTY_INJECT_TOKEN,
256
+ );
257
+
258
+ expect(result.isContainer).toBe(true);
259
+ expect(result.dep).toBe(dep);
260
+ expect(emptyInjectResult.isContainer).toBe(true);
261
+ expect(emptyInjectResult.dep).toBe(dep);
262
+ });
263
+
264
+ test('FactoryProvider inject resolves tokens exported from imported modules', () => {
265
+ const DEP_TOKEN = Symbol.for('test.factory.inject.exported.dep');
266
+ const TOKEN = Symbol.for('test.factory.inject.exported.result');
267
+
268
+ interface DepContract {
269
+ label(): string;
270
+ }
271
+
272
+ const exportedDep: DepContract = {
273
+ label: () => 'from-export',
274
+ };
275
+
276
+ @Module({
277
+ providers: [{ provide: DEP_TOKEN, useValue: exportedDep }],
278
+ exports: [DEP_TOKEN],
279
+ })
280
+ class SharedModule {}
281
+
282
+ @Module({
283
+ imports: [SharedModule],
284
+ providers: [
285
+ {
286
+ provide: TOKEN,
287
+ useFactory: (dep: DepContract) => ({
288
+ dep,
289
+ label: dep.label(),
290
+ }),
291
+ inject: [DEP_TOKEN],
292
+ },
293
+ ],
294
+ })
295
+ class AppModule {}
296
+
297
+ const app = new Application();
298
+ app.registerModule(AppModule);
299
+
300
+ const ref = ModuleRegistry.getInstance().getModuleRef(AppModule)!;
301
+ const result = ref.container.resolve<{ dep: DepContract; label: string }>(TOKEN);
302
+
303
+ expect(result.dep).toBe(exportedDep);
304
+ expect(result.label).toBe('from-export');
305
+ });
306
+
307
+ test('FactoryProvider inject preserves token order for factory arguments', () => {
308
+ const FIRST = Symbol.for('test.factory.inject.order.first');
309
+ const SECOND = Symbol.for('test.factory.inject.order.second');
310
+ const TOKEN = Symbol.for('test.factory.inject.order.result');
311
+
312
+ @Module({
313
+ providers: [
314
+ { provide: FIRST, useValue: 'first' },
315
+ { provide: SECOND, useValue: 'second' },
316
+ {
317
+ provide: TOKEN,
318
+ useFactory: (second: string, first: string) => [second, first],
319
+ inject: [SECOND, FIRST],
320
+ },
321
+ ],
322
+ })
323
+ class TestModule {}
324
+
325
+ const app = new Application();
326
+ app.registerModule(TestModule);
327
+
328
+ const ref = ModuleRegistry.getInstance().getModuleRef(TestModule)!;
329
+ const result = ref.container.resolve<string[]>(TOKEN);
330
+
331
+ expect(result).toEqual(['second', 'first']);
332
+ });
333
+
334
+ test('FactoryProvider inject works when mixed with useExisting useValue and useClass providers', () => {
335
+ const CLASS_TOKEN = Symbol.for('test.factory.inject.mix.class');
336
+ const VALUE_TOKEN = Symbol.for('test.factory.inject.mix.value');
337
+ const ALIAS_TOKEN = Symbol.for('test.factory.inject.mix.alias');
338
+ const TOKEN = Symbol.for('test.factory.inject.mix.result');
339
+
340
+ class Impl {
341
+ public readonly kind = 'impl';
342
+ }
343
+
344
+ const value = { kind: 'value' };
345
+
346
+ @Module({
347
+ providers: [
348
+ { provide: CLASS_TOKEN, useClass: Impl },
349
+ { provide: VALUE_TOKEN, useValue: value },
350
+ { provide: ALIAS_TOKEN, useExisting: CLASS_TOKEN },
351
+ {
352
+ provide: TOKEN,
353
+ useFactory: (aliased: Impl, injectedValue: typeof value) => ({
354
+ aliased,
355
+ injectedValue,
356
+ }),
357
+ inject: [ALIAS_TOKEN, VALUE_TOKEN],
358
+ },
359
+ ],
360
+ })
361
+ class TestModule {}
362
+
363
+ const app = new Application();
364
+ app.registerModule(TestModule);
365
+
366
+ const ref = ModuleRegistry.getInstance().getModuleRef(TestModule)!;
367
+ const classInstance = ref.container.resolve<Impl>(CLASS_TOKEN);
368
+ const aliasInstance = ref.container.resolve<Impl>(ALIAS_TOKEN);
369
+ const valueInstance = ref.container.resolve<typeof value>(VALUE_TOKEN);
370
+ const result = ref.container.resolve<{ aliased: Impl; injectedValue: typeof value }>(TOKEN);
371
+
372
+ expect(classInstance).toBeInstanceOf(Impl);
373
+ expect(aliasInstance).toBe(classInstance);
374
+ expect(valueInstance).toBe(value);
375
+ expect(result.aliased).toBe(classInstance);
376
+ expect(result.injectedValue).toBe(value);
377
+ });
378
+
180
379
  test('should throw error for circular module dependencies', () => {
181
380
  @Module({
182
381
  imports: [],
@@ -199,4 +398,3 @@ describe('ModuleRegistry', () => {
199
398
  );
200
399
  });
201
400
  });
202
-
@@ -257,7 +257,7 @@ describe('EventEmitterService', () => {
257
257
  });
258
258
 
259
259
  test('should use custom error handler when provided', () => {
260
- const errorHandler = mock(() => {});
260
+ const errorHandler = mock((_error: Error) => {});
261
261
  const emitterWithErrorHandler = new EventEmitterService({
262
262
  onError: errorHandler,
263
263
  });
@@ -274,7 +274,7 @@ describe('EventEmitterService', () => {
274
274
 
275
275
  describe('maxListeners warning', () => {
276
276
  test('should warn when exceeding maxListeners', () => {
277
- const consoleSpy = mock(() => {});
277
+ const consoleSpy = mock((_message: string) => {});
278
278
  const originalWarn = console.warn;
279
279
  console.warn = consoleSpy;
280
280
 
@@ -0,0 +1,30 @@
1
+ declare global {
2
+ interface Body {
3
+ json(): Promise<any>;
4
+ }
5
+
6
+ interface Response {
7
+ json(): Promise<any>;
8
+ }
9
+ }
10
+
11
+ declare module 'bun:test' {
12
+ export function expect(actual?: any): any;
13
+ export function mock(fn?: (...args: any[]) => any): any;
14
+
15
+ interface MatchersBuiltin<T = unknown> {
16
+ toBe(expected: any): void;
17
+ }
18
+
19
+ interface Matchers<T = unknown> {
20
+ toBe(expected: any): void;
21
+ }
22
+ }
23
+
24
+ declare module '@dangao/logsmith' {
25
+ interface LogEntry {
26
+ data?: unknown;
27
+ }
28
+ }
29
+
30
+ export {};
@@ -47,6 +47,16 @@ function createMockStore(): QueueStore {
47
47
  return first as Job<T> | undefined;
48
48
  },
49
49
 
50
+ async updateStatus(queueName: string, jobId: string, status: Job['status']): Promise<boolean> {
51
+ const job = queues.get(queueName)?.get(jobId);
52
+ if (!job) {
53
+ return false;
54
+ }
55
+ job.status = status;
56
+ job.updatedAt = Date.now();
57
+ return true;
58
+ },
59
+
50
60
  async complete(queueName: string, jobId: string, result?: any): Promise<boolean> {
51
61
  const job = queues.get(queueName)?.get(jobId);
52
62
  if (job) {
@@ -84,6 +94,10 @@ function createMockStore(): QueueStore {
84
94
  }
85
95
  return { waiting, active, completed, failed };
86
96
  },
97
+
98
+ async count(queueName: string): Promise<number> {
99
+ return queues.get(queueName)?.size ?? 0;
100
+ },
87
101
  };
88
102
  }
89
103
 
@@ -126,4 +126,24 @@ describe('TestingModule', () => {
126
126
  const greeter = module.get<Greeter>(GREETER_TOKEN);
127
127
  expect(greeter.greet('X')).toBe('Factory: X');
128
128
  });
129
+
130
+ test('should inject dependencies into provider factories', async () => {
131
+ const FACTORY_TOKEN = Symbol('FactoryGreeter');
132
+
133
+ const module = await Test.createTestingModule({
134
+ providers: [
135
+ { provide: GREETER_TOKEN, useClass: RealGreeter },
136
+ {
137
+ provide: FACTORY_TOKEN,
138
+ useFactory: (greeter: Greeter) => ({
139
+ greet: (name: string) => greeter.greet(name).toUpperCase(),
140
+ }),
141
+ inject: [GREETER_TOKEN],
142
+ },
143
+ ],
144
+ }).compile();
145
+
146
+ const greeter = module.get<Greeter>(FACTORY_TOKEN);
147
+ expect(greeter.greet('Test')).toBe('HELLO, TEST!');
148
+ });
129
149
  });