@krisanalfa/bunest-adapter 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -15,10 +15,12 @@ This project provides a native Bun adapter for NestJS, allowing developers to le
15
15
  - [Validation](#validation)
16
16
  - [File Uploads](#file-uploads)
17
17
  - [Streaming Responses](#streaming-responses)
18
+ - [Server-Sent Events (SSE)](#server-sent-events-sse)
18
19
  - [Versioning](#versioning)
19
20
  - [CORS](#cors)
20
21
  - [Cookies](#cookies)
21
22
  - [Popular Express Middleware](#popular-express-middleware)
23
+ - [Static Assets](#static-assets)
22
24
  - [Bun File API Support](#bun-file-api-support)
23
25
  - [BunFileInterceptor](#bunfileinterceptor)
24
26
  - [WebSocket Support](#websocket-support)
@@ -50,7 +52,7 @@ This project provides a native Bun adapter for NestJS, allowing developers to le
50
52
  Easy to set up and use Bun as the underlying HTTP server for your NestJS applications.
51
53
 
52
54
  ```ts
53
- import { BunAdapter } from "@krisanalfa/bunest-adapter";
55
+ import { BunAdapter, NestBunApplication } from "@krisanalfa/bunest-adapter";
54
56
  import { Logger } from "@nestjs/common";
55
57
  import { NestFactory } from "@nestjs/core";
56
58
  import { Server } from "bun";
@@ -58,10 +60,10 @@ import { Server } from "bun";
58
60
  import { AppModule } from "./app.module.js";
59
61
 
60
62
  async function main() {
61
- const app = await NestFactory.create(AppModule, new BunAdapter());
63
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
62
64
  await app.listen(3000);
63
- const server = app.getHttpAdapter().getHttpServer() as Server<unknown>;
64
- Logger.log(`Server started on ${server.url.toString()}`, "NestApplication");
65
+ const server = app.getHttpServer().getBunServer()
66
+ Logger.log(`Server started on ${server?.url.toString() ?? 'http://localhost:3000'}`, 'NestApplication')
65
67
  }
66
68
 
67
69
  await main();
@@ -375,6 +377,67 @@ class FilesController {
375
377
  }
376
378
  ```
377
379
 
380
+ #### Server-Sent Events (SSE)
381
+
382
+ Full support for [Server-Sent Events](https://docs.nestjs.com/techniques/server-sent-events) using the `@Sse()` decorator. SSE allows servers to push real-time updates to clients over HTTP:
383
+
384
+ ```ts
385
+ import { Controller, Sse, MessageEvent } from '@nestjs/common';
386
+ import { Observable, interval, map } from 'rxjs';
387
+
388
+ @Controller()
389
+ class EventsController {
390
+ @Sse('/sse')
391
+ sendEvents(): Observable<MessageEvent> {
392
+ return interval(1000).pipe(
393
+ map(num => ({
394
+ data: `SSE message ${num.toString()}`,
395
+ })),
396
+ );
397
+ }
398
+ }
399
+ ```
400
+
401
+ **Client Connection Example:**
402
+
403
+ ```ts
404
+ const eventSource = new EventSource('http://localhost:3000/sse');
405
+
406
+ eventSource.onopen = () => {
407
+ console.log('SSE connection opened');
408
+ };
409
+
410
+ eventSource.onmessage = (event) => {
411
+ console.log('Received:', event.data); // "SSE message 0", "SSE message 1", etc.
412
+ };
413
+
414
+ eventSource.onerror = (error) => {
415
+ console.error('SSE error:', error);
416
+ eventSource.close();
417
+ };
418
+
419
+ // Close the connection when done
420
+ // eventSource.close();
421
+ ```
422
+
423
+ **For HTTPS/Secure Connections:**
424
+
425
+ ```ts
426
+ import { EventSource } from 'eventsource'; // npm package for Node.js
427
+
428
+ const eventSource = new EventSource('https://localhost:3000/sse', {
429
+ fetch: (url, init) => fetch(url, {
430
+ ...init,
431
+ tls: { rejectUnauthorized: false }, // For self-signed certificates
432
+ }),
433
+ });
434
+
435
+ eventSource.onmessage = (event) => {
436
+ console.log('Received:', event.data);
437
+ };
438
+ ```
439
+
440
+
378
441
  #### Versioning
379
442
 
380
443
  Full API [versioning](https://docs.nestjs.com/techniques/versioning) support (URI, Header, Media Type, Custom):
@@ -433,7 +496,7 @@ app.enableCors((req: BunRequest, callback) => {
433
496
  You can also use NestJS's `CorsOptions` type for static configuration.
434
497
 
435
498
  ```ts
436
- const app = await NestFactory.create(AppModule, new BunAdapter(), {
499
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter(), {
437
500
  cors: {
438
501
  origin: "https://example.com",
439
502
  methods: ["GET", "POST", "PUT"],
@@ -473,7 +536,7 @@ Compatible with popular Express middleware:
473
536
  ```ts
474
537
  import helmet from "helmet";
475
538
 
476
- const app = await NestFactory.create(AppModule, new BunAdapter());
539
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
477
540
  app.use(helmet());
478
541
  ```
479
542
 
@@ -481,7 +544,65 @@ Tested and working with:
481
544
 
482
545
  - `helmet` - Security headers
483
546
  - `cors` - CORS handling
484
- - And most other Express-compatible middleware
547
+ - `@thallesp/nestjs-better-auth` - `better-auth` middleware
548
+ - `express-session` - Session management
549
+
550
+ #### Static Assets
551
+
552
+ Serve static files from your NestJS application using Bun's native file serving capabilities. The adapter supports two distinct modes:
553
+
554
+ **File Routes (Default)** - Reads files from the filesystem on each request, supports range requests, respects middlewares, and provides full HTTP feature compatibility:
555
+
556
+ ```ts
557
+ import { join } from 'path';
558
+
559
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
560
+
561
+ // Serve static assets using file routes (default)
562
+ app.useStaticAssets(join(__dirname, 'public'));
563
+
564
+ // Or explicitly set useStatic to false
565
+ app.useStaticAssets(join(__dirname, 'public'), { useStatic: false });
566
+
567
+ await app.listen(3000);
568
+
569
+ // Files in 'public' directory are now accessible:
570
+ // public/index.html -> http://localhost:3000/index.html
571
+ // public/css/style.css -> http://localhost:3000/css/style.css
572
+ // public/images/logo.png -> http://localhost:3000/images/logo.png
573
+ ```
574
+
575
+ > Note: Even if the file routes read the files from the filesystem on each request, you still need to make sure that Bun has access to the files right before you call `app.listen()`. The adapter reads the directory structure and prepares the routes at that time. If you need different behavior (e.g., dynamic files), consider using a custom controller to serve those files.
576
+
577
+ **Static Routes** - Serves files directly from memory for maximum performance, but with some limitations (no range requests, doesn't respect middlewares):
578
+
579
+ ```ts
580
+ import { join } from 'path';
581
+
582
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
583
+
584
+ // Serve static assets using static routes (faster, but with limitations)
585
+ app.useStaticAssets(join(__dirname, 'public'), { useStatic: true });
586
+
587
+ await app.listen(3000);
588
+ ```
589
+
590
+ **With CORS Support:**
591
+
592
+ ```ts
593
+ const app = await NestFactory.create<NestBunApplication>(
594
+ AppModule,
595
+ new BunAdapter(),
596
+ { cors: true }
597
+ );
598
+
599
+ // Static assets will respect CORS settings when using file routes
600
+ app.useStaticAssets(join(__dirname, 'public'), { useStatic: false });
601
+ ```
602
+
603
+ **Choosing Between Modes:**
604
+
605
+ For more details, see [Bun's documentation on file responses vs static responses](https://bun.sh/docs/runtime/http/routing#file-responses-vs-static-responses).
485
606
 
486
607
  ### WebSocket Support
487
608
 
@@ -523,7 +644,7 @@ class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
523
644
  }
524
645
 
525
646
  // Enable WebSocket support in your application
526
- const app = await NestFactory.create(AppModule, new BunAdapter());
647
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
527
648
  app.useWebSocketAdapter(new BunWsAdapter(app));
528
649
  await app.listen(3000);
529
650
  ```
@@ -715,10 +836,10 @@ The Bun adapter supports secure WebSocket connections (WSS) using TLS/SSL certif
715
836
  **Using BunAdapter constructor options:**
716
837
 
717
838
  ```ts
718
- import { BunAdapter, BunWsAdapter } from "@krisanalfa/bunest-adapter";
839
+ import { BunAdapter, BunWsAdapter, NestBunApplication } from "@krisanalfa/bunest-adapter";
719
840
  import { NestFactory } from "@nestjs/core";
720
841
 
721
- const app = await NestFactory.create(
842
+ const app = await NestFactory.create<NestBunApplication>(
722
843
  AppModule,
723
844
  new BunAdapter({
724
845
  tls: {
@@ -738,10 +859,10 @@ await app.listen(3000);
738
859
  **Using NestFactory.create httpsOptions:**
739
860
 
740
861
  ```ts
741
- import { BunAdapter, BunWsAdapter } from "@krisanalfa/bunest-adapter";
862
+ import { BunAdapter, BunWsAdapter, NestBunApplication } from "@krisanalfa/bunest-adapter";
742
863
  import { NestFactory } from "@nestjs/core";
743
864
 
744
- const app = await NestFactory.create(AppModule, new BunAdapter(), {
865
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter(), {
745
866
  httpsOptions: {
746
867
  cert: Bun.file("/path/to/cert.pem"),
747
868
  key: Bun.file("/path/to/key.pem"),
@@ -757,10 +878,10 @@ await app.listen(3000);
757
878
  You can also run secure WebSocket servers over Unix sockets:
758
879
 
759
880
  ```ts
760
- import { BunAdapter, BunWsAdapter } from "@krisanalfa/bunest-adapter";
881
+ import { BunAdapter, BunWsAdapter, NestBunApplication } from "@krisanalfa/bunest-adapter";
761
882
  import { NestFactory } from "@nestjs/core";
762
883
 
763
- const app = await NestFactory.create(
884
+ const app = await NestFactory.create<NestBunApplication>(
764
885
  AppModule,
765
886
  new BunAdapter({
766
887
  tls: {
@@ -815,7 +936,7 @@ class ChatGateway {
815
936
  }
816
937
 
817
938
  // WebSocket will be available on the same port as HTTP
818
- const app = await NestFactory.create(AppModule, new BunAdapter());
939
+ const app = await NestFactory.create<NestBunApplication>(AppModule, new BunAdapter());
819
940
  app.useWebSocketAdapter(new BunWsAdapter(app));
820
941
  await app.listen(3000); // Both HTTP and WebSocket use port 3000
821
942
  ```
@@ -881,7 +1002,7 @@ You can run your NestJS application with HTTPS using two approaches:
881
1002
  #### Using Bun's built-in HTTPS support (recommended)
882
1003
 
883
1004
  ```ts
884
- const app = await NestFactory.create(
1005
+ const app = await NestFactory.create<NestBunApplication>(
885
1006
  AppModule,
886
1007
  new BunAdapter({
887
1008
  tls: {
@@ -895,7 +1016,7 @@ const app = await NestFactory.create(
895
1016
  #### Using NestJS App Factory HTTPS options
896
1017
 
897
1018
  ```ts
898
- const app = await NestFactory.create(
1019
+ const app = await NestFactory.create<NestBunApplication>(
899
1020
  AppModule,
900
1021
  new BunAdapter(/* leave it empty */),
901
1022
  {
@@ -1251,6 +1372,23 @@ oha -c 125 -n 1000000 --no-tui "http://127.0.0.1:3000/"
1251
1372
 
1252
1373
  > **Pure Bun** is the fastest at **80,743 req/s**. **Nest + Bun + Native Bun Adapter** achieves **~86%** of Pure Bun's performance while providing full NestJS features, and is **~5x faster** than Nest + Node + Express. Compared to Bun with Express adapter, the native Bun adapter is **~1.6x faster**.
1253
1374
 
1375
+ Bonus if you use Unix sockets:
1376
+ ```
1377
+ Summary:
1378
+ Success rate: 100.00%
1379
+ Total: 8298.2243 ms
1380
+ Slowest: 5.2326 ms
1381
+ Fastest: 0.2857 ms
1382
+ Average: 1.0361 ms
1383
+ Requests/sec: 120507.7092
1384
+
1385
+ Total data: 21.93 MiB
1386
+ Size/request: 23 B
1387
+ Size/sec: 2.64 MiB
1388
+ ```
1389
+
1390
+ As you can see, using Unix sockets boosts the performance further to **120,508 req/s**, which is **~1.5x faster** than TCP. Since Bun `fetch` supports Unix sockets, you can leverage this for inter-process communication on the same machine.
1391
+
1254
1392
  ### WebSocket Benchmark
1255
1393
 
1256
1394
  WebSocket benchmarks run using the custom benchmark script in `benchmarks/ws.benchmark.ts`.
@@ -1321,7 +1459,7 @@ Contributions are welcome! Please open issues or submit pull requests for bug fi
1321
1459
  ## Future Plans
1322
1460
 
1323
1461
  - Enhanced trusted proxy configuration for host header handling
1324
- - Additional performance optimizations and benchmarks
1462
+ - Improved documentation and examples
1325
1463
  - Release automation via CI/CD pipelines
1326
1464
 
1327
1465
  ## License
@@ -1,64 +1,20 @@
1
1
  import { CorsOptions, CorsOptionsDelegate } from '@nestjs/common/interfaces/external/cors-options.interface.js';
2
2
  import { ErrorHandler, RequestHandler } from '@nestjs/common/interfaces/index.js';
3
- import { Server } from 'bun';
4
3
  import { NestApplicationOptions, RequestMethod, VersioningOptions } from '@nestjs/common';
4
+ import { Server } from 'bun';
5
5
  import { AbstractHttpAdapter } from '@nestjs/core';
6
6
  import { VersionValue } from '@nestjs/common/interfaces/version-options.interface.js';
7
- import { ServerOptions } from './internal.types.js';
7
+ import { BunStaticAssetsOptions, BunWsClientData, ServerOptions } from './bun.internal.types.js';
8
8
  import { BunPreflightHttpServer } from './bun.preflight-http-server.js';
9
9
  import { BunRequest } from './bun.request.js';
10
10
  import { BunResponse } from './bun.response.js';
11
+ import { BunServerInstance } from './bun.server-instance.js';
11
12
  export declare class BunAdapter extends AbstractHttpAdapter<Server<unknown>, BunRequest, BunResponse> {
12
- protected bunServeOptions: ServerOptions;
13
+ protected bunServeOptions: ServerOptions<BunWsClientData>;
13
14
  private readonly logger;
14
- private readonly middlewareEngine;
15
- private useVersioning;
16
- private readonly routes;
17
- private readonly routeHandlers;
18
- private notFoundHandler;
19
- private readonly wsHandlers;
20
- private readonly wsMiddlewareEngine;
21
- private wsOptions;
22
- private useWs;
23
- private useWsCors;
24
- private wsCorsHeaders?;
25
- constructor(bunServeOptions?: ServerOptions);
26
- use(middleware: RequestHandler<BunRequest, BunResponse>): void;
27
- private createHttpMethodHandler;
28
- get(handler: RequestHandler<BunRequest, BunResponse>): void;
29
- get(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
30
- post(handler: RequestHandler<BunRequest, BunResponse>): void;
31
- post(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
32
- put(handler: RequestHandler<BunRequest, BunResponse>): void;
33
- put(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
34
- patch(handler: RequestHandler<BunRequest, BunResponse>): void;
35
- patch(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
36
- delete(handler: RequestHandler<BunRequest, BunResponse>): void;
37
- delete(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
38
- head(handler: RequestHandler<BunRequest, BunResponse>): void;
39
- head(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
40
- options(handler: RequestHandler<BunRequest, BunResponse>): void;
41
- options(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
42
- private createUnsupportedMethod;
43
- all(handler: RequestHandler<BunRequest, BunResponse>): void;
44
- all(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
45
- propfind(handler: RequestHandler<BunRequest, BunResponse>): void;
46
- propfind(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
47
- proppatch(handler: RequestHandler<BunRequest, BunResponse>): void;
48
- proppatch(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
49
- mkcol(handler: RequestHandler<BunRequest, BunResponse>): void;
50
- mkcol(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
51
- copy(handler: RequestHandler<BunRequest, BunResponse>): void;
52
- copy(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
53
- move(handler: RequestHandler<BunRequest, BunResponse>): void;
54
- move(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
55
- lock(handler: RequestHandler<BunRequest, BunResponse>): void;
56
- lock(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
57
- unlock(handler: RequestHandler<BunRequest, BunResponse>): void;
58
- unlock(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
59
- search(handler: RequestHandler<BunRequest, BunResponse>): void;
60
- search(path: unknown, handler: RequestHandler<BunRequest, BunResponse>): void;
61
- useStaticAssets(...args: unknown[]): void;
15
+ protected instance: BunServerInstance;
16
+ constructor(bunServeOptions?: ServerOptions<BunWsClientData>);
17
+ useStaticAssets(path: string, options?: BunStaticAssetsOptions): void;
62
18
  setViewEngine(engine: string): void;
63
19
  render(response: unknown, view: string, options: unknown): void;
64
20
  close(): Promise<void>;
@@ -94,20 +50,5 @@ export declare class BunAdapter extends AbstractHttpAdapter<Server<unknown>, Bun
94
50
  * @param callback Optional callback to invoke once the server is listening.
95
51
  */
96
52
  listen(port: string | number, hostname: string, callback?: () => void): void;
97
- private static isNumericPort;
98
- private static omitKeys;
99
- private isWebSocketUpgradeRequest;
100
- private handleWebSocketCors;
101
- private upgradeWebSocket;
102
- private setupWebSocketIfNeeded;
103
- private createServer;
104
- private delegateRouteHandler;
105
- private ensureRouteExists;
106
- private prepareRequestHandler;
107
- private createRouteFetchHandler;
108
- private createVersioningHandlers;
109
- private executeHandlerChain;
110
- private createChainedHandlerForVersioningResolution;
111
- private mapRequestMethodToString;
112
- private parseRouteHandler;
53
+ private configureTls;
113
54
  }
@@ -0,0 +1,53 @@
1
+ import { CorsOptions, CorsOptionsDelegate } from '@nestjs/common/interfaces/external/cors-options.interface.js';
2
+ import { Serve, Server, ServerWebSocket, WebSocketHandler } from 'bun';
3
+ import { INestApplication } from '@nestjs/common';
4
+ import { BunPreflightHttpServer } from './bun.preflight-http-server.js';
5
+ import { BunRequest } from './bun.request.js';
6
+ export interface WsOptions extends Pick<WebSocketHandler<unknown>, 'maxPayloadLength' | 'idleTimeout' | 'backpressureLimit' | 'closeOnBackpressureLimit' | 'sendPings' | 'publishToSelf' | 'perMessageDeflate'> {
7
+ cors?: true | CorsOptions | CorsOptionsDelegate<BunRequest>;
8
+ clientDataFactory?: (req: BunRequest) => unknown;
9
+ }
10
+ export type ServerOptions<TWebSocketData = unknown> = Pick<Serve.Options<TWebSocketData>, 'development' | 'maxRequestBodySize' | 'idleTimeout' | 'id' | 'tls' | 'websocket' | 'port' | 'hostname'>;
11
+ export type WsData = string | Buffer | ArrayBuffer | Buffer[];
12
+ export interface WsHandlers {
13
+ onOpen: ((ws: ServerWebSocket<unknown>) => void) | undefined;
14
+ onMessage: ((ws: ServerWebSocket<unknown>, message: WsData, server: Server<unknown>) => void) | undefined;
15
+ onClose: ((ws: ServerWebSocket<unknown>, code: number, reason: string) => void) | undefined;
16
+ }
17
+ export interface BunWsClientData {
18
+ /** Called when a message is received - matches bun.adapter.ts onMessageInternal */
19
+ onMessageInternal?: (message: WsData) => void;
20
+ /** Called when the connection closes - matches bun.adapter.ts onCloseInternal */
21
+ onCloseInternal?: () => void;
22
+ /** Called by NestJS for disconnect handling */
23
+ onDisconnect?: (ws: ServerWebSocket<unknown>) => void;
24
+ }
25
+ export interface BunStaticAssetsOptions {
26
+ /**
27
+ * Enable static assets serving.
28
+ *
29
+ * Bun has two distict modes for serving static assets:
30
+ * 1. Static routes
31
+ * 2. File routes
32
+ *
33
+ * If you set `useStatic: true`, Bun will use static routes for serving assets.
34
+ * This approach is generally faster for serving static files, as it serves
35
+ * files directly from memory. However, it comes with some limitations, such as
36
+ * lack of support for certain features like range requests and directory indexing.
37
+ * On top of that, static routes didn't respect middlewares due to Bun's internal design.
38
+ *
39
+ * On the other hand, if you set `useStatic: false` (the default behavior),
40
+ * Bun will use file routes, which read files from the filesystem on each request.
41
+ * This method supports a wider range of features, including range requests, and respects
42
+ * middlewares. However, it may be slightly slower than static routes due to
43
+ * filesystem access on each request.
44
+ *
45
+ * @see https://bun.com/docs/runtime/http/routing#file-responses-vs-static-responses
46
+ * @defaults false Use file routes by default.
47
+ */
48
+ useStatic?: boolean;
49
+ }
50
+ export interface NestBunApplication extends INestApplication<BunPreflightHttpServer> {
51
+ useStaticAssets(path: string, options?: BunStaticAssetsOptions): void;
52
+ enableCors(options?: CorsOptions | CorsOptionsDelegate<BunRequest>): void;
53
+ }
@@ -1,16 +1,7 @@
1
1
  import { Server, ServerWebSocket } from 'bun';
2
2
  import { BaseWsInstance } from '@nestjs/websockets';
3
- import { ServerOptions, WsOptions } from './internal.types.js';
4
- interface BunHttpAdapter {
5
- setWsOptions(options: WsOptions): void;
6
- getBunHttpServerInstance(): Server<unknown>;
7
- getWsHandlers(): {
8
- onOpen: ((ws: ServerWebSocket<unknown>) => void) | undefined;
9
- onMessage: ((ws: ServerWebSocket<unknown>, message: string | ArrayBuffer | Buffer | Buffer[], server: Server<unknown>) => void) | undefined;
10
- onClose: ((ws: ServerWebSocket<unknown>, code: number, reason: string) => void) | undefined;
11
- };
12
- getBunServerOptions(): Pick<ServerOptions, 'port' | 'hostname'>;
13
- }
3
+ import { WsData, WsOptions } from './bun.internal.types.js';
4
+ import { BunServerInstance } from './bun.server-instance.js';
14
5
  /**
15
6
  * Bun HTTP server placeholder used before the actual server instance is created.
16
7
  * This class provides compatibility methods expected by NestJS framework.
@@ -20,8 +11,8 @@ interface BunHttpAdapter {
20
11
  * the server creation until NestJS calls the listen method.
21
12
  */
22
13
  export declare class BunPreflightHttpServer implements BaseWsInstance {
23
- private readonly adapter;
24
- constructor(adapter: BunHttpAdapter);
14
+ private readonly serverInstance;
15
+ constructor(serverInstance: BunServerInstance);
25
16
  on(event: string, callback: Function): void;
26
17
  /**
27
18
  * NestJS compatibility methods
@@ -38,25 +29,16 @@ export declare class BunPreflightHttpServer implements BaseWsInstance {
38
29
  */
39
30
  stop(force?: boolean): Promise<void>;
40
31
  address(): {
41
- address: "0.0.0.0" | "127.0.0.1" | "localhost" | (string & {});
42
- port: string | number;
43
- } | {
44
- address: string | undefined;
45
- port: number | undefined;
32
+ address: string;
33
+ port: number;
46
34
  };
47
35
  setWsOptions(options: WsOptions): void;
48
36
  registerWsOpenHandler(handler: (ws: ServerWebSocket<unknown>) => void): void;
49
- registerWsMessageHandler(handler: (ws: ServerWebSocket<unknown>, message: string | ArrayBuffer | Buffer | Buffer[], server: Server<unknown>) => void): void;
37
+ registerWsMessageHandler(handler: (ws: ServerWebSocket<unknown>, message: WsData, server: Server<unknown>) => void): void;
50
38
  registerWsCloseHandler(handler: (ws: ServerWebSocket<unknown>, code: number, reason: string) => void): void;
51
- getWsHandlers(): {
52
- onOpen: ((ws: ServerWebSocket<unknown>) => void) | undefined;
53
- onMessage: ((ws: ServerWebSocket<unknown>, message: string | ArrayBuffer | Buffer | Buffer[], server: Server<unknown>) => void) | undefined;
54
- onClose: ((ws: ServerWebSocket<unknown>, code: number, reason: string) => void) | undefined;
55
- };
56
- getBunServer(): Server<unknown>;
39
+ getBunServer(): Server<unknown> | null;
57
40
  /**
58
41
  * Proxy method for WebSocket server close
59
42
  */
60
43
  close(): Promise<void>;
61
44
  }
62
- export {};
@@ -3,6 +3,15 @@ import { ParsedQs } from 'qs';
3
3
  type HeadersProxy = Record<string, string> & {
4
4
  get: (key: string) => string | null;
5
5
  };
6
+ interface Connection {
7
+ encrypted: boolean;
8
+ }
9
+ interface TcpSocket {
10
+ encrypted: boolean;
11
+ setKeepAlive: (enable?: boolean, initialDelay?: number) => void;
12
+ setNoDelay: (noDelay?: boolean) => void;
13
+ setTimeout: (timeout: number, callback?: () => void) => void;
14
+ }
6
15
  /**
7
16
  * A high-performance request wrapper for Bun's native request object.
8
17
  * Provides lazy parsing and caching for optimal performance in NestJS applications.
@@ -26,20 +35,23 @@ export declare class BunRequest {
26
35
  private _file;
27
36
  private _files;
28
37
  private _settings;
29
- private readonly _url;
38
+ private _connection;
39
+ private _socket;
40
+ private _url;
30
41
  private readonly _parsedUrl;
31
42
  readonly method: string;
32
43
  readonly params: Record<string, string>;
33
44
  constructor(nativeRequest: NativeRequest);
45
+ /**
46
+ * Gets a mock connection object for compatibility with Node.js middleware.
47
+ * Some middleware (like express-session) check req.connection.encrypted to determine if the connection is HTTPS.
48
+ */
49
+ get connection(): Connection;
34
50
  /**
35
51
  * Gets a mock socket object for compatibility with Node.js middleware.
36
52
  * Some middleware (like Better Auth) check req.socket.encrypted to determine if the connection is HTTPS.
37
- *
38
- * @returns A mock socket object with encrypted property
39
53
  */
40
- get socket(): {
41
- encrypted: boolean;
42
- };
54
+ get socket(): TcpSocket;
43
55
  /**
44
56
  * Gets the URL path and query string of the request.
45
57
  * Returns the pathname + search params for Node.js/Express compatibility.
@@ -235,7 +247,7 @@ export declare class BunRequest {
235
247
  * console.log(user); // { id: 1, name: 'John' }
236
248
  * ```
237
249
  */
238
- get(key: string): unknown;
250
+ get<T>(key: string): T | undefined;
239
251
  /**
240
252
  * Sets a custom setting/property in the request.
241
253
  * Useful for passing data between middleware and handlers.
@@ -358,5 +370,42 @@ export declare class BunRequest {
358
370
  * ```
359
371
  */
360
372
  clone(): BunRequest;
373
+ /**
374
+ * Stub method for Node.js EventEmitter compatibility.
375
+ * This is a no-op method provided for compatibility with Node.js HTTP request objects.
376
+ * Required for SSE and other streaming scenarios where NestJS listens for request events.
377
+ *
378
+ * @param event - The event name
379
+ * @param listener - The event listener function
380
+ * @returns This request object for chaining
381
+ */
382
+ on(event: string, listener: (...args: unknown[]) => void): this;
383
+ /**
384
+ * Stub method for Node.js EventEmitter compatibility.
385
+ * This is a no-op method provided for compatibility with Node.js HTTP request objects.
386
+ *
387
+ * @param event - The event name
388
+ * @param listener - The event listener function
389
+ * @returns This request object for chaining
390
+ */
391
+ once(event: string, listener: (...args: unknown[]) => void): this;
392
+ /**
393
+ * Stub method for Node.js EventEmitter compatibility.
394
+ * This is a no-op method provided for compatibility with Node.js HTTP request objects.
395
+ *
396
+ * @param event - The event name
397
+ * @param listener - The event listener function
398
+ * @returns This request object for chaining
399
+ */
400
+ off(event: string, listener: (...args: unknown[]) => void): this;
401
+ /**
402
+ * Stub method for Node.js EventEmitter compatibility.
403
+ * This is a no-op method provided for compatibility with Node.js HTTP request objects.
404
+ *
405
+ * @param event - The event name
406
+ * @param args - Event arguments
407
+ * @returns True to indicate the event was handled
408
+ */
409
+ emit(event: string, ...args: unknown[]): boolean;
361
410
  }
362
411
  export {};
@@ -18,11 +18,18 @@ export declare class BunResponse {
18
18
  private readonly response;
19
19
  private readonly cookieMap;
20
20
  private static readonly textDecoder;
21
+ /**
22
+ * Property for Node.js Writable stream compatibility.
23
+ * Indicates this object can be written to.
24
+ */
25
+ readonly writable = true;
21
26
  private headers;
22
27
  private statusCode;
23
28
  private ended;
24
29
  private cookieHeaders;
25
30
  private chunks;
31
+ private streamWriter;
32
+ private textEncoder;
26
33
  constructor();
27
34
  private get headersMap();
28
35
  /**
@@ -205,6 +212,21 @@ export declare class BunResponse {
205
212
  * @returns This response object for chaining
206
213
  */
207
214
  once(event: string, listener: (...args: unknown[]) => void): this;
215
+ /**
216
+ * Stub method for Node.js EventEmitter compatibility.
217
+ * This is a no-op method provided for compatibility with Node.js streams and HTTP response objects.
218
+ * Required when streams are piped to the response object (e.g., for SSE).
219
+ *
220
+ * @param event - The event name
221
+ * @param args - Event arguments
222
+ * @returns True to indicate the event was handled
223
+ */
224
+ emit(event: string, ...args: unknown[]): boolean;
225
+ /**
226
+ * Property for Node.js Writable stream compatibility.
227
+ * Indicates whether the stream has ended.
228
+ */
229
+ get writableEnded(): boolean;
208
230
  /**
209
231
  * Stub method for Node.js HTTP response compatibility.
210
232
  * This method writes data to the response stream.
@@ -234,6 +256,12 @@ export declare class BunResponse {
234
256
  * ```
235
257
  */
236
258
  write(chunk: unknown): boolean;
259
+ /**
260
+ * Initializes streaming mode by creating a TransformStream and resolving the response.
261
+ * This is used for SSE and other streaming scenarios where data needs to be sent
262
+ * before end() is called.
263
+ */
264
+ private initializeStreamingMode;
237
265
  /**
238
266
  * Gets the value of a response header.
239
267
  * Header lookup is case-insensitive.
@@ -345,6 +373,13 @@ export declare class BunResponse {
345
373
  * ```
346
374
  */
347
375
  isEnded(): boolean;
376
+ /**
377
+ * Stub method for Node.js HTTP response compatibility.
378
+ *
379
+ * The primary purpose of _implicitHeader() is to automatically generate and send the HTTP headers if a write operation (like `response.write()` or `response.end()`)
380
+ * is called without explicitly calling `response.writeHead()` first.
381
+ */
382
+ _implicitHeader(): void;
348
383
  private buildStreamableResponse;
349
384
  private buildJsonResponse;
350
385
  private createResponse;