bun-types 1.2.24-canary.20251006T140715 → 1.2.24-canary.20251008T140733

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/serve.d.ts ADDED
@@ -0,0 +1,1272 @@
1
+ declare module "bun" {
2
+ /**
3
+ * A status that represents the outcome of a sent message.
4
+ *
5
+ * - if **0**, the message was **dropped**.
6
+ * - if **-1**, there is **backpressure** of messages.
7
+ * - if **>0**, it represents the **number of bytes sent**.
8
+ *
9
+ * @example
10
+ * ```js
11
+ * const status = ws.send("Hello!");
12
+ * if (status === 0) {
13
+ * console.log("Message was dropped");
14
+ * } else if (status === -1) {
15
+ * console.log("Backpressure was applied");
16
+ * } else {
17
+ * console.log(`Success! Sent ${status} bytes`);
18
+ * }
19
+ * ```
20
+ */
21
+ type ServerWebSocketSendStatus = number;
22
+
23
+ /**
24
+ * A state that represents if a WebSocket is connected.
25
+ *
26
+ * - `WebSocket.CONNECTING` is `0`, the connection is pending.
27
+ * - `WebSocket.OPEN` is `1`, the connection is established and `send()` is possible.
28
+ * - `WebSocket.CLOSING` is `2`, the connection is closing.
29
+ * - `WebSocket.CLOSED` is `3`, the connection is closed or couldn't be opened.
30
+ *
31
+ * @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
32
+ */
33
+ type WebSocketReadyState = 0 | 1 | 2 | 3;
34
+
35
+ /**
36
+ * A fast WebSocket designed for servers.
37
+ *
38
+ * Features:
39
+ * - **Message compression** - Messages can be compressed
40
+ * - **Backpressure** - If the client is not ready to receive data, the server will tell you.
41
+ * - **Dropped messages** - If the client cannot receive data, the server will tell you.
42
+ * - **Topics** - Messages can be {@link ServerWebSocket.publish}ed to a specific topic and the client can {@link ServerWebSocket.subscribe} to topics
43
+ *
44
+ * This is slightly different than the browser {@link WebSocket} which Bun supports for clients.
45
+ *
46
+ * Powered by [uWebSockets](https://github.com/uNetworking/uWebSockets).
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * Bun.serve({
51
+ * websocket: {
52
+ * open(ws) {
53
+ * console.log("Connected", ws.remoteAddress);
54
+ * },
55
+ * message(ws, data) {
56
+ * console.log("Received", data);
57
+ * ws.send(data);
58
+ * },
59
+ * close(ws, code, reason) {
60
+ * console.log("Disconnected", code, reason);
61
+ * },
62
+ * }
63
+ * });
64
+ * ```
65
+ */
66
+ interface ServerWebSocket<T = undefined> {
67
+ /**
68
+ * Sends a message to the client.
69
+ *
70
+ * @param data The data to send.
71
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
72
+ * @example
73
+ * ws.send("Hello!");
74
+ * ws.send("Compress this.", true);
75
+ * ws.send(new Uint8Array([1, 2, 3, 4]));
76
+ */
77
+ send(data: string | BufferSource, compress?: boolean): ServerWebSocketSendStatus;
78
+
79
+ /**
80
+ * Sends a text message to the client.
81
+ *
82
+ * @param data The data to send.
83
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
84
+ * @example
85
+ * ws.send("Hello!");
86
+ * ws.send("Compress this.", true);
87
+ */
88
+ sendText(data: string, compress?: boolean): ServerWebSocketSendStatus;
89
+
90
+ /**
91
+ * Sends a binary message to the client.
92
+ *
93
+ * @param data The data to send.
94
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
95
+ * @example
96
+ * ws.send(new TextEncoder().encode("Hello!"));
97
+ * ws.send(new Uint8Array([1, 2, 3, 4]), true);
98
+ */
99
+ sendBinary(data: BufferSource, compress?: boolean): ServerWebSocketSendStatus;
100
+
101
+ /**
102
+ * Closes the connection.
103
+ *
104
+ * Here is a list of close codes:
105
+ * - `1000` means "normal closure" **(default)**
106
+ * - `1009` means a message was too big and was rejected
107
+ * - `1011` means the server encountered an error
108
+ * - `1012` means the server is restarting
109
+ * - `1013` means the server is too busy or the client is rate-limited
110
+ * - `4000` through `4999` are reserved for applications (you can use it!)
111
+ *
112
+ * To close the connection abruptly, use `terminate()`.
113
+ *
114
+ * @param code The close code to send
115
+ * @param reason The close reason to send
116
+ */
117
+ close(code?: number, reason?: string): void;
118
+
119
+ /**
120
+ * Abruptly close the connection.
121
+ *
122
+ * To gracefully close the connection, use `close()`.
123
+ */
124
+ terminate(): void;
125
+
126
+ /**
127
+ * Sends a ping.
128
+ *
129
+ * @param data The data to send
130
+ */
131
+ ping(data?: string | BufferSource): ServerWebSocketSendStatus;
132
+
133
+ /**
134
+ * Sends a pong.
135
+ *
136
+ * @param data The data to send
137
+ */
138
+ pong(data?: string | BufferSource): ServerWebSocketSendStatus;
139
+
140
+ /**
141
+ * Sends a message to subscribers of the topic.
142
+ *
143
+ * @param topic The topic name.
144
+ * @param data The data to send.
145
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
146
+ * @example
147
+ * ws.publish("chat", "Hello!");
148
+ * ws.publish("chat", "Compress this.", true);
149
+ * ws.publish("chat", new Uint8Array([1, 2, 3, 4]));
150
+ */
151
+ publish(topic: string, data: string | BufferSource, compress?: boolean): ServerWebSocketSendStatus;
152
+
153
+ /**
154
+ * Sends a text message to subscribers of the topic.
155
+ *
156
+ * @param topic The topic name.
157
+ * @param data The data to send.
158
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
159
+ * @example
160
+ * ws.publish("chat", "Hello!");
161
+ * ws.publish("chat", "Compress this.", true);
162
+ */
163
+ publishText(topic: string, data: string, compress?: boolean): ServerWebSocketSendStatus;
164
+
165
+ /**
166
+ * Sends a binary message to subscribers of the topic.
167
+ *
168
+ * @param topic The topic name.
169
+ * @param data The data to send.
170
+ * @param compress Should the data be compressed? If the client does not support compression, this is ignored.
171
+ * @example
172
+ * ws.publish("chat", new TextEncoder().encode("Hello!"));
173
+ * ws.publish("chat", new Uint8Array([1, 2, 3, 4]), true);
174
+ */
175
+ publishBinary(topic: string, data: BufferSource, compress?: boolean): ServerWebSocketSendStatus;
176
+
177
+ /**
178
+ * Subscribes a client to the topic.
179
+ *
180
+ * @param topic The topic name.
181
+ * @example
182
+ * ws.subscribe("chat");
183
+ */
184
+ subscribe(topic: string): void;
185
+
186
+ /**
187
+ * Unsubscribes a client to the topic.
188
+ *
189
+ * @param topic The topic name.
190
+ * @example
191
+ * ws.unsubscribe("chat");
192
+ */
193
+ unsubscribe(topic: string): void;
194
+
195
+ /**
196
+ * Is the client subscribed to a topic?
197
+ *
198
+ * @param topic The topic name.
199
+ * @example
200
+ * ws.subscribe("chat");
201
+ * console.log(ws.isSubscribed("chat")); // true
202
+ */
203
+ isSubscribed(topic: string): boolean;
204
+
205
+ /**
206
+ * Batches `send()` and `publish()` operations, which makes it faster to send data.
207
+ *
208
+ * The `message`, `open`, and `drain` callbacks are automatically corked, so
209
+ * you only need to call this if you are sending messages outside of those
210
+ * callbacks or in async functions.
211
+ *
212
+ * @param callback The callback to run.
213
+ * @example
214
+ * ws.cork((ctx) => {
215
+ * ctx.send("These messages");
216
+ * ctx.sendText("are sent");
217
+ * ctx.sendBinary(new TextEncoder().encode("together!"));
218
+ * });
219
+ */
220
+ cork<T = unknown>(callback: (ws: ServerWebSocket<T>) => T): T;
221
+
222
+ /**
223
+ * The IP address of the client.
224
+ *
225
+ * @example
226
+ * console.log(socket.remoteAddress); // "127.0.0.1"
227
+ */
228
+ readonly remoteAddress: string;
229
+
230
+ /**
231
+ * The ready state of the client.
232
+ *
233
+ * - if `0`, the client is connecting.
234
+ * - if `1`, the client is connected.
235
+ * - if `2`, the client is closing.
236
+ * - if `3`, the client is closed.
237
+ *
238
+ * @example
239
+ * console.log(socket.readyState); // 1
240
+ */
241
+ readonly readyState: WebSocketReadyState;
242
+
243
+ /**
244
+ * Sets how binary data is returned in events.
245
+ *
246
+ * - if `nodebuffer`, binary data is returned as `Buffer` objects. **(default)**
247
+ * - if `arraybuffer`, binary data is returned as `ArrayBuffer` objects.
248
+ * - if `uint8array`, binary data is returned as `Uint8Array` objects.
249
+ *
250
+ * @example
251
+ * let ws: WebSocket;
252
+ * ws.binaryType = "uint8array";
253
+ * ws.addEventListener("message", ({ data }) => {
254
+ * console.log(data instanceof Uint8Array); // true
255
+ * });
256
+ */
257
+ binaryType?: "nodebuffer" | "arraybuffer" | "uint8array";
258
+
259
+ /**
260
+ * Custom data that you can assign to a client, can be read and written at any time.
261
+ *
262
+ * @example
263
+ * import { serve } from "bun";
264
+ *
265
+ * serve({
266
+ * fetch(request, server) {
267
+ * const data = {
268
+ * accessToken: request.headers.get("Authorization"),
269
+ * };
270
+ * if (server.upgrade(request, { data })) {
271
+ * return;
272
+ * }
273
+ * return new Response();
274
+ * },
275
+ * websocket: {
276
+ * open(ws) {
277
+ * console.log(ws.data.accessToken);
278
+ * }
279
+ * }
280
+ * });
281
+ */
282
+ data: T;
283
+
284
+ getBufferedAmount(): number;
285
+ }
286
+
287
+ /**
288
+ * Compression options for WebSocket messages.
289
+ */
290
+ type WebSocketCompressor =
291
+ | "disable"
292
+ | "shared"
293
+ | "dedicated"
294
+ | "3KB"
295
+ | "4KB"
296
+ | "8KB"
297
+ | "16KB"
298
+ | "32KB"
299
+ | "64KB"
300
+ | "128KB"
301
+ | "256KB";
302
+
303
+ /**
304
+ * Create a server-side {@link ServerWebSocket} handler for use with {@link Bun.serve}
305
+ *
306
+ * @example
307
+ * ```ts
308
+ * import { websocket, serve } from "bun";
309
+ *
310
+ * serve<{name: string}>({
311
+ * port: 3000,
312
+ * websocket: {
313
+ * open: (ws) => {
314
+ * console.log("Client connected");
315
+ * },
316
+ * message: (ws, message) => {
317
+ * console.log(`${ws.data.name}: ${message}`);
318
+ * },
319
+ * close: (ws) => {
320
+ * console.log("Client disconnected");
321
+ * },
322
+ * },
323
+ *
324
+ * fetch(req, server) {
325
+ * const url = new URL(req.url);
326
+ * if (url.pathname === "/chat") {
327
+ * const upgraded = server.upgrade(req, {
328
+ * data: {
329
+ * name: new URL(req.url).searchParams.get("name"),
330
+ * },
331
+ * });
332
+ * if (!upgraded) {
333
+ * return new Response("Upgrade failed", { status: 400 });
334
+ * }
335
+ * return;
336
+ * }
337
+ * return new Response("Hello World");
338
+ * },
339
+ * });
340
+ * ```
341
+ */
342
+ interface WebSocketHandler<T> {
343
+ /**
344
+ * Specify the type for the {@link ServerWebSocket.data} property on
345
+ * connecting websocket clients. You can pass this value when you make a
346
+ * call to {@link Server.upgrade}.
347
+ *
348
+ * This pattern exists in Bun due to a [TypeScript limitation (#26242)](https://github.com/microsoft/TypeScript/issues/26242)
349
+ *
350
+ * @example
351
+ * ```ts
352
+ * Bun.serve({
353
+ * websocket: {
354
+ * data: {} as { name: string }, // ← Specify the type of `ws.data` like this
355
+ * message: (ws, message) => console.log(ws.data.name, 'says:', message);
356
+ * },
357
+ * // ...
358
+ * });
359
+ * ```
360
+ */
361
+ data?: T;
362
+
363
+ /**
364
+ * Called when the server receives an incoming message.
365
+ *
366
+ * If the message is not a `string`, its type is based on the value of `binaryType`.
367
+ * - if `nodebuffer`, then the message is a `Buffer`.
368
+ * - if `arraybuffer`, then the message is an `ArrayBuffer`.
369
+ * - if `uint8array`, then the message is a `Uint8Array`.
370
+ *
371
+ * @param ws The websocket that sent the message
372
+ * @param message The message received
373
+ */
374
+ message(ws: ServerWebSocket<T>, message: string | Buffer<ArrayBuffer>): void | Promise<void>;
375
+
376
+ /**
377
+ * Called when a connection is opened.
378
+ *
379
+ * @param ws The websocket that was opened
380
+ */
381
+ open?(ws: ServerWebSocket<T>): void | Promise<void>;
382
+
383
+ /**
384
+ * Called when a connection was previously under backpressure,
385
+ * meaning it had too many queued messages, but is now ready to receive more data.
386
+ *
387
+ * @param ws The websocket that is ready for more data
388
+ */
389
+ drain?(ws: ServerWebSocket<T>): void | Promise<void>;
390
+
391
+ /**
392
+ * Called when a connection is closed.
393
+ *
394
+ * @param ws The websocket that was closed
395
+ * @param code The close code
396
+ * @param reason The close reason
397
+ */
398
+ close?(ws: ServerWebSocket<T>, code: number, reason: string): void | Promise<void>;
399
+
400
+ /**
401
+ * Called when a ping is sent.
402
+ *
403
+ * @param ws The websocket that received the ping
404
+ * @param data The data sent with the ping
405
+ */
406
+ ping?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
407
+
408
+ /**
409
+ * Called when a pong is received.
410
+ *
411
+ * @param ws The websocket that received the ping
412
+ * @param data The data sent with the ping
413
+ */
414
+ pong?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
415
+
416
+ /**
417
+ * Sets the maximum size of messages in bytes.
418
+ *
419
+ * Default is 16 MB, or `1024 * 1024 * 16` in bytes.
420
+ */
421
+ maxPayloadLength?: number;
422
+
423
+ /**
424
+ * Sets the maximum number of bytes that can be buffered on a single connection.
425
+ *
426
+ * Default is 16 MB, or `1024 * 1024 * 16` in bytes.
427
+ */
428
+ backpressureLimit?: number;
429
+
430
+ /**
431
+ * Sets if the connection should be closed if `backpressureLimit` is reached.
432
+ *
433
+ * @default false
434
+ */
435
+ closeOnBackpressureLimit?: boolean;
436
+
437
+ /**
438
+ * Sets the the number of seconds to wait before timing out a connection
439
+ * due to no messages or pings.
440
+ *
441
+ * @default 120
442
+ */
443
+ idleTimeout?: number;
444
+
445
+ /**
446
+ * Should `ws.publish()` also send a message to `ws` (itself), if it is subscribed?
447
+ *
448
+ * @default false
449
+ */
450
+ publishToSelf?: boolean;
451
+
452
+ /**
453
+ * Should the server automatically send and respond to pings to clients?
454
+ *
455
+ * @default true
456
+ */
457
+ sendPings?: boolean;
458
+
459
+ /**
460
+ * Sets the compression level for messages, for clients that supports it. By default, compression is disabled.
461
+ *
462
+ * @default false
463
+ */
464
+ perMessageDeflate?:
465
+ | boolean
466
+ | {
467
+ /**
468
+ * Sets the compression level.
469
+ */
470
+ compress?: WebSocketCompressor | boolean;
471
+ /**
472
+ * Sets the decompression level.
473
+ */
474
+ decompress?: WebSocketCompressor | boolean;
475
+ };
476
+ }
477
+
478
+ namespace Serve {
479
+ type ExtractRouteParams<T> = T extends `${string}:${infer Param}/${infer Rest}`
480
+ ? { [K in Param]: string } & ExtractRouteParams<Rest>
481
+ : T extends `${string}:${infer Param}`
482
+ ? { [K in Param]: string }
483
+ : T extends `${string}*`
484
+ ? {}
485
+ : {};
486
+
487
+ /**
488
+ * Development configuration for {@link Bun.serve}
489
+ */
490
+ type Development =
491
+ | boolean
492
+ | {
493
+ /**
494
+ * Enable Hot Module Replacement for routes (including React Fast Refresh, if React is in use)
495
+ *
496
+ * @default true if process.env.NODE_ENV !== 'production'
497
+ *
498
+ */
499
+ hmr?: boolean;
500
+
501
+ /**
502
+ * Enable console log streaming from browser to server
503
+ * @default false
504
+ */
505
+ console?: boolean;
506
+
507
+ /**
508
+ * Enable automatic workspace folders for Chrome DevTools
509
+ *
510
+ * This lets you persistently edit files in the browser. It works by adding the following route to the server:
511
+ * `/.well-known/appspecific/com.chrome.devtools.json`
512
+ *
513
+ * The response is a JSON object with the following shape:
514
+ * ```json
515
+ * {
516
+ * "workspace": {
517
+ * "root": "<cwd>",
518
+ * "uuid": "<uuid>"
519
+ * }
520
+ * }
521
+ * ```
522
+ *
523
+ * The `root` field is the current working directory of the server.
524
+ * The `"uuid"` field is a hash of the file that started the server and a hash of the current working directory.
525
+ *
526
+ * For security reasons, if the remote socket address is not from localhost, 127.0.0.1, or ::1, the request is ignored.
527
+ * @default true
528
+ */
529
+ chromeDevToolsAutomaticWorkspaceFolders?: boolean;
530
+ };
531
+
532
+ type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
533
+
534
+ type Handler<Req extends Request, S, Res> = (request: Req, server: S) => MaybePromise<Res>;
535
+
536
+ type BaseRouteValue = Response | false | HTMLBundle | BunFile;
537
+
538
+ type Routes<WebSocketData, R extends string> = {
539
+ [Path in R]:
540
+ | BaseRouteValue
541
+ | Handler<BunRequest<Path>, Server<WebSocketData>, Response>
542
+ | Partial<Record<HTTPMethod, Handler<BunRequest<Path>, Server<WebSocketData>, Response>>>;
543
+ };
544
+
545
+ type RoutesWithUpgrade<WebSocketData, R extends string> = {
546
+ [Path in R]:
547
+ | BaseRouteValue
548
+ | Handler<BunRequest<Path>, Server<WebSocketData>, Response | undefined | void>
549
+ | Partial<Record<HTTPMethod, Handler<BunRequest<Path>, Server<WebSocketData>, Response | undefined | void>>>;
550
+ };
551
+
552
+ type FetchOrRoutes<WebSocketData, R extends string> =
553
+ | {
554
+ /**
555
+ * Handle HTTP requests
556
+ *
557
+ * Respond to {@link Request} objects with a {@link Response} object.
558
+ */
559
+ fetch?(this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>): MaybePromise<Response>;
560
+
561
+ routes: Routes<WebSocketData, R>;
562
+ }
563
+ | {
564
+ /**
565
+ * Handle HTTP requests
566
+ *
567
+ * Respond to {@link Request} objects with a {@link Response} object.
568
+ */
569
+ fetch(this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>): MaybePromise<Response>;
570
+
571
+ routes?: Routes<WebSocketData, R>;
572
+ };
573
+
574
+ type FetchOrRoutesWithWebSocket<WebSocketData, R extends string> = {
575
+ /**
576
+ * Enable websockets with {@link Bun.serve}
577
+ *
578
+ * Upgrade a {@link Request} to a {@link ServerWebSocket} via {@link Server.upgrade}
579
+ *
580
+ * Pass `data` in {@link Server.upgrade} to attach data to the {@link ServerWebSocket.data} property
581
+ *
582
+ * @example
583
+ * ```js
584
+ * const server: Bun.Server = Bun.serve({
585
+ * websocket: {
586
+ * open: (ws) => {
587
+ * console.log("Client connected");
588
+ * },
589
+ * message: (ws, message) => {
590
+ * console.log("Client sent message", message);
591
+ * },
592
+ * close: (ws) => {
593
+ * console.log("Client disconnected");
594
+ * },
595
+ * },
596
+ * fetch(req, server) {
597
+ * const url = new URL(req.url);
598
+ * if (url.pathname === "/chat") {
599
+ * const upgraded = server.upgrade(req);
600
+ * if (!upgraded) {
601
+ * return new Response("Upgrade failed", { status: 400 });
602
+ * }
603
+ * }
604
+ * return new Response("Hello World");
605
+ * },
606
+ * });
607
+ * ```
608
+ */
609
+ websocket: WebSocketHandler<WebSocketData>;
610
+ } & (
611
+ | {
612
+ /**
613
+ * Handle HTTP requests, or call {@link Server.upgrade} and return early
614
+ *
615
+ * Respond to {@link Request} objects with a {@link Response} object.
616
+ */
617
+ fetch?(
618
+ this: Server<WebSocketData>,
619
+ req: Request,
620
+ server: Server<WebSocketData>,
621
+ ): MaybePromise<Response | void | undefined>;
622
+
623
+ routes: RoutesWithUpgrade<WebSocketData, R>;
624
+ }
625
+ | {
626
+ /**
627
+ * Handle HTTP requests, or call {@link Server.upgrade} and return early
628
+ *
629
+ * Respond to {@link Request} objects with a {@link Response} object.
630
+ */
631
+ fetch(
632
+ this: Server<WebSocketData>,
633
+ req: Request,
634
+ server: Server<WebSocketData>,
635
+ ): MaybePromise<Response | void | undefined>;
636
+
637
+ routes?: RoutesWithUpgrade<WebSocketData, R>;
638
+ }
639
+ );
640
+
641
+ interface BaseServeOptions<WebSocketData> {
642
+ /**
643
+ * Set options for using TLS with this server
644
+ *
645
+ * @example
646
+ * ```ts
647
+ * const server = Bun.serve({
648
+ * fetch: request => new Response("Welcome to Bun!"),
649
+ * tls: {
650
+ * cert: Bun.file("cert.pem"),
651
+ * key: Bun.file("key.pem"),
652
+ * ca: [Bun.file("ca1.pem"), Bun.file("ca2.pem")],
653
+ * },
654
+ * });
655
+ * ```
656
+ */
657
+ tls?: TLSOptions | TLSOptions[];
658
+
659
+ /**
660
+ * What is the maximum size of a request body? (in bytes)
661
+ * @default 1024 * 1024 * 128 // 128MB
662
+ */
663
+ maxRequestBodySize?: number;
664
+
665
+ /**
666
+ * Render contextual errors? This enables bun's error page
667
+ * @default process.env.NODE_ENV !== 'production'
668
+ */
669
+ development?: Development;
670
+
671
+ /**
672
+ * Callback called when an error is thrown during request handling
673
+ * @param error The error that was thrown
674
+ * @returns A response to send to the client
675
+ *
676
+ * @example
677
+ * ```ts
678
+ * error: (error) => {
679
+ * return new Response("Internal Server Error", { status: 500 });
680
+ * }
681
+ * ```
682
+ */
683
+ error?: (this: Server<WebSocketData>, error: ErrorLike) => Response | Promise<Response> | void | Promise<void>;
684
+
685
+ /**
686
+ * Uniquely identify a server instance with an ID
687
+ *
688
+ * ---
689
+ *
690
+ * **When bun is started with the `--hot` flag**:
691
+ *
692
+ * This string will be used to hot reload the server without interrupting
693
+ * pending requests or websockets. If not provided, a value will be
694
+ * generated. To disable hot reloading, set this value to `null`.
695
+ *
696
+ * **When bun is not started with the `--hot` flag**:
697
+ *
698
+ * This string will currently do nothing. But in the future it could be useful for logs or metrics.
699
+ */
700
+ id?: string | null;
701
+ }
702
+
703
+ interface HostnamePortServeOptions<WebSocketData> extends BaseServeOptions<WebSocketData> {
704
+ /**
705
+ * What hostname should the server listen on?
706
+ *
707
+ * @default
708
+ * ```js
709
+ * "0.0.0.0" // listen on all interfaces
710
+ * ```
711
+ * @example
712
+ * ```js
713
+ * "127.0.0.1" // Only listen locally
714
+ * ```
715
+ * @example
716
+ * ```js
717
+ * "remix.run" // Only listen on remix.run
718
+ * ````
719
+ *
720
+ * note: hostname should not include a {@link port}
721
+ */
722
+ hostname?: "0.0.0.0" | "127.0.0.1" | "localhost" | (string & {});
723
+
724
+ /**
725
+ * What port should the server listen on?
726
+ * @default process.env.PORT || "3000"
727
+ */
728
+ port?: string | number;
729
+
730
+ /**
731
+ * Whether the `SO_REUSEPORT` flag should be set.
732
+ *
733
+ * This allows multiple processes to bind to the same port, which is useful for load balancing.
734
+ *
735
+ * @default false
736
+ */
737
+ reusePort?: boolean;
738
+
739
+ /**
740
+ * Whether the `IPV6_V6ONLY` flag should be set.
741
+ * @default false
742
+ */
743
+ ipv6Only?: boolean;
744
+
745
+ /**
746
+ * Sets the the number of seconds to wait before timing out a connection
747
+ * due to inactivity.
748
+ *
749
+ * @default 10
750
+ */
751
+ idleTimeout?: number;
752
+ }
753
+
754
+ interface UnixServeOptions<WebSocketData> extends BaseServeOptions<WebSocketData> {
755
+ /**
756
+ * If set, the HTTP server will listen on a unix socket instead of a port.
757
+ * (Cannot be used with hostname+port)
758
+ */
759
+ unix?: string;
760
+ }
761
+
762
+ /**
763
+ * The type of options that can be passed to {@link serve}, with support for
764
+ * `routes` and a safer requirement for `fetch`
765
+ *
766
+ * @example
767
+ * ```ts
768
+ * export default {
769
+ * fetch: req => Response.json(req.url),
770
+ *
771
+ * websocket: {
772
+ * message(ws) {
773
+ * ws.data.name; // string
774
+ * },
775
+ * },
776
+ * } satisfies Bun.Serve.Options<{ name: string }>;
777
+ * ```
778
+ */
779
+ type Options<WebSocketData, R extends string = never> = Bun.__internal.XOR<
780
+ HostnamePortServeOptions<WebSocketData>,
781
+ UnixServeOptions<WebSocketData>
782
+ > &
783
+ Bun.__internal.XOR<FetchOrRoutes<WebSocketData, R>, FetchOrRoutesWithWebSocket<WebSocketData, R>>;
784
+ }
785
+
786
+ interface BunRequest<T extends string = string> extends Request {
787
+ readonly params: {
788
+ [Key in keyof Serve.ExtractRouteParams<T>]: Serve.ExtractRouteParams<T>[Key];
789
+ } & {};
790
+ readonly cookies: CookieMap;
791
+ clone(): BunRequest<T>;
792
+ }
793
+
794
+ /**
795
+ * HTTP & HTTPS Server
796
+ *
797
+ * To start the server, see {@link serve}
798
+ *
799
+ * For performance, Bun pre-allocates most of the data for 2048 concurrent requests.
800
+ * That means starting a new server allocates about 500 KB of memory. Try to
801
+ * avoid starting and stopping the server often (unless it's a new instance of bun).
802
+ *
803
+ * Powered by a fork of [uWebSockets](https://github.com/uNetworking/uWebSockets). Thank you \@alexhultman.
804
+ */
805
+ interface Server<WebSocketData> extends Disposable {
806
+ /**
807
+ * Stop listening to prevent new connections from being accepted.
808
+ *
809
+ * By default, it does not cancel in-flight requests or websockets. That means it may take some time before all network activity stops.
810
+ *
811
+ * @param closeActiveConnections Immediately terminate in-flight requests, websockets, and stop accepting new connections.
812
+ * @default false
813
+ */
814
+ stop(closeActiveConnections?: boolean): Promise<void>;
815
+
816
+ /**
817
+ * Update the `fetch` and `error` handlers without restarting the server.
818
+ *
819
+ * This is useful if you want to change the behavior of your server without
820
+ * restarting it or for hot reloading.
821
+ *
822
+ * @example
823
+ *
824
+ * ```js
825
+ * // create the server
826
+ * const server = Bun.serve({
827
+ * fetch(request) {
828
+ * return new Response("Hello World v1")
829
+ * }
830
+ * });
831
+ *
832
+ * // Update the server to return a different response
833
+ * server.reload({
834
+ * fetch(request) {
835
+ * return new Response("Hello World v2")
836
+ * }
837
+ * });
838
+ * ```
839
+ *
840
+ * Passing other options such as `port` or `hostname` won't do anything.
841
+ */
842
+ reload<R extends string>(options: Serve.Options<WebSocketData, R>): Server<WebSocketData>;
843
+
844
+ /**
845
+ * Mock the fetch handler for a running server.
846
+ *
847
+ * This feature is not fully implemented yet. It doesn't normalize URLs
848
+ * consistently in all cases and it doesn't yet call the `error` handler
849
+ * consistently. This needs to be fixed
850
+ */
851
+ fetch(request: Request | string): Response | Promise<Response>;
852
+
853
+ /**
854
+ * Upgrade a {@link Request} to a {@link ServerWebSocket}
855
+ *
856
+ * @param request The {@link Request} to upgrade
857
+ * @param options Pass headers or attach data to the {@link ServerWebSocket}
858
+ *
859
+ * @returns `true` if the upgrade was successful and `false` if it failed
860
+ *
861
+ * @example
862
+ * ```js
863
+ * import { serve } from "bun";
864
+ * const server: Bun.Server<{ user: string }> = serve({
865
+ * websocket: {
866
+ * open: (ws) => {
867
+ * console.log("Client connected");
868
+ * },
869
+ * message: (ws, message) => {
870
+ * console.log("Client sent message", message);
871
+ * },
872
+ * close: (ws) => {
873
+ * console.log("Client disconnected");
874
+ * },
875
+ * },
876
+ * fetch(req, server) {
877
+ * const url = new URL(req.url);
878
+ * if (url.pathname === "/chat") {
879
+ * const upgraded = server.upgrade(req, {
880
+ * data: {user: "John Doe"}
881
+ * });
882
+ * if (!upgraded) {
883
+ * return new Response("Upgrade failed", { status: 400 });
884
+ * }
885
+ * }
886
+ * return new Response("Hello World");
887
+ * },
888
+ * });
889
+ * ```
890
+ *
891
+ * What you pass to `data` is available on the {@link ServerWebSocket.data} property
892
+ */
893
+ upgrade(
894
+ request: Request,
895
+ ...options: [WebSocketData] extends [undefined]
896
+ ? [
897
+ options?: {
898
+ /**
899
+ */
900
+ headers?: HeadersInit;
901
+
902
+ /**
903
+ * Data to store on the WebSocket instance
904
+ *
905
+ * ---
906
+ *
907
+ * **Surprised this line is erroring?**
908
+ *
909
+ * Tell TypeScript about the WebSocket data by using `Bun.Server<MyWebSocketData>`
910
+ *
911
+ * ```ts
912
+ * const server: Bun.Server<MyWebSocketData> = Bun.serve({
913
+ * fetch: (req, server) => {
914
+ * const didUpgrade = server.upgrade(req, {
915
+ * data: { ... }, // Works now!
916
+ * });
917
+ * },
918
+ * });
919
+ * ```
920
+ */
921
+ data?: undefined;
922
+ },
923
+ ]
924
+ : [
925
+ options: {
926
+ /**
927
+ * Send any additional headers while upgrading, like cookies
928
+ */
929
+ headers?: HeadersInit;
930
+
931
+ /**
932
+ * Data to store on the WebSocket instance
933
+ */
934
+ data: WebSocketData;
935
+ },
936
+ ]
937
+ ): boolean;
938
+
939
+ /**
940
+ * Send a message to all connected {@link ServerWebSocket} subscribed to a topic
941
+ *
942
+ * @param topic The topic to publish to
943
+ * @param data The data to send
944
+ * @param compress Should the data be compressed? Ignored if the client does not support compression.
945
+ *
946
+ * @returns 0 if the message was dropped, -1 if backpressure was applied, or the number of bytes sent.
947
+ *
948
+ * @example
949
+ *
950
+ * ```js
951
+ * server.publish("chat", "Hello World");
952
+ * ```
953
+ *
954
+ * @example
955
+ * ```js
956
+ * server.publish("chat", new Uint8Array([1, 2, 3, 4]));
957
+ * ```
958
+ *
959
+ * @example
960
+ * ```js
961
+ * server.publish("chat", new ArrayBuffer(4), true);
962
+ * ```
963
+ *
964
+ * @example
965
+ * ```js
966
+ * server.publish("chat", new DataView(new ArrayBuffer(4)));
967
+ * ```
968
+ */
969
+ publish(
970
+ topic: string,
971
+ data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
972
+ compress?: boolean,
973
+ ): ServerWebSocketSendStatus;
974
+
975
+ /**
976
+ * A count of connections subscribed to a given topic
977
+ *
978
+ * This operation will loop through each topic internally to get the count.
979
+ *
980
+ * @param topic the websocket topic to check how many subscribers are connected to
981
+ * @returns the number of subscribers
982
+ */
983
+ subscriberCount(topic: string): number;
984
+
985
+ /**
986
+ * Returns the client IP address and port of the given Request. If the request was closed or is a unix socket, returns null.
987
+ *
988
+ * @example
989
+ * ```js
990
+ * export default {
991
+ * async fetch(request, server) {
992
+ * return new Response(server.requestIP(request));
993
+ * }
994
+ * }
995
+ * ```
996
+ */
997
+ requestIP(request: Request): SocketAddress | null;
998
+
999
+ /**
1000
+ * Reset the idleTimeout of the given Request to the number in seconds. 0 means no timeout.
1001
+ *
1002
+ * @example
1003
+ * ```js
1004
+ * export default {
1005
+ * async fetch(request, server) {
1006
+ * server.timeout(request, 60);
1007
+ * await Bun.sleep(30000);
1008
+ * return new Response("30 seconds have passed");
1009
+ * }
1010
+ * }
1011
+ * ```
1012
+ */
1013
+ timeout(request: Request, seconds: number): void;
1014
+
1015
+ /**
1016
+ * Undo a call to {@link Server.unref}
1017
+ *
1018
+ * If the Server has already been stopped, this does nothing.
1019
+ *
1020
+ * If {@link Server.ref} is called multiple times, this does nothing. Think of it as a boolean toggle.
1021
+ */
1022
+ ref(): void;
1023
+
1024
+ /**
1025
+ * Don't keep the process alive if this server is the only thing left.
1026
+ * Active connections may continue to keep the process alive.
1027
+ *
1028
+ * By default, the server is ref'd.
1029
+ *
1030
+ * To prevent new connections from being accepted, use {@link Server.stop}
1031
+ */
1032
+ unref(): void;
1033
+
1034
+ /**
1035
+ * How many requests are in-flight right now?
1036
+ */
1037
+ readonly pendingRequests: number;
1038
+
1039
+ /**
1040
+ * How many {@link ServerWebSocket}s are in-flight right now?
1041
+ */
1042
+ readonly pendingWebSockets: number;
1043
+
1044
+ readonly url: URL;
1045
+
1046
+ /**
1047
+ * The port the server is listening on.
1048
+ *
1049
+ * This will be undefined when the server is listening on a unix socket.
1050
+ *
1051
+ * @example
1052
+ * ```js
1053
+ * 3000
1054
+ * ```
1055
+ */
1056
+ readonly port: number | undefined;
1057
+
1058
+ /**
1059
+ * The hostname the server is listening on. Does not include the port.
1060
+ *
1061
+ * This will be `undefined` when the server is listening on a unix socket.
1062
+ *
1063
+ * @example
1064
+ * ```js
1065
+ * "localhost"
1066
+ * ```
1067
+ */
1068
+ readonly hostname: string | undefined;
1069
+
1070
+ /**
1071
+ * Is the server running in development mode?
1072
+ *
1073
+ * In development mode, `Bun.serve()` returns rendered error messages with
1074
+ * stack traces instead of a generic 500 error. This makes debugging easier,
1075
+ * but development mode shouldn't be used in production or you will risk
1076
+ * leaking sensitive information.
1077
+ */
1078
+ readonly development: boolean;
1079
+
1080
+ /**
1081
+ * An identifier of the server instance
1082
+ *
1083
+ * When bun is started with the `--hot` flag, this ID is used to hot reload the server without interrupting pending requests or websockets.
1084
+ *
1085
+ * When bun is not started with the `--hot` flag, this ID is currently unused.
1086
+ */
1087
+ readonly id: string;
1088
+ }
1089
+
1090
+ /**
1091
+ * Bun.serve provides a high-performance HTTP server with built-in routing support.
1092
+ * It enables both function-based and object-based route handlers with type-safe
1093
+ * parameters and method-specific handling.
1094
+ *
1095
+ * @param options Server configuration options
1096
+ *
1097
+ * @example
1098
+ * **Basic Usage**
1099
+ *
1100
+ * ```ts
1101
+ * Bun.serve({
1102
+ * port: 3000,
1103
+ * fetch(req) {
1104
+ * return new Response("Hello World");
1105
+ * }
1106
+ * });
1107
+ * ```
1108
+ *
1109
+ * @example
1110
+ * **Route-based Handlers**
1111
+ *
1112
+ * ```ts
1113
+ * Bun.serve({
1114
+ * routes: {
1115
+ * // Static responses
1116
+ * "/": new Response("Home page"),
1117
+ *
1118
+ * // Function handlers with type-safe parameters
1119
+ * "/users/:id": (req) => {
1120
+ * // req.params.id is typed as string
1121
+ * return new Response(`User ${req.params.id}`);
1122
+ * },
1123
+ *
1124
+ * // Method-specific handlers
1125
+ * "/api/posts": {
1126
+ * GET: () => new Response("Get posts"),
1127
+ * POST: async (req) => {
1128
+ * const body = await req.json();
1129
+ * return new Response("Created post");
1130
+ * },
1131
+ * DELETE: (req) => new Response("Deleted post")
1132
+ * },
1133
+ *
1134
+ * // Wildcard routes
1135
+ * "/static/*": (req) => {
1136
+ * // Handle any path under /static/
1137
+ * return new Response("Static file");
1138
+ * },
1139
+ *
1140
+ * // Disable route (fall through to fetch handler)
1141
+ * "/api/legacy": false
1142
+ * },
1143
+ *
1144
+ * // Fallback handler for unmatched routes
1145
+ * fetch(req) {
1146
+ * return new Response("Not Found", { status: 404 });
1147
+ * }
1148
+ * });
1149
+ * ```
1150
+ *
1151
+ * @example
1152
+ * **Path Parameters**
1153
+ *
1154
+ * ```ts
1155
+ * Bun.serve({
1156
+ * routes: {
1157
+ * // Single parameter
1158
+ * "/users/:id": (req: BunRequest<"/users/:id">) => {
1159
+ * return new Response(`User ID: ${req.params.id}`);
1160
+ * },
1161
+ *
1162
+ * // Multiple parameters
1163
+ * "/posts/:postId/comments/:commentId": (
1164
+ * req: BunRequest<"/posts/:postId/comments/:commentId">
1165
+ * ) => {
1166
+ * return new Response(JSON.stringify(req.params));
1167
+ * // Output: {"postId": "123", "commentId": "456"}
1168
+ * }
1169
+ * }
1170
+ * });
1171
+ * ```
1172
+ *
1173
+ * @example
1174
+ * **Route Precedence**
1175
+ *
1176
+ * ```ts
1177
+ * // Routes are matched in the following order:
1178
+ * // 1. Exact static routes ("/about")
1179
+ * // 2. Parameter routes ("/users/:id")
1180
+ * // 3. Wildcard routes ("/api/*")
1181
+ *
1182
+ * Bun.serve({
1183
+ * routes: {
1184
+ * "/api/users": () => new Response("Users list"),
1185
+ * "/api/users/:id": (req) => new Response(`User ${req.params.id}`),
1186
+ * "/api/*": () => new Response("API catchall"),
1187
+ * "/*": () => new Response("Root catchall")
1188
+ * }
1189
+ * });
1190
+ * ```
1191
+ *
1192
+ * @example
1193
+ * **Error Handling**
1194
+ *
1195
+ * ```ts
1196
+ * Bun.serve({
1197
+ * routes: {
1198
+ * "/error": () => {
1199
+ * throw new Error("Something went wrong");
1200
+ * }
1201
+ * },
1202
+ * error(error) {
1203
+ * // Custom error handler
1204
+ * console.error(error);
1205
+ * return new Response(`Error: ${error.message}`, {
1206
+ * status: 500
1207
+ * });
1208
+ * }
1209
+ * });
1210
+ * ```
1211
+ *
1212
+ * @example
1213
+ * **Server Lifecycle**
1214
+ *
1215
+ * ```ts
1216
+ * const server = Bun.serve({
1217
+ * // Server config...
1218
+ * });
1219
+ *
1220
+ * // Update routes at runtime
1221
+ * server.reload({
1222
+ * routes: {
1223
+ * "/": () => new Response("Updated route")
1224
+ * }
1225
+ * });
1226
+ *
1227
+ * // Stop the server
1228
+ * server.stop();
1229
+ * ```
1230
+ *
1231
+ * @example
1232
+ * **Development Mode**
1233
+ *
1234
+ * ```ts
1235
+ * Bun.serve({
1236
+ * development: true, // Enable hot reloading
1237
+ * routes: {
1238
+ * // Routes will auto-reload on changes
1239
+ * }
1240
+ * });
1241
+ * ```
1242
+ *
1243
+ * @example
1244
+ * **Type-Safe Request Handling**
1245
+ *
1246
+ * ```ts
1247
+ * type Post = {
1248
+ * id: string;
1249
+ * title: string;
1250
+ * };
1251
+ *
1252
+ * Bun.serve({
1253
+ * routes: {
1254
+ * "/api/posts/:id": async (
1255
+ * req: BunRequest<"/api/posts/:id">
1256
+ * ) => {
1257
+ * if (req.method === "POST") {
1258
+ * const body: Post = await req.json();
1259
+ * return Response.json(body);
1260
+ * }
1261
+ * return new Response("Method not allowed", {
1262
+ * status: 405
1263
+ * });
1264
+ * }
1265
+ * }
1266
+ * });
1267
+ * ```
1268
+ */
1269
+ function serve<WebSocketData = undefined, R extends string = string>(
1270
+ options: Serve.Options<WebSocketData, R>,
1271
+ ): Server<WebSocketData>;
1272
+ }