@onebun/core 0.1.23 → 0.2.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.
@@ -11,6 +11,7 @@ import {
11
11
  expect,
12
12
  beforeEach,
13
13
  afterEach,
14
+ mock,
14
15
  } from 'bun:test';
15
16
 
16
17
  import { OneBunApplication } from '../application';
@@ -817,50 +818,63 @@ describe('decorators', () => {
817
818
  });
818
819
 
819
820
  test('should properly inject module service into controller without @Inject', async () => {
820
- @Service()
821
- class TestService extends BaseService {
822
- getValue() {
823
- return 'injected-value';
821
+ // Mock Bun.serve to avoid starting a real server
822
+ const originalServe = Bun.serve;
823
+
824
+ (Bun as any).serve = mock(() => ({
825
+ stop: mock(),
826
+ port: 3000,
827
+ }));
828
+
829
+ try {
830
+ @Service()
831
+ class TestService extends BaseService {
832
+ getValue() {
833
+ return 'injected-value';
834
+ }
824
835
  }
825
- }
826
836
 
827
- // No @Inject needed - automatic DI via emitDecoratorMetadata
828
- @Controller('')
829
- class TestController extends BaseController {
830
- constructor(private service: TestService) {
831
- super();
832
- }
837
+ // No @Inject needed - automatic DI via emitDecoratorMetadata
838
+ @Controller('')
839
+ class TestController extends BaseController {
840
+ constructor(private service: TestService) {
841
+ super();
842
+ }
833
843
 
834
- getServiceValue() {
835
- return this.service.getValue();
844
+ getServiceValue() {
845
+ return this.service.getValue();
846
+ }
836
847
  }
837
- }
838
848
 
839
- @Module({
840
- controllers: [TestController],
841
- providers: [TestService],
842
- })
843
- class TestModule {}
849
+ @Module({
850
+ controllers: [TestController],
851
+ providers: [TestService],
852
+ })
853
+ class TestModule {}
844
854
 
845
- const app = new OneBunApplication(TestModule, {
846
- loggerLayer: makeMockLoggerLayer(),
847
- });
855
+ const app = new OneBunApplication(TestModule, {
856
+ loggerLayer: makeMockLoggerLayer(),
857
+ });
848
858
 
849
- // Access rootModule to setup and verify DI
850
- const rootModule = (app as any).rootModule;
859
+ // start() creates rootModule and calls setup, triggering dependency injection
860
+ await app.start();
851
861
 
852
- // Setup module to trigger dependency injection
853
- const { Effect } = await import('effect');
854
- await Effect.runPromise(rootModule.setup());
862
+ // Access rootModule after start to verify DI
863
+
864
+ const rootModule = (app as any).rootModule;
855
865
 
856
- // Get controller instance and verify service was injected
857
- const controllerInstance = rootModule.getControllerInstance(TestController) as TestController;
866
+ // Get controller instance and verify service was injected
867
+ const controllerInstance = rootModule.getControllerInstance(TestController) as TestController;
858
868
 
859
- expect(controllerInstance).toBeDefined();
860
- expect(controllerInstance).toBeInstanceOf(TestController);
869
+ expect(controllerInstance).toBeDefined();
870
+ expect(controllerInstance).toBeInstanceOf(TestController);
861
871
 
862
- // Verify the injected service works correctly
863
- expect(controllerInstance.getServiceValue()).toBe('injected-value');
872
+ // Verify the injected service works correctly
873
+ expect(controllerInstance.getServiceValue()).toBe('injected-value');
874
+ } finally {
875
+
876
+ (Bun as any).serve = originalServe;
877
+ }
864
878
  });
865
879
  });
866
880
 
@@ -493,6 +493,18 @@ export const Body = createParamDecorator(ParamType.BODY);
493
493
  // eslint-disable-next-line @typescript-eslint/naming-convention
494
494
  export const Header = createParamDecorator(ParamType.HEADER);
495
495
 
496
+ /**
497
+ * Cookie parameter decorator.
498
+ * Extracts a cookie value by name using BunRequest.cookies (CookieMap).
499
+ * Optional by default, use { required: true } for required cookies.
500
+ * @example \@Cookie('session_id') - optional
501
+ * @example \@Cookie('session_id', { required: true }) - required
502
+ * @example \@Cookie('session_id', schema) - optional with validation
503
+ * @example \@Cookie('session_id', schema, { required: true }) - required with validation
504
+ */
505
+ // eslint-disable-next-line @typescript-eslint/naming-convention
506
+ export const Cookie = createParamDecorator(ParamType.COOKIE);
507
+
496
508
  /**
497
509
  * Request object decorator
498
510
  * @example \@Req()
@@ -33,7 +33,12 @@ import type {
33
33
  BeforeApplicationDestroy,
34
34
  OnApplicationDestroy,
35
35
  } from './';
36
- import type { SseEvent, SseGenerator } from './types';
36
+ import type {
37
+ SseEvent,
38
+ SseGenerator,
39
+ OneBunRequest,
40
+ OneBunResponse,
41
+ } from './types';
37
42
  import type { ServerWebSocket } from 'bun';
38
43
 
39
44
 
@@ -3431,13 +3436,16 @@ import {
3431
3436
  Body,
3432
3437
  Header,
3433
3438
  Req,
3439
+ Cookie,
3434
3440
  Module,
3435
3441
  Service,
3436
3442
  BaseService,
3437
3443
  BaseController,
3438
3444
  UseMiddleware,
3439
3445
  getServiceTag,
3446
+ getControllerMetadata,
3440
3447
  HttpStatusCode,
3448
+ ParamType,
3441
3449
  NotFoundError,
3442
3450
  InternalServerError,
3443
3451
  OneBunBaseError,
@@ -3829,3 +3837,294 @@ describe('SSE (Server-Sent Events) API Documentation (docs/api/controllers.md)',
3829
3837
  });
3830
3838
  });
3831
3839
  });
3840
+
3841
+ // ============================================================================
3842
+ // Cookie, Headers, @Req with OneBunRequest
3843
+ // ============================================================================
3844
+
3845
+ describe('@Cookie Decorator (docs/api/decorators.md)', () => {
3846
+ /**
3847
+ * @source docs/api/decorators.md#cookie
3848
+ */
3849
+ it('should define @Cookie decorator with optional parameter', () => {
3850
+ // From docs: @Cookie('session_id') - optional
3851
+ @Controller('/api')
3852
+ class ApiController extends BaseController {
3853
+ @Get('/me')
3854
+ async getMe(@Cookie('session_id') sessionId?: string) {
3855
+ return { sessionId };
3856
+ }
3857
+ }
3858
+
3859
+ expect(ApiController).toBeDefined();
3860
+ const metadata = getControllerMetadata(ApiController);
3861
+ expect(metadata).toBeDefined();
3862
+ expect(metadata!.routes.length).toBe(1);
3863
+ expect(metadata!.routes[0].params!.length).toBe(1);
3864
+ expect(metadata!.routes[0].params![0].type).toBe(ParamType.COOKIE);
3865
+ expect(metadata!.routes[0].params![0].name).toBe('session_id');
3866
+ expect(metadata!.routes[0].params![0].isRequired).toBe(false);
3867
+ });
3868
+
3869
+ /**
3870
+ * @source docs/api/decorators.md#cookie-required
3871
+ */
3872
+ it('should define @Cookie decorator with required option', () => {
3873
+ // From docs: @Cookie('session_id', { required: true }) - required
3874
+ @Controller('/api')
3875
+ class AuthController extends BaseController {
3876
+ @Get('/protected')
3877
+ async protectedRoute(@Cookie('session_id', { required: true }) sessionId: string) {
3878
+ return { sessionId };
3879
+ }
3880
+ }
3881
+
3882
+ expect(AuthController).toBeDefined();
3883
+ const metadata = getControllerMetadata(AuthController);
3884
+ expect(metadata!.routes[0].params![0].isRequired).toBe(true);
3885
+ });
3886
+
3887
+ /**
3888
+ * @source docs/api/decorators.md#cookie-with-validation
3889
+ */
3890
+ it('should define @Cookie decorator with validation schema', () => {
3891
+ // From docs: @Cookie('session_id', schema) - optional with validation
3892
+ const uuidSchema = type('string');
3893
+
3894
+ @Controller('/api')
3895
+ class ApiController extends BaseController {
3896
+ @Get('/session')
3897
+ async getSession(@Cookie('session_id', uuidSchema) sessionId?: string) {
3898
+ return { sessionId };
3899
+ }
3900
+ }
3901
+
3902
+ expect(ApiController).toBeDefined();
3903
+ const metadata = getControllerMetadata(ApiController);
3904
+ expect(metadata!.routes[0].params![0].schema).toBeDefined();
3905
+ });
3906
+
3907
+ /**
3908
+ * @source docs/api/decorators.md#cookie-combined-example
3909
+ */
3910
+ it('should combine @Cookie with other parameter decorators', () => {
3911
+ // From docs: combining @Cookie, @Param, @Header, @Query
3912
+ @Controller('/api')
3913
+ class CombinedController extends BaseController {
3914
+ @Get('/users/:id')
3915
+ async getUser(
3916
+ @Param('id') id: string,
3917
+ @Query('fields') fields?: string,
3918
+ @Header('Authorization') auth?: string,
3919
+ @Cookie('session') session?: string,
3920
+ ) {
3921
+ return {
3922
+ id, fields, auth, session,
3923
+ };
3924
+ }
3925
+ }
3926
+
3927
+ expect(CombinedController).toBeDefined();
3928
+ const metadata = getControllerMetadata(CombinedController);
3929
+ expect(metadata!.routes[0].params!.length).toBe(4);
3930
+ });
3931
+ });
3932
+
3933
+ describe('@Req() with OneBunRequest (docs/api/decorators.md)', () => {
3934
+ /**
3935
+ * @source docs/api/decorators.md#req-onebunrequest
3936
+ */
3937
+ it('should define @Req() handler with OneBunRequest type', () => {
3938
+ // From docs: @Req() with OneBunRequest type
3939
+ // OneBunRequest extends Request with .cookies (CookieMap) and .params
3940
+ @Controller('/api')
3941
+ class ApiController extends BaseController {
3942
+ @Get('/raw')
3943
+ async handleRaw(@Req() req: OneBunRequest) {
3944
+ const url = new URL(req.url);
3945
+
3946
+ // req.cookies is CookieMap, req.params is available from routes API
3947
+ return { url: url.pathname };
3948
+ }
3949
+ }
3950
+
3951
+ expect(ApiController).toBeDefined();
3952
+ const metadata = getControllerMetadata(ApiController);
3953
+ expect(metadata!.routes[0].params![0].type).toBe(ParamType.REQUEST);
3954
+ });
3955
+
3956
+ /**
3957
+ * @source docs/api/decorators.md#req-cookies-access
3958
+ */
3959
+ it('should define handler accessing cookies via req.cookies', () => {
3960
+ // From docs: reading cookies through @Req()
3961
+ @Controller('/api')
3962
+ class ApiController extends BaseController {
3963
+ @Get('/session')
3964
+ async session(@Req() req: OneBunRequest) {
3965
+ // Access cookies via CookieMap
3966
+ const session = req.cookies.get('session');
3967
+
3968
+ return { session };
3969
+ }
3970
+ }
3971
+
3972
+ expect(ApiController).toBeDefined();
3973
+ });
3974
+ });
3975
+
3976
+ describe('OneBunRequest and OneBunResponse Types (docs/api/decorators.md)', () => {
3977
+ /**
3978
+ * @source docs/api/decorators.md#onebunrequest-type
3979
+ */
3980
+ it('should use OneBunRequest as type alias for BunRequest', () => {
3981
+ // OneBunRequest is an alias for BunRequest
3982
+ // It extends standard Request with .cookies and .params
3983
+ const _check: OneBunRequest extends Request ? true : false = true;
3984
+ expect(_check).toBe(true);
3985
+ });
3986
+
3987
+ /**
3988
+ * @source docs/api/decorators.md#onebunresponse-type
3989
+ */
3990
+ it('should use OneBunResponse as type alias for Response', () => {
3991
+ // OneBunResponse is an alias for Response
3992
+ const response: OneBunResponse = new Response('ok');
3993
+ expect(response).toBeInstanceOf(Response);
3994
+ });
3995
+ });
3996
+
3997
+ describe('Custom Response Headers (docs/api/controllers.md)', () => {
3998
+ /**
3999
+ * @source docs/api/controllers.md#custom-response-headers
4000
+ */
4001
+ it('should define handler returning Response with custom headers', () => {
4002
+ // From docs: returning Response with custom headers
4003
+ @Controller('/api')
4004
+ class ApiController extends BaseController {
4005
+ @Get('/download')
4006
+ async download() {
4007
+ return new Response(JSON.stringify({ data: 'file content' }), {
4008
+ status: 200,
4009
+ headers: {
4010
+ // eslint-disable-next-line @typescript-eslint/naming-convention
4011
+ 'Content-Type': 'application/json',
4012
+ // eslint-disable-next-line @typescript-eslint/naming-convention
4013
+ 'X-Custom-Header': 'custom-value',
4014
+ },
4015
+ });
4016
+ }
4017
+ }
4018
+
4019
+ expect(ApiController).toBeDefined();
4020
+ });
4021
+
4022
+ /**
4023
+ * @source docs/api/controllers.md#set-cookie-header
4024
+ */
4025
+ it('should define handler returning Response with Set-Cookie header', () => {
4026
+ // From docs: setting cookies via Set-Cookie header
4027
+ @Controller('/api')
4028
+ class AuthController extends BaseController {
4029
+ @Post('/login')
4030
+
4031
+ async login(@Body() _body: unknown) {
4032
+ const headers = new Headers();
4033
+ headers.set('Content-Type', 'application/json');
4034
+ headers.append('Set-Cookie', 'session=abc123; Path=/; HttpOnly');
4035
+ headers.append('Set-Cookie', 'theme=dark; Path=/');
4036
+
4037
+ return new Response(JSON.stringify({ loggedIn: true }), {
4038
+ status: 200,
4039
+ headers,
4040
+ });
4041
+ }
4042
+ }
4043
+
4044
+ expect(AuthController).toBeDefined();
4045
+ });
4046
+ });
4047
+
4048
+ describe('Working with Cookies (docs/api/controllers.md)', () => {
4049
+ /**
4050
+ * @source docs/api/controllers.md#reading-cookies-via-decorator
4051
+ */
4052
+ it('should define handler reading cookies via @Cookie decorator', () => {
4053
+ // From docs: reading cookies via @Cookie('name')
4054
+ @Controller('/api')
4055
+ class PrefsController extends BaseController {
4056
+ @Get('/preferences')
4057
+ async getPrefs(
4058
+ @Cookie('theme') theme?: string,
4059
+ @Cookie('lang') lang?: string,
4060
+ ) {
4061
+ return {
4062
+ theme: theme ?? 'light',
4063
+ lang: lang ?? 'en',
4064
+ };
4065
+ }
4066
+ }
4067
+
4068
+ expect(PrefsController).toBeDefined();
4069
+ });
4070
+
4071
+ /**
4072
+ * @source docs/api/controllers.md#reading-cookies-via-req
4073
+ */
4074
+ it('should define handler reading cookies via req.cookies', () => {
4075
+ // From docs: reading cookies through @Req() with req.cookies.get()
4076
+ @Controller('/api')
4077
+ class ApiController extends BaseController {
4078
+ @Get('/session')
4079
+ async session(@Req() req: OneBunRequest) {
4080
+ const session = req.cookies.get('session');
4081
+
4082
+ return { session };
4083
+ }
4084
+ }
4085
+
4086
+ expect(ApiController).toBeDefined();
4087
+ });
4088
+
4089
+ /**
4090
+ * @source docs/api/controllers.md#setting-cookies-via-req
4091
+ */
4092
+ it('should define handler setting cookies via req.cookies', () => {
4093
+ // From docs: setting cookies using req.cookies.set()
4094
+ @Controller('/api')
4095
+ class AuthController extends BaseController {
4096
+ @Post('/login')
4097
+
4098
+ async login(@Req() req: OneBunRequest, @Body() _body: unknown) {
4099
+ // Set cookie via CookieMap
4100
+ req.cookies.set('session', 'new-session-id', {
4101
+ httpOnly: true,
4102
+ path: '/',
4103
+ maxAge: 3600,
4104
+ });
4105
+
4106
+ return { loggedIn: true };
4107
+ }
4108
+ }
4109
+
4110
+ expect(AuthController).toBeDefined();
4111
+ });
4112
+
4113
+ /**
4114
+ * @source docs/api/controllers.md#deleting-cookies-via-req
4115
+ */
4116
+ it('should define handler deleting cookies via req.cookies', () => {
4117
+ // From docs: deleting cookies using req.cookies.delete()
4118
+ @Controller('/api')
4119
+ class AuthController extends BaseController {
4120
+ @Post('/logout')
4121
+ async logout(@Req() req: OneBunRequest) {
4122
+ req.cookies.delete('session');
4123
+
4124
+ return { loggedOut: true };
4125
+ }
4126
+ }
4127
+
4128
+ expect(AuthController).toBeDefined();
4129
+ });
4130
+ });
package/src/index.ts CHANGED
@@ -26,6 +26,8 @@ export { Effect, Layer } from 'effect';
26
26
  export {
27
27
  HttpMethod,
28
28
  ParamType,
29
+ type OneBunRequest,
30
+ type OneBunResponse,
29
31
  type ServiceInterface,
30
32
  type ModuleProviders,
31
33
  type ModuleInstance,
@@ -1,5 +1,9 @@
1
1
  import type { IConfig, OneBunAppConfig } from './config.interface';
2
- import type { SseEvent, SseOptions } from '../types';
2
+ import type {
3
+ OneBunRequest,
4
+ SseEvent,
5
+ SseOptions,
6
+ } from '../types';
3
7
  import type { Context } from 'effect';
4
8
 
5
9
  import type { SyncLogger } from '@onebun/logger';
@@ -101,14 +105,14 @@ export class Controller {
101
105
  /**
102
106
  * Check if request has JSON content type
103
107
  */
104
- protected isJson(req: Request): boolean {
108
+ protected isJson(req: OneBunRequest | Request): boolean {
105
109
  return req.headers.get('content-type')?.includes('application/json') ?? false;
106
110
  }
107
111
 
108
112
  /**
109
113
  * Parse JSON from request body
110
114
  */
111
- protected async parseJson<T = unknown>(req: Request): Promise<T> {
115
+ protected async parseJson<T = unknown>(req: OneBunRequest | Request): Promise<T> {
112
116
  return (await req.json()) as T;
113
117
  }
114
118
 
@@ -50,6 +50,65 @@ import {
50
50
  hasQueueDecorators,
51
51
  } from './index';
52
52
 
53
+ /**
54
+ * @source docs/api/queue.md#setup
55
+ */
56
+ describe('Setup Section Examples (docs/api/queue.md)', () => {
57
+ it('should register controller with queue decorators in module controllers', () => {
58
+ // From docs/api/queue.md: Registering Controllers with Queue Decorators
59
+ class OrderProcessor {
60
+ @Subscribe('orders.created')
61
+ async handleOrderCreated(message: Message<{ orderId: string }>) {
62
+ expect(message.data.orderId).toBeDefined();
63
+ }
64
+
65
+ @Cron(CronExpression.EVERY_HOUR, { pattern: 'cleanup.expired' })
66
+ getCleanupData() {
67
+ return { timestamp: Date.now() };
68
+ }
69
+ }
70
+
71
+ // Verify decorators are registered and auto-discoverable
72
+ expect(hasQueueDecorators(OrderProcessor)).toBe(true);
73
+
74
+ const subscriptions = getSubscribeMetadata(OrderProcessor);
75
+ expect(subscriptions.length).toBe(1);
76
+ expect(subscriptions[0].pattern).toBe('orders.created');
77
+
78
+ const cronJobs = getCronMetadata(OrderProcessor);
79
+ expect(cronJobs.length).toBe(1);
80
+ });
81
+
82
+ it('should support error handling with manual ack mode', () => {
83
+ // From docs/api/queue.md: Error Handling in Handlers
84
+ class ErrorHandlingProcessor {
85
+ @Subscribe('orders.created', {
86
+ ackMode: 'manual',
87
+ retry: { attempts: 3, backoff: 'exponential', delay: 1000 },
88
+ })
89
+ async handleOrder(message: Message<{ orderId: string }>) {
90
+ try {
91
+ // process order
92
+ await message.ack();
93
+ } catch {
94
+ if (message.attempt && message.attempt >= (message.maxAttempts || 3)) {
95
+ await message.ack();
96
+ } else {
97
+ await message.nack(true);
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ const subscriptions = getSubscribeMetadata(ErrorHandlingProcessor);
104
+ expect(subscriptions.length).toBe(1);
105
+ expect(subscriptions[0].options?.ackMode).toBe('manual');
106
+ expect(subscriptions[0].options?.retry?.attempts).toBe(3);
107
+ expect(subscriptions[0].options?.retry?.backoff).toBe('exponential');
108
+ expect(subscriptions[0].options?.retry?.delay).toBe(1000);
109
+ });
110
+ });
111
+
53
112
  /**
54
113
  * @source docs/api/queue.md#quick-start
55
114
  */
@@ -86,6 +145,33 @@ describe('Quick Start Example (docs/api/queue.md)', () => {
86
145
  expect(cronJobs[0].expression).toBe(CronExpression.EVERY_HOUR);
87
146
  expect(cronJobs[0].options.pattern).toBe('cleanup.expired');
88
147
  });
148
+
149
+ it('should define service with interval decorator', () => {
150
+ // From docs/api/queue.md: Quick Start - Interval example
151
+ class EventProcessor {
152
+ @Subscribe('orders.created')
153
+ async handleOrderCreated(message: Message<{ orderId: number }>) {
154
+ expect(message.data.orderId).toBeDefined();
155
+ }
156
+
157
+ @Cron(CronExpression.EVERY_HOUR, { pattern: 'cleanup.expired' })
158
+ getCleanupData() {
159
+ return { timestamp: Date.now() };
160
+ }
161
+
162
+ @Interval(30000, { pattern: 'metrics.collect' })
163
+ getMetricsData() {
164
+ return { cpu: process.cpuUsage() };
165
+ }
166
+ }
167
+
168
+ expect(hasQueueDecorators(EventProcessor)).toBe(true);
169
+
170
+ const intervals = getIntervalMetadata(EventProcessor);
171
+ expect(intervals.length).toBe(1);
172
+ expect(intervals[0].milliseconds).toBe(30000);
173
+ expect(intervals[0].options.pattern).toBe('metrics.collect');
174
+ });
89
175
  });
90
176
 
91
177
  /**
@@ -138,7 +138,7 @@ describe('createServiceClient', () => {
138
138
  }),
139
139
  ),
140
140
  );
141
- globalThis.fetch = mockFetch;
141
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
142
142
  });
143
143
 
144
144
  afterEach(() => {
package/src/types.ts CHANGED
@@ -3,6 +3,21 @@ import type { Effect, Layer } from 'effect';
3
3
 
4
4
  import type { Logger, LoggerOptions } from '@onebun/logger';
5
5
 
6
+ /**
7
+ * HTTP Request type used in OneBun controllers.
8
+ * Extends standard Web API Request with:
9
+ * - `.cookies` (CookieMap) for reading/setting cookies
10
+ * - `.params` for accessing route parameters
11
+ * @see https://bun.sh/docs/api/http#bunsrequest
12
+ */
13
+ export type OneBunRequest = import('bun').BunRequest;
14
+
15
+ /**
16
+ * HTTP Response type used in OneBun controllers.
17
+ * Standard Web API Response.
18
+ */
19
+ export type OneBunResponse = Response;
20
+
6
21
  /**
7
22
  * Base interface for all OneBun services
8
23
  */
@@ -505,18 +520,19 @@ export enum ParamType {
505
520
  QUERY = 'query',
506
521
  BODY = 'body',
507
522
  HEADER = 'header',
523
+ COOKIE = 'cookie',
508
524
  REQUEST = 'request',
509
525
  RESPONSE = 'response',
510
526
  }
511
527
 
512
528
  /**
513
- * Options for parameter decorators (@Query, @Header, @Body, etc.)
529
+ * Options for parameter decorators (@Query, @Header, @Cookie, @Body, etc.)
514
530
  */
515
531
  export interface ParamDecoratorOptions {
516
532
  /**
517
533
  * Whether the parameter is required
518
534
  * - @Param: always true (OpenAPI spec requirement)
519
- * - @Query, @Header: false by default
535
+ * - @Query, @Header, @Cookie: false by default
520
536
  * - @Body: determined from schema (accepts undefined = optional)
521
537
  */
522
538
  required?: boolean;
@@ -47,7 +47,6 @@ describe('Validation Schemas', () => {
47
47
  test('should create an optional schema that accepts undefined', () => {
48
48
  const schema = optionalSchema(stringSchema());
49
49
  expect(schema('test')).toBe('test');
50
- // @ts-expect-error - Testing that optional schema accepts undefined
51
50
  expect(schema(undefined)).toBe(undefined);
52
51
  const invalidResult = schema(123);
53
52
  expect(invalidResult instanceof type.errors).toBe(true);
@@ -56,7 +55,6 @@ describe('Validation Schemas', () => {
56
55
  test('should work with number schema', () => {
57
56
  const schema = optionalSchema(numberSchema());
58
57
  expect(schema(42)).toBe(42);
59
- // @ts-expect-error - Testing that optional schema accepts undefined
60
58
  expect(schema(undefined)).toBe(undefined);
61
59
  const invalidResult = schema('test');
62
60
  expect(invalidResult instanceof type.errors).toBe(true);
@@ -49,7 +49,7 @@ export abstract class BaseWebSocketGateway {
49
49
  protected storage: WsStorageAdapter | null = null;
50
50
 
51
51
  /** Bun server reference */
52
- protected server: Server | null = null;
52
+ protected server: Server<WsClientData> | null = null;
53
53
 
54
54
  /** Unique instance ID (for multi-instance setups) */
55
55
  protected instanceId: string = crypto.randomUUID();
@@ -63,7 +63,7 @@ export abstract class BaseWebSocketGateway {
63
63
  * Called internally by the framework
64
64
  * @internal
65
65
  */
66
- _initialize(storage: WsStorageAdapter, server: Server): void {
66
+ _initialize(storage: WsStorageAdapter, server: Server<WsClientData>): void {
67
67
  this.storage = storage;
68
68
  this.server = server;
69
69