bun-types 1.2.3-canary.20250215T140625 → 1.2.3-canary.20250217T140554

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/bun.d.ts CHANGED
@@ -465,55 +465,6 @@ declare module "bun" {
465
465
  }
466
466
  const TOML: TOML;
467
467
 
468
- type Serve<WebSocketDataType = undefined> =
469
- | ServeOptions
470
- | TLSServeOptions
471
- | UnixServeOptions
472
- | UnixTLSServeOptions
473
- | WebSocketServeOptions<WebSocketDataType>
474
- | TLSWebSocketServeOptions<WebSocketDataType>
475
- | UnixWebSocketServeOptions<WebSocketDataType>
476
- | UnixTLSWebSocketServeOptions<WebSocketDataType>;
477
-
478
- /**
479
- * Start a fast HTTP server.
480
- *
481
- * @param options Server options (port defaults to $PORT || 3000)
482
- *
483
- * -----
484
- *
485
- * @example
486
- *
487
- * ```ts
488
- * Bun.serve({
489
- * fetch(req: Request): Response | Promise<Response> {
490
- * return new Response("Hello World!");
491
- * },
492
- *
493
- * // Optional port number - the default value is 3000
494
- * port: process.env.PORT || 3000,
495
- * });
496
- * ```
497
- * -----
498
- *
499
- * @example
500
- *
501
- * Send a file
502
- *
503
- * ```ts
504
- * Bun.serve({
505
- * fetch(req: Request): Response | Promise<Response> {
506
- * return new Response(Bun.file("./package.json"));
507
- * },
508
- *
509
- * // Optional port number - the default value is 3000
510
- * port: process.env.PORT || 3000,
511
- * });
512
- * ```
513
- */
514
- // eslint-disable-next-line @definitelytyped/no-unnecessary-generics
515
- function serve<T>(options: Serve<T>): Server;
516
-
517
468
  /**
518
469
  * Synchronously resolve a `moduleId` as though it were imported from `parent`
519
470
  *
@@ -3805,6 +3756,45 @@ declare module "bun" {
3805
3756
  };
3806
3757
  }
3807
3758
 
3759
+ namespace RouterTypes {
3760
+ type ExtractRouteParams<T> =
3761
+ T extends `${string}:${infer Param}/${infer Rest}`
3762
+ ? { [K in Param]: string } & ExtractRouteParams<Rest>
3763
+ : T extends `${string}:${infer Param}`
3764
+ ? { [K in Param]: string }
3765
+ : T extends `${string}*`
3766
+ ? {}
3767
+ : {};
3768
+
3769
+ type RouteHandler<T extends string> = (
3770
+ req: BunRequest<T>,
3771
+ server: Server,
3772
+ ) => Response | Promise<Response>;
3773
+
3774
+ type HTTPMethod =
3775
+ | "GET"
3776
+ | "POST"
3777
+ | "PUT"
3778
+ | "DELETE"
3779
+ | "PATCH"
3780
+ | "HEAD"
3781
+ | "OPTIONS";
3782
+
3783
+ type RouteHandlerObject<T extends string> = {
3784
+ [K in HTTPMethod]?: RouteHandler<T>;
3785
+ };
3786
+
3787
+ type RouteValue<T extends string> =
3788
+ | Response
3789
+ | false
3790
+ | RouteHandler<T>
3791
+ | RouteHandlerObject<T>;
3792
+ }
3793
+
3794
+ interface BunRequest<T extends string = string> extends Request {
3795
+ params: RouterTypes.ExtractRouteParams<T>;
3796
+ }
3797
+
3808
3798
  interface GenericServeOptions {
3809
3799
  /**
3810
3800
  * What URI should be used to make {@link Request.url} absolute?
@@ -3869,37 +3859,6 @@ declare module "bun" {
3869
3859
  * This string will currently do nothing. But in the future it could be useful for logs or metrics.
3870
3860
  */
3871
3861
  id?: string | null;
3872
-
3873
- /**
3874
- * Server static Response objects by route.
3875
- *
3876
- * @example
3877
- * ```ts
3878
- * Bun.serve({
3879
- * static: {
3880
- * "/": new Response("Hello World"),
3881
- * "/about": new Response("About"),
3882
- * },
3883
- * fetch(req) {
3884
- * return new Response("Fallback response");
3885
- * },
3886
- * });
3887
- * ```
3888
- *
3889
- * @experimental
3890
- */
3891
- static?: Record<
3892
- `/${string}`,
3893
- | Response
3894
- /**
3895
- * An HTML import.
3896
- */
3897
- | HTMLBundle
3898
- /**
3899
- * false to force fetch() to handle the route
3900
- */
3901
- | false
3902
- >;
3903
3862
  }
3904
3863
 
3905
3864
  interface ServeOptions extends GenericServeOptions {
@@ -4305,7 +4264,32 @@ declare module "bun" {
4305
4264
  *
4306
4265
  * Passing other options such as `port` or `hostname` won't do anything.
4307
4266
  */
4308
- reload(options: Serve): void;
4267
+ reload<T, R extends { [K in keyof R]: RouterTypes.RouteValue<K & string> }>(
4268
+ options: (
4269
+ | (Omit<ServeOptions, "fetch"> & {
4270
+ routes: R;
4271
+ fetch?: (
4272
+ this: Server,
4273
+ request: Request,
4274
+ server: Server,
4275
+ ) => Response | Promise<Response>;
4276
+ })
4277
+ | (Omit<ServeOptions, "routes"> & {
4278
+ routes?: never;
4279
+ fetch: (
4280
+ this: Server,
4281
+ request: Request,
4282
+ server: Server,
4283
+ ) => Response | Promise<Response>;
4284
+ })
4285
+ | WebSocketServeOptions<T>
4286
+ ) & {
4287
+ /**
4288
+ * @deprecated Use `routes` instead in new code. This will continue to work for awhile though.
4289
+ */
4290
+ static?: R;
4291
+ },
4292
+ ): Server;
4309
4293
 
4310
4294
  /**
4311
4295
  * Mock the fetch handler for a running server.
@@ -4503,6 +4487,209 @@ declare module "bun" {
4503
4487
  readonly id: string;
4504
4488
  }
4505
4489
 
4490
+ type Serve<WebSocketDataType = undefined> =
4491
+ | ServeOptions
4492
+ | TLSServeOptions
4493
+ | UnixServeOptions
4494
+ | UnixTLSServeOptions
4495
+ | WebSocketServeOptions<WebSocketDataType>
4496
+ | TLSWebSocketServeOptions<WebSocketDataType>
4497
+ | UnixWebSocketServeOptions<WebSocketDataType>
4498
+ | UnixTLSWebSocketServeOptions<WebSocketDataType>;
4499
+
4500
+ /**
4501
+ Bun.serve provides a high-performance HTTP server with built-in routing support.
4502
+ It enables both function-based and object-based route handlers with type-safe
4503
+ parameters and method-specific handling.
4504
+
4505
+ @example Basic Usage
4506
+ ```ts
4507
+ Bun.serve({
4508
+ port: 3000,
4509
+ fetch(req) {
4510
+ return new Response("Hello World");
4511
+ }
4512
+ });
4513
+ ```
4514
+
4515
+ @example Route-based Handlers
4516
+ ```ts
4517
+ Bun.serve({
4518
+ routes: {
4519
+ // Static responses
4520
+ "/": new Response("Home page"),
4521
+
4522
+ // Function handlers with type-safe parameters
4523
+ "/users/:id": (req) => {
4524
+ // req.params.id is typed as string
4525
+ return new Response(`User ${req.params.id}`);
4526
+ },
4527
+
4528
+ // Method-specific handlers
4529
+ "/api/posts": {
4530
+ GET: () => new Response("Get posts"),
4531
+ POST: async (req) => {
4532
+ const body = await req.json();
4533
+ return new Response("Created post");
4534
+ },
4535
+ DELETE: (req) => new Response("Deleted post")
4536
+ },
4537
+
4538
+ // Wildcard routes
4539
+ "/static/*": (req) => {
4540
+ // Handle any path under /static/
4541
+ return new Response("Static file");
4542
+ },
4543
+
4544
+ // Disable route (fall through to fetch handler)
4545
+ "/api/legacy": false
4546
+ },
4547
+
4548
+ // Fallback handler for unmatched routes
4549
+ fetch(req) {
4550
+ return new Response("Not Found", { status: 404 });
4551
+ }
4552
+ });
4553
+ ```
4554
+
4555
+ @example Path Parameters
4556
+ ```ts
4557
+ Bun.serve({
4558
+ routes: {
4559
+ // Single parameter
4560
+ "/users/:id": (req: BunRequest<"/users/:id">) => {
4561
+ return new Response(`User ID: ${req.params.id}`);
4562
+ },
4563
+
4564
+ // Multiple parameters
4565
+ "/posts/:postId/comments/:commentId": (
4566
+ req: BunRequest<"/posts/:postId/comments/:commentId">
4567
+ ) => {
4568
+ return new Response(JSON.stringify(req.params));
4569
+ // Output: {"postId": "123", "commentId": "456"}
4570
+ }
4571
+ }
4572
+ });
4573
+ ```
4574
+
4575
+ @example Route Precedence
4576
+ ```ts
4577
+ // Routes are matched in the following order:
4578
+ // 1. Exact static routes ("/about")
4579
+ // 2. Parameter routes ("/users/:id")
4580
+ // 3. Wildcard routes ("/api/*")
4581
+
4582
+ Bun.serve({
4583
+ routes: {
4584
+ "/api/users": () => new Response("Users list"),
4585
+ "/api/users/:id": (req) => new Response(`User ${req.params.id}`),
4586
+ "/api/*": () => new Response("API catchall"),
4587
+ "/*": () => new Response("Root catchall")
4588
+ }
4589
+ });
4590
+ ```
4591
+
4592
+ @example Error Handling
4593
+ ```ts
4594
+ Bun.serve({
4595
+ routes: {
4596
+ "/error": () => {
4597
+ throw new Error("Something went wrong");
4598
+ }
4599
+ },
4600
+ error(error) {
4601
+ // Custom error handler
4602
+ console.error(error);
4603
+ return new Response(`Error: ${error.message}`, {
4604
+ status: 500
4605
+ });
4606
+ }
4607
+ });
4608
+ ```
4609
+
4610
+ @example Server Lifecycle
4611
+ ```ts
4612
+ const server = Bun.serve({
4613
+ // Server config...
4614
+ });
4615
+
4616
+ // Update routes at runtime
4617
+ server.reload({
4618
+ routes: {
4619
+ "/": () => new Response("Updated route")
4620
+ }
4621
+ });
4622
+
4623
+ // Stop the server
4624
+ server.stop();
4625
+ ```
4626
+
4627
+ @example Development Mode
4628
+ ```ts
4629
+ Bun.serve({
4630
+ development: true, // Enable hot reloading
4631
+ routes: {
4632
+ // Routes will auto-reload on changes
4633
+ }
4634
+ });
4635
+ ```
4636
+
4637
+ @example Type-Safe Request Handling
4638
+ ```ts
4639
+ type Post = {
4640
+ id: string;
4641
+ title: string;
4642
+ };
4643
+
4644
+ Bun.serve({
4645
+ routes: {
4646
+ "/api/posts/:id": async (
4647
+ req: BunRequest<"/api/posts/:id">
4648
+ ) => {
4649
+ if (req.method === "POST") {
4650
+ const body: Post = await req.json();
4651
+ return Response.json(body);
4652
+ }
4653
+ return new Response("Method not allowed", {
4654
+ status: 405
4655
+ });
4656
+ }
4657
+ }
4658
+ });
4659
+ ```
4660
+ @param options - Server configuration options
4661
+ @param options.routes - Route definitions mapping paths to handlers
4662
+ */
4663
+ function serve<
4664
+ T,
4665
+ R extends { [K in keyof R]: RouterTypes.RouteValue<K & string> },
4666
+ >(
4667
+ options: (
4668
+ | (Omit<ServeOptions, "fetch"> & {
4669
+ routes: R;
4670
+ fetch?: (
4671
+ this: Server,
4672
+ request: Request,
4673
+ server: Server,
4674
+ ) => Response | Promise<Response>;
4675
+ })
4676
+ | (Omit<ServeOptions, "routes"> & {
4677
+ routes?: never;
4678
+ fetch: (
4679
+ this: Server,
4680
+ request: Request,
4681
+ server: Server,
4682
+ ) => Response | Promise<Response>;
4683
+ })
4684
+ | WebSocketServeOptions<T>
4685
+ ) & {
4686
+ /**
4687
+ * @deprecated Use `routes` instead in new code. This will continue to work for awhile though.
4688
+ */
4689
+ static?: R;
4690
+ },
4691
+ ): Server;
4692
+
4506
4693
  /**
4507
4694
  * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) powered by the fastest system calls available for operating on files.
4508
4695
  *
package/docs/api/fetch.md CHANGED
@@ -337,7 +337,7 @@ This will print the request and response headers to your terminal:
337
337
  ```sh
338
338
  [fetch] > HTTP/1.1 GET http://example.com/
339
339
  [fetch] > Connection: keep-alive
340
- [fetch] > User-Agent: Bun/1.2.3-canary.20250215T140625
340
+ [fetch] > User-Agent: Bun/1.2.3-canary.20250217T140554
341
341
  [fetch] > Accept: */*
342
342
  [fetch] > Host: example.com
343
343
  [fetch] > Accept-Encoding: gzip, deflate, br
package/docs/api/http.md CHANGED
@@ -8,130 +8,158 @@ To start a high-performance HTTP server with a clean API, the recommended approa
8
8
 
9
9
  ## `Bun.serve()`
10
10
 
11
- Start an HTTP server in Bun with `Bun.serve`.
11
+ Use `Bun.serve` to start an HTTP server in Bun.
12
12
 
13
13
  ```ts
14
14
  Bun.serve({
15
- fetch(req) {
16
- return new Response("Bun!");
17
- },
18
- });
19
- ```
15
+ // `routes` requires Bun v1.2.3+
16
+ routes: {
17
+ // Static routes
18
+ "/api/status": new Response("OK"),
19
+
20
+ // Dynamic routes
21
+ "/users/:id": req => {
22
+ return new Response(`Hello User ${req.params.id}!`);
23
+ },
20
24
 
21
- ### `fetch` request handler
25
+ // Per-HTTP method handlers
26
+ "/api/posts": {
27
+ GET: () => new Response("List posts"),
28
+ POST: async req => {
29
+ const body = await req.json();
30
+ return Response.json({ created: true, ...body });
31
+ },
32
+ },
22
33
 
23
- The `fetch` handler handles incoming requests. It receives a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object and returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) or `Promise<Response>`.
34
+ // Wildcard route for all routes that start with "/api/" and aren't otherwise matched
35
+ "/api/*": Response.json({ message: "Not found" }, { status: 404 }),
24
36
 
25
- ```ts
26
- Bun.serve({
37
+ // Redirect from /blog/hello to /blog/hello/world
38
+ "/blog/hello": Response.redirect("/blog/hello/world"),
39
+
40
+ // Serve a file by buffering it in memory
41
+ "/favicon.ico": new Response(await Bun.file("./favicon.ico").bytes(), {
42
+ headers: {
43
+ "Content-Type": "image/x-icon",
44
+ },
45
+ }),
46
+ },
47
+
48
+ // (optional) fallback for unmatched routes:
49
+ // Required if Bun's version < 1.2.3
27
50
  fetch(req) {
28
- const url = new URL(req.url);
29
- if (url.pathname === "/") return new Response("Home page!");
30
- if (url.pathname === "/blog") return new Response("Blog!");
31
- return new Response("404!");
51
+ return new Response("Not Found", { status: 404 });
32
52
  },
33
53
  });
34
54
  ```
35
55
 
36
- The `fetch` handler supports async/await:
56
+ ### Routing
57
+
58
+ Routes in `Bun.serve()` receive a `BunRequest` (which extends [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)) and return a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) or `Promise<Response>`. This makes it easier to use the same code for both sending & receiving HTTP requests.
37
59
 
38
60
  ```ts
39
- import { sleep, serve } from "bun";
40
- serve({
41
- async fetch(req) {
42
- const start = performance.now();
43
- await sleep(10);
44
- const end = performance.now();
45
- return new Response(`Slept for ${end - start}ms`);
46
- },
47
- });
61
+ // Simplified for brevity
62
+ interface BunRequest<T extends string> extends Request {
63
+ params: Record<T, string>;
64
+ }
48
65
  ```
49
66
 
50
- Promise-based responses are also supported:
67
+ #### Async/await in routes
68
+
69
+ You can use async/await in route handlers to return a `Promise<Response>`.
51
70
 
52
71
  ```ts
53
- Bun.serve({
54
- fetch(req) {
55
- // Forward the request to another server.
56
- return fetch("https://example.com");
72
+ import { sql, serve } from "bun";
73
+
74
+ serve({
75
+ port: 3001,
76
+ routes: {
77
+ "/api/version": async () => {
78
+ const [version] = await sql`SELECT version()`;
79
+ return Response.json(version);
80
+ },
57
81
  },
58
82
  });
59
83
  ```
60
84
 
61
- You can also access the `Server` object from the `fetch` handler. It's the second argument passed to the `fetch` function.
85
+ #### Promise in routes
86
+
87
+ You can also return a `Promise<Response>` from a route handler.
62
88
 
63
89
  ```ts
64
- // `server` is passed in as the second argument to `fetch`.
65
- const server = Bun.serve({
66
- fetch(req, server) {
67
- const ip = server.requestIP(req);
68
- return new Response(`Your IP is ${ip}`);
90
+ import { sql, serve } from "bun";
91
+
92
+ serve({
93
+ routes: {
94
+ "/api/version": () => {
95
+ return new Promise(resolve => {
96
+ setTimeout(async () => {
97
+ const [version] = await sql`SELECT version()`;
98
+ resolve(Response.json(version));
99
+ }, 100);
100
+ });
101
+ },
69
102
  },
70
103
  });
71
104
  ```
72
105
 
73
- ### Static routes
106
+ #### Type-safe route parameters
74
107
 
75
- Use the `static` option to serve static `Response` objects by route.
108
+ TypeScript parses route parameters when passed as a string literal, so that your editor will show autocomplete when accessing `request.params`.
76
109
 
77
110
  ```ts
78
- // Bun v1.1.27+ required
79
- Bun.serve({
80
- static: {
81
- // health-check endpoint
82
- "/api/health-check": new Response("All good!"),
111
+ import type { BunRequest } from "bun";
83
112
 
84
- // redirect from /old-link to /new-link
85
- "/old-link": Response.redirect("/new-link", 301),
86
-
87
- // serve static text
88
- "/": new Response("Hello World"),
89
-
90
- // serve a file by buffering it in memory
91
- "/index.html": new Response(await Bun.file("./index.html").bytes(), {
92
- headers: {
93
- "Content-Type": "text/html",
94
- },
95
- }),
96
- "/favicon.ico": new Response(await Bun.file("./favicon.ico").bytes(), {
97
- headers: {
98
- "Content-Type": "image/x-icon",
99
- },
100
- }),
101
-
102
- // serve JSON
103
- "/api/version.json": Response.json({ version: "1.0.0" }),
104
- },
113
+ Bun.serve({
114
+ routes: {
115
+ // TypeScript knows the shape of params when passed as a string literal
116
+ "/orgs/:orgId/repos/:repoId": req => {
117
+ const { orgId, repoId } = req.params;
118
+ return Response.json({ orgId, repoId });
119
+ },
105
120
 
106
- fetch(req) {
107
- return new Response("404!");
121
+ "/orgs/:orgId/repos/:repoId/settings": (
122
+ // optional: you can explicitly pass a type to BunRequest:
123
+ req: BunRequest<"/orgs/:orgId/repos/:repoId/settings">,
124
+ ) => {
125
+ const { orgId, repoId } = req.params;
126
+ return Response.json({ orgId, repoId });
127
+ },
108
128
  },
109
129
  });
110
130
  ```
111
131
 
112
- Static routes support headers, status code, and other `Response` options.
132
+ Percent-encoded route parameter values are automatically decoded. Unicode characters are supported. Invalid unicode is replaced with the unicode replacement character `&0xFFFD;`.
133
+
134
+ ### Static responses
135
+
136
+ Routes can also be `Response` objects (without the handler function). Bun.serve() optimizes it for zero-allocation dispatch - perfect for health checks, redirects, and fixed content:
113
137
 
114
138
  ```ts
115
139
  Bun.serve({
116
- static: {
117
- "/api/time": new Response(new Date().toISOString(), {
140
+ routes: {
141
+ // Health checks
142
+ "/health": new Response("OK"),
143
+ "/ready": new Response("Ready", {
118
144
  headers: {
119
- "X-Custom-Header": "Bun!",
145
+ // Pass custom headers
146
+ "X-Ready": "1",
120
147
  },
121
148
  }),
122
- },
123
149
 
124
- fetch(req) {
125
- return new Response("404!");
150
+ // Redirects
151
+ "/blog": Response.redirect("https://bun.sh/blog"),
152
+
153
+ // API responses
154
+ "/api/config": Response.json({
155
+ version: "1.0.0",
156
+ env: "production",
157
+ }),
126
158
  },
127
159
  });
128
160
  ```
129
161
 
130
- Static routes can serve Response bodies faster than `fetch` handlers because they don't create `Request` objects, they don't create `AbortSignal`, they don't create additional `Response` objects. The only per-request memory allocation is the TCP/TLS socket data needed for each request.
131
-
132
- {% note %}
133
- `static` is experimental
134
- {% /note %}
162
+ Static responses do not allocate additional memory after initialization. You can generally expect at least a 15% performance improvement over manually returning a `Response` object.
135
163
 
136
164
  Static route responses are cached for the lifetime of the server object. To reload static routes, call `server.reload(options)`.
137
165
 
@@ -160,7 +188,7 @@ setInterval(() => {
160
188
  }, 1000);
161
189
  ```
162
190
 
163
- Reloading static routes only impact the next request. In-flight requests continue to use the old static routes. After in-flight requests to old static routes are finished, the old static routes are freed from memory.
191
+ Reloading routes only impact the next request. In-flight requests continue to use the old routes. After in-flight requests to old routes are finished, the old routes are freed from memory.
164
192
 
165
193
  To simplify error handling, static routes do not support streaming response bodies from `ReadableStream` or an `AsyncIterator`. Fortunately, you can still buffer the response in memory first:
166
194
 
@@ -180,6 +208,270 @@ const server = Bun.serve({
180
208
  });
181
209
  ```
182
210
 
211
+ ### Route precedence
212
+
213
+ Routes are matched in order of specificity:
214
+
215
+ 1. Exact routes (`/users/all`)
216
+ 2. Parameter routes (`/users/:id`)
217
+ 3. Wildcard routes (`/users/*`)
218
+ 4. Global catch-all (`/*`)
219
+
220
+ ```ts
221
+ Bun.serve({
222
+ routes: {
223
+ // Most specific first
224
+ "/api/users/me": () => new Response("Current user"),
225
+ "/api/users/:id": req => new Response(`User ${req.params.id}`),
226
+ "/api/*": () => new Response("API catch-all"),
227
+ "/*": () => new Response("Global catch-all"),
228
+ },
229
+ });
230
+ ```
231
+
232
+ ### Per-HTTP Method Routes
233
+
234
+ Route handlers can be specialized by HTTP method:
235
+
236
+ ```ts
237
+ Bun.serve({
238
+ routes: {
239
+ "/api/posts": {
240
+ // Different handlers per method
241
+ GET: () => new Response("List posts"),
242
+ POST: async req => {
243
+ const post = await req.json();
244
+ return Response.json({ id: crypto.randomUUID(), ...post });
245
+ },
246
+ PUT: async req => {
247
+ const updates = await req.json();
248
+ return Response.json({ updated: true, ...updates });
249
+ },
250
+ DELETE: () => new Response(null, { status: 204 }),
251
+ },
252
+ },
253
+ });
254
+ ```
255
+
256
+ You can pass any of the following methods:
257
+
258
+ | Method | Usecase example |
259
+ | --------- | ------------------------------- |
260
+ | `GET` | Fetch a resource |
261
+ | `HEAD` | Check if a resource exists |
262
+ | `OPTIONS` | Get allowed HTTP methods (CORS) |
263
+ | `DELETE` | Delete a resource |
264
+ | `PATCH` | Update a resource |
265
+ | `POST` | Create a resource |
266
+ | `PUT` | Update a resource |
267
+
268
+ When passing a function instead of an object, all methods will be handled by that function:
269
+
270
+ ```ts
271
+ const server = Bun.serve({
272
+ routes: {
273
+ "/api/version": () => Response.json({ version: "1.0.0" }),
274
+ },
275
+ });
276
+
277
+ await fetch(new URL("/api/version", server.url));
278
+ await fetch(new URL("/api/version", server.url), { method: "PUT" });
279
+ // ... etc
280
+ ```
281
+
282
+ ### Hot Route Reloading
283
+
284
+ Update routes without server restarts using `server.reload()`:
285
+
286
+ ```ts
287
+ const server = Bun.serve({
288
+ routes: {
289
+ "/api/version": () => Response.json({ version: "1.0.0" }),
290
+ },
291
+ });
292
+
293
+ // Deploy new routes without downtime
294
+ server.reload({
295
+ routes: {
296
+ "/api/version": () => Response.json({ version: "2.0.0" }),
297
+ },
298
+ });
299
+ ```
300
+
301
+ ### Error Handling
302
+
303
+ Bun provides structured error handling for routes:
304
+
305
+ ```ts
306
+ Bun.serve({
307
+ routes: {
308
+ // Errors are caught automatically
309
+ "/api/risky": () => {
310
+ throw new Error("Something went wrong");
311
+ },
312
+ },
313
+ // Global error handler
314
+ error(error) {
315
+ console.error(error);
316
+ return new Response(`Internal Error: ${error.message}`, {
317
+ status: 500,
318
+ headers: {
319
+ "Content-Type": "text/plain",
320
+ },
321
+ });
322
+ },
323
+ });
324
+ ```
325
+
326
+ ### HTML imports
327
+
328
+ To add a client-side single-page app, you can use an HTML import:
329
+
330
+ ```ts
331
+ import myReactSinglePageApp from "./index.html";
332
+
333
+ Bun.serve({
334
+ routes: {
335
+ "/": myReactSinglePageApp,
336
+ },
337
+ });
338
+ ```
339
+
340
+ HTML imports don't just serve HTML. It's a full-featured frontend bundler, transpiler, and toolkit built using Bun's [bundler](https://bun.sh/docs/bundler), JavaScript transpiler and CSS parser.
341
+
342
+ You can use this to build a full-featured frontend with React, TypeScript, Tailwind CSS, and more. Check out [/docs/bundler/fullstack](https://bun.sh/docs/bundler/fullstack) to learn more.
343
+
344
+ ### Practical example: REST API
345
+
346
+ Here's a basic database-backed REST API using Bun's router with zero dependencies:
347
+
348
+ {% codetabs %}
349
+
350
+ ```ts#server.ts
351
+ import type { Post } from "./types.ts";
352
+ import { Database } from "bun:sqlite";
353
+
354
+ const db = new Database("posts.db");
355
+ db.exec(`
356
+ CREATE TABLE IF NOT EXISTS posts (
357
+ id TEXT PRIMARY KEY,
358
+ title TEXT NOT NULL,
359
+ content TEXT NOT NULL,
360
+ created_at TEXT NOT NULL
361
+ )
362
+ `);
363
+
364
+ Bun.serve({
365
+ routes: {
366
+ // List posts
367
+ "/api/posts": {
368
+ GET: () => {
369
+ const posts = db.query("SELECT * FROM posts").all();
370
+ return Response.json(posts);
371
+ },
372
+
373
+ // Create post
374
+ POST: async req => {
375
+ const post: Omit<Post, "id" | "created_at"> = await req.json();
376
+ const id = crypto.randomUUID();
377
+
378
+ db.query(
379
+ `INSERT INTO posts (id, title, content, created_at)
380
+ VALUES (?, ?, ?, ?)`,
381
+ ).run(id, post.title, post.content, new Date().toISOString());
382
+
383
+ return Response.json({ id, ...post }, { status: 201 });
384
+ },
385
+ },
386
+
387
+ // Get post by ID
388
+ "/api/posts/:id": req => {
389
+ const post = db
390
+ .query("SELECT * FROM posts WHERE id = ?")
391
+ .get(req.params.id);
392
+
393
+ if (!post) {
394
+ return new Response("Not Found", { status: 404 });
395
+ }
396
+
397
+ return Response.json(post);
398
+ },
399
+ },
400
+
401
+ error(error) {
402
+ console.error(error);
403
+ return new Response("Internal Server Error", { status: 500 });
404
+ },
405
+ });
406
+ ```
407
+
408
+ ```ts#types.ts
409
+ export interface Post {
410
+ id: string;
411
+ title: string;
412
+ content: string;
413
+ created_at: string;
414
+ }
415
+ ```
416
+
417
+ {% /codetabs %}
418
+
419
+ ### Routing performance
420
+
421
+ `Bun.serve()`'s router builds on top uWebSocket's [tree-based approach](https://github.com/oven-sh/bun/blob/0d1a00fa0f7830f8ecd99c027fce8096c9d459b6/packages/bun-uws/src/HttpRouter.h#L57-L64) to add [SIMD-accelerated route parameter decoding](https://github.com/oven-sh/bun/blob/jarred/optional-fetch/src/bun.js/bindings/decodeURIComponentSIMD.cpp#L21-L271) and [JavaScriptCore structure caching](https://github.com/oven-sh/bun/blob/jarred/optional-fetch/src/bun.js/bindings/ServerRouteList.cpp#L100-L101) to push the performance limits of what modern hardware allows.
422
+
423
+ ### `fetch` request handler
424
+
425
+ The `fetch` handler handles incoming requests that weren't matched by any route. It receives a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object and returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) or [`Promise<Response>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
426
+
427
+ ```ts
428
+ Bun.serve({
429
+ fetch(req) {
430
+ const url = new URL(req.url);
431
+ if (url.pathname === "/") return new Response("Home page!");
432
+ if (url.pathname === "/blog") return new Response("Blog!");
433
+ return new Response("404!");
434
+ },
435
+ });
436
+ ```
437
+
438
+ The `fetch` handler supports async/await:
439
+
440
+ ```ts
441
+ import { sleep, serve } from "bun";
442
+ serve({
443
+ async fetch(req) {
444
+ const start = performance.now();
445
+ await sleep(10);
446
+ const end = performance.now();
447
+ return new Response(`Slept for ${end - start}ms`);
448
+ },
449
+ });
450
+ ```
451
+
452
+ Promise-based responses are also supported:
453
+
454
+ ```ts
455
+ Bun.serve({
456
+ fetch(req) {
457
+ // Forward the request to another server.
458
+ return fetch("https://example.com");
459
+ },
460
+ });
461
+ ```
462
+
463
+ You can also access the `Server` object from the `fetch` handler. It's the second argument passed to the `fetch` function.
464
+
465
+ ```ts
466
+ // `server` is passed in as the second argument to `fetch`.
467
+ const server = Bun.serve({
468
+ fetch(req, server) {
469
+ const ip = server.requestIP(req);
470
+ return new Response(`Your IP is ${ip}`);
471
+ },
472
+ });
473
+ ```
474
+
183
475
  ### Changing the `port` and `hostname`
184
476
 
185
477
  To configure which port and hostname the server will listen on, set `port` and `hostname` in the options object.
@@ -553,7 +845,7 @@ Update the server's handlers without restarting:
553
845
 
554
846
  ```ts
555
847
  const server = Bun.serve({
556
- static: {
848
+ routes: {
557
849
  "/api/version": Response.json({ version: "v1" }),
558
850
  },
559
851
  fetch(req) {
@@ -563,7 +855,7 @@ const server = Bun.serve({
563
855
 
564
856
  // Update to new handler
565
857
  server.reload({
566
- static: {
858
+ routes: {
567
859
  "/api/version": Response.json({ version: "v2" }),
568
860
  },
569
861
  fetch(req) {
@@ -572,7 +864,7 @@ server.reload({
572
864
  });
573
865
  ```
574
866
 
575
- This is useful for development and hot reloading. Only `fetch`, `error`, and `static` handlers can be updated.
867
+ This is useful for development and hot reloading. Only `fetch`, `error`, and `routes` can be updated.
576
868
 
577
869
  ## Per-Request Controls
578
870
 
package/docs/api/spawn.md CHANGED
@@ -110,7 +110,7 @@ You can read results from the subprocess via the `stdout` and `stderr` propertie
110
110
  ```ts
111
111
  const proc = Bun.spawn(["bun", "--version"]);
112
112
  const text = await new Response(proc.stdout).text();
113
- console.log(text); // => "1.2.3-canary.20250215T140625"
113
+ console.log(text); // => "1.2.3-canary.20250217T140554"
114
114
  ```
115
115
 
116
116
  Configure the output stream by passing one of the following values to `stdout/stderr`:
package/docs/api/sql.md CHANGED
@@ -165,13 +165,39 @@ await sql`
165
165
  `;
166
166
  ```
167
167
 
168
+ ## `sql``.simple()`
169
+
170
+ The PostgreSQL wire protocol supports two types of queries: "simple" and "extended". Simple queries can contain multiple statements but don't support parameters, while extended queries (the default) support parameters but only allow one statement.
171
+
172
+ To run multiple statements in a single query, use `sql``.simple()`:
173
+
174
+ ```ts
175
+ // Multiple statements in one query
176
+ await sql`
177
+ SELECT 1;
178
+ SELECT 2;
179
+ `.simple();
180
+ ```
181
+
182
+ Simple queries are often useful for database migrations and setup scripts.
183
+
184
+ Note that simple queries cannot use parameters (`${value}`). If you need parameters, you must split your query into separate statements.
185
+
168
186
  ### Unsafe Queries
169
187
 
170
- You can use the `sql.unsafe` function to execute raw SQL strings. Use this with caution, as it will not escape user input.
188
+ You can use the `sql.unsafe` function to execute raw SQL strings. Use this with caution, as it will not escape user input. Executing more than one command per query is allowed if no parameters are used.
171
189
 
172
190
  ```ts
191
+ // Multiple commands without parameters
192
+ const result = await sql.unsafe(`
193
+ SELECT ${userColumns} FROM users;
194
+ SELECT ${accountColumns} FROM accounts;
195
+ `);
196
+
197
+ // Using parameters (only one command is allowed)
173
198
  const result = await sql.unsafe(
174
- "SELECT " + columns + " FROM users WHERE id = " + id,
199
+ "SELECT " + dangerous + " FROM users WHERE id = $1",
200
+ [id],
175
201
  );
176
202
  ```
177
203
 
@@ -431,6 +457,34 @@ try {
431
457
  } // Automatically released
432
458
  ```
433
459
 
460
+ ## Prepared Statements
461
+
462
+ By default, Bun's SQL client automatically creates named prepared statements for queries where it can be inferred that the query is static. This provides better performance. However, you can change this behavior by setting `prepare: false` in the connection options:
463
+
464
+ ```ts
465
+ const sql = new SQL({
466
+ // ... other options ...
467
+ prepare: false, // Disable persisting named prepared statements on the server
468
+ });
469
+ ```
470
+
471
+ When `prepare: false` is set:
472
+
473
+ Queries are still executed using the "extended" protocol, but they are executed using [unnamed prepared statements](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY), an unnamed prepared statement lasts only until the next Parse statement specifying the unnamed statement as destination is issued.
474
+
475
+ - Parameter binding is still safe against SQL injection
476
+ - Each query is parsed and planned from scratch by the server
477
+ - Queries will not be [pipelined](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-PIPELINING)
478
+
479
+ You might want to use `prepare: false` when:
480
+
481
+ - Using PGBouncer in transaction mode (though since PGBouncer 1.21.0, protocol-level named prepared statements are supported when configured properly)
482
+ - Debugging query execution plans
483
+ - Working with dynamic SQL where query plans need to be regenerated frequently
484
+ - More than one command per query will not be supported (unless you use `sql``.simple()`)
485
+
486
+ Note that disabling prepared statements may impact performance for queries that are executed frequently with different parameters, as the server needs to parse and plan each query from scratch.
487
+
434
488
  ## Error Handling
435
489
 
436
490
  The client provides typed errors for different failure scenarios:
@@ -501,7 +555,7 @@ The client provides typed errors for different failure scenarios:
501
555
 
502
556
  ## Numbers and BigInt
503
557
 
504
- Bun's SQL client includes special handling for large numbers that exceed the range of a 53-bit integer. Heres how it works:
558
+ Bun's SQL client includes special handling for large numbers that exceed the range of a 53-bit integer. Here's how it works:
505
559
 
506
560
  ```ts
507
561
  import { sql } from "bun";
@@ -1,36 +1,50 @@
1
- Using `Bun.serve()`'s `static` option, you can run your frontend and backend in the same app with no extra steps.
1
+ Using `Bun.serve()`'s `routes` option, you can run your frontend and backend in the same app with no extra steps.
2
2
 
3
- To get started, import HTML files and pass them to the `static` option in `Bun.serve()`.
3
+ To get started, import HTML files and pass them to the `routes` option in `Bun.serve()`.
4
4
 
5
5
  ```ts
6
+ import { sql, serve } from "bun";
6
7
  import dashboard from "./dashboard.html";
7
8
  import homepage from "./index.html";
8
9
 
9
- const server = Bun.serve({
10
- // Add HTML imports to `static`
11
- static: {
12
- // Bundle & route index.html to "/"
10
+ const server = serve({
11
+ routes: {
12
+ // ** HTML imports **
13
+ // Bundle & route index.html to "/". This uses HTMLRewriter to scan the HTML for `<script>` and `<link>` tags, run's Bun's JavaScript & CSS bundler on them, transpiles any TypeScript, JSX, and TSX, downlevels CSS with Bun's CSS parser and serves the result.
13
14
  "/": homepage,
14
15
  // Bundle & route dashboard.html to "/dashboard"
15
16
  "/dashboard": dashboard,
17
+
18
+ // ** API endpoints ** (Bun v1.2.3+ required)
19
+ "/api/users": {
20
+ async GET(req) {
21
+ const users = await sql`SELECT * FROM users`;
22
+ return Response.json(users);
23
+ },
24
+ async POST(req) {
25
+ const { name, email } = await req.json();
26
+ const [user] =
27
+ await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`;
28
+ return Response.json(user);
29
+ },
30
+ },
31
+ "/api/users/:id": async req => {
32
+ const { id } = req.params;
33
+ const [user] = await sql`SELECT * FROM users WHERE id = ${id}`;
34
+ return Response.json(user);
35
+ },
16
36
  },
17
37
 
18
38
  // Enable development mode for:
19
39
  // - Detailed error messages
20
- // - Rebuild on request
40
+ // - Hot reloading (Bun v1.2.3+ required)
21
41
  development: true,
22
42
 
23
- // Handle API requests
24
- async fetch(req) {
25
- // ...your API code
26
- if (req.url.endsWith("/api/users")) {
27
- const users = await Bun.sql`SELECT * FROM users`;
28
- return Response.json(users);
29
- }
30
-
31
- // Return 404 for unmatched routes
32
- return new Response("Not Found", { status: 404 });
33
- },
43
+ // Prior to v1.2.3, the `fetch` option was used to handle all API requests. It is now optional.
44
+ // async fetch(req) {
45
+ // // Return 404 for unmatched routes
46
+ // return new Response("Not Found", { status: 404 });
47
+ // },
34
48
  });
35
49
 
36
50
  console.log(`Listening on ${server.url}`);
@@ -55,7 +69,7 @@ These HTML files are used as routes in Bun's dev server you can pass to `Bun.ser
55
69
 
56
70
  ```ts
57
71
  Bun.serve({
58
- static: {
72
+ routes: {
59
73
  "/": homepage,
60
74
  "/dashboard": dashboard,
61
75
  }
@@ -113,7 +127,7 @@ import dashboard from "../public/dashboard.html";
113
127
  import { serve } from "bun";
114
128
 
115
129
  serve({
116
- static: {
130
+ routes: {
117
131
  "/": dashboard,
118
132
  },
119
133
 
@@ -171,7 +185,7 @@ import homepage from "./index.html";
171
185
  import dashboard from "./dashboard.html";
172
186
 
173
187
  Bun.serve({
174
- static: {
188
+ routes: {
175
189
  "/": homepage,
176
190
  "/dashboard": dashboard,
177
191
  }
@@ -249,6 +263,8 @@ plugins = ["./my-plugin-implementation.ts"]
249
263
 
250
264
  Bun will lazily resolve and load each plugin and use them to bundle your routes.
251
265
 
266
+ Note: this is currently in `bunfig.toml` to make it possible to know statically which plugins are in use when we eventually integrate this with the `bun build` CLI. These plugins work in `Bun.build()`'s JS API, but are not yet supported in the CLI.
267
+
252
268
  ## How this works
253
269
 
254
270
  Bun uses [`HTMLRewriter`](/docs/api/html-rewriter) to scan for `<script>` and `<link>` tags in HTML files, uses them as entrypoints for [Bun's bundler](/docs/bundler), generates an optimized bundle for the JavaScript/TypeScript/TSX/JSX and CSS files, and serves the result.
@@ -293,5 +309,5 @@ This works similarly to how [`Bun.build` processes HTML files](/docs/bundler/htm
293
309
 
294
310
  ## This is a work in progress
295
311
 
296
- - Client-side hot reloading isn't wired up yet. It will be in the future.
312
+ - ~Client-side hot reloading isn't wired up yet. It will be in the future.~ New in Bun v1.2.3
297
313
  - This doesn't support `bun build` yet. It also will in the future.
@@ -301,6 +301,6 @@ This is a small wrapper around Bun's support for HTML imports in JavaScript.
301
301
 
302
302
  ### Adding a backend to your frontend
303
303
 
304
- To add a backend to your frontend, you can use the `"static"` option in `Bun.serve`.
304
+ To add a backend to your frontend, you can use the `"routes"` option in `Bun.serve`.
305
305
 
306
306
  Learn more in [the full-stack docs](/docs/bundler/fullstack).
@@ -7,7 +7,7 @@ Use `bun publish` to publish a package to the npm registry.
7
7
  $ bun publish
8
8
 
9
9
  ## Output
10
- bun publish v1.2.3-canary.20250215T140625 (ca7428e9)
10
+ bun publish v1.2.3-canary.20250217T140554 (ca7428e9)
11
11
 
12
12
  packed 203B package.json
13
13
  packed 224B README.md
@@ -9,7 +9,7 @@ $ bunx nuxi init my-nuxt-app
9
9
  ✔ Which package manager would you like to use?
10
10
  bun
11
11
  ◐ Installing dependencies...
12
- bun install v1.2.3-canary.20250215T140625 (16b4bf34)
12
+ bun install v1.2.3-canary.20250217T140554 (16b4bf34)
13
13
  + @nuxt/devtools@0.8.2
14
14
  + nuxt@3.7.0
15
15
  785 packages installed [2.67s]
@@ -16,7 +16,7 @@ This will add the package to `peerDependencies` in `package.json`.
16
16
  ```json-diff
17
17
  {
18
18
  "peerDependencies": {
19
- + "@types/bun": "^1.2.3-canary.20250215T140625"
19
+ + "@types/bun": "^1.2.3-canary.20250217T140554"
20
20
  }
21
21
  }
22
22
  ```
@@ -28,7 +28,7 @@ Running `bun install` will install peer dependencies by default, unless marked o
28
28
  ```json-diff
29
29
  {
30
30
  "peerDependencies": {
31
- "@types/bun": "^1.2.3-canary.20250215T140625"
31
+ "@types/bun": "^1.2.3-canary.20250217T140554"
32
32
  },
33
33
  "peerDependenciesMeta": {
34
34
  + "@types/bun": {
@@ -97,7 +97,7 @@ $ bun update
97
97
  $ bun update @types/bun --latest
98
98
 
99
99
  # Update a dependency to a specific version
100
- $ bun update @types/bun@1.2.3-canary.20250215T140625
100
+ $ bun update @types/bun@1.2.3-canary.20250217T140554
101
101
 
102
102
  # Update all dependencies to the latest versions
103
103
  $ bun update --latest
@@ -21,7 +21,7 @@ Here's what the output of a typical test run looks like. In this case, there are
21
21
 
22
22
  ```sh
23
23
  $ bun test
24
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
24
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
25
25
 
26
26
  test.test.js:
27
27
  ✓ add [0.87ms]
@@ -47,7 +47,7 @@ To only run certain test files, pass a positional argument to `bun test`. The ru
47
47
 
48
48
  ```sh
49
49
  $ bun test test3
50
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
50
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
51
51
 
52
52
  test3.test.js:
53
53
  ✓ add [1.40ms]
@@ -85,7 +85,7 @@ Adding `-t add` will only run tests with "add" in the name. This works with test
85
85
 
86
86
  ```sh
87
87
  $ bun test -t add
88
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
88
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
89
89
 
90
90
  test.test.js:
91
91
  ✓ add [1.79ms]
@@ -18,7 +18,7 @@ The first time this test is executed, Bun will evaluate the value passed into `e
18
18
 
19
19
  ```sh
20
20
  $ bun test test/snap
21
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
21
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
22
22
 
23
23
  test/snap.test.ts:
24
24
  ✓ snapshot [1.48ms]
@@ -61,7 +61,7 @@ Later, when this test file is executed again, Bun will read the snapshot file an
61
61
 
62
62
  ```sh
63
63
  $ bun test
64
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
64
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
65
65
 
66
66
  test/snap.test.ts:
67
67
  ✓ snapshot [1.05ms]
@@ -78,7 +78,7 @@ To update snapshots, use the `--update-snapshots` flag.
78
78
 
79
79
  ```sh
80
80
  $ bun test --update-snapshots
81
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
81
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
82
82
 
83
83
  test/snap.test.ts:
84
84
  ✓ snapshot [0.86ms]
@@ -29,7 +29,7 @@ To regenerate snapshots, use the `--update-snapshots` flag.
29
29
 
30
30
  ```sh
31
31
  $ bun test --update-snapshots
32
- bun test v1.2.3-canary.20250215T140625 (9c68abdb)
32
+ bun test v1.2.3-canary.20250217T140554 (9c68abdb)
33
33
 
34
34
  test/snap.test.ts:
35
35
  ✓ snapshot [0.86ms]
@@ -5,7 +5,7 @@ name: Get the current Bun version
5
5
  Get the current version of Bun in a semver format.
6
6
 
7
7
  ```ts#index.ts
8
- Bun.version; // => "1.2.3-canary.20250215T140625"
8
+ Bun.version; // => "1.2.3-canary.20250217T140554"
9
9
  ```
10
10
 
11
11
  ---
@@ -14,7 +14,7 @@ Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1. Us
14
14
  ```bash#macOS/Linux_(curl)
15
15
  $ curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
16
16
  # to install a specific version
17
- $ curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.3-canary.20250215T140625"
17
+ $ curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.3-canary.20250217T140554"
18
18
  ```
19
19
 
20
20
  ```bash#npm
@@ -188,10 +188,10 @@ Since Bun is a single binary, you can install older versions of Bun by re-runnin
188
188
 
189
189
  ### Installing a specific version of Bun on Linux/Mac
190
190
 
191
- To install a specific version of Bun, you can pass the git tag of the version you want to install to the install script, such as `bun-v1.2.0` or `bun-v1.2.3-canary.20250215T140625`.
191
+ To install a specific version of Bun, you can pass the git tag of the version you want to install to the install script, such as `bun-v1.2.0` or `bun-v1.2.3-canary.20250217T140554`.
192
192
 
193
193
  ```sh
194
- $ curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.3-canary.20250215T140625"
194
+ $ curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.3-canary.20250217T140554"
195
195
  ```
196
196
 
197
197
  ### Installing a specific version of Bun on Windows
@@ -200,7 +200,7 @@ On Windows, you can install a specific version of Bun by passing the version num
200
200
 
201
201
  ```sh
202
202
  # PowerShell:
203
- $ iex "& {$(irm https://bun.sh/install.ps1)} -Version 1.2.3-canary.20250215T140625"
203
+ $ iex "& {$(irm https://bun.sh/install.ps1)} -Version 1.2.3-canary.20250217T140554"
204
204
  ```
205
205
 
206
206
  ## Downloading Bun binaries directly
@@ -124,11 +124,11 @@ await fetch("https://example.com", {
124
124
  This prints the `fetch` request as a single-line `curl` command to let you copy-paste into your terminal to replicate the request.
125
125
 
126
126
  ```sh
127
- [fetch] $ curl --http1.1 "https://example.com/" -X POST -H "content-type: application/json" -H "Connection: keep-alive" -H "User-Agent: Bun/1.2.3-canary.20250215T140625" -H "Accept: */*" -H "Host: example.com" -H "Accept-Encoding: gzip, deflate, br" --compressed -H "Content-Length: 13" --data-raw "{\"foo\":\"bar\"}"
127
+ [fetch] $ curl --http1.1 "https://example.com/" -X POST -H "content-type: application/json" -H "Connection: keep-alive" -H "User-Agent: Bun/1.2.3-canary.20250217T140554" -H "Accept: */*" -H "Host: example.com" -H "Accept-Encoding: gzip, deflate, br" --compressed -H "Content-Length: 13" --data-raw "{\"foo\":\"bar\"}"
128
128
  [fetch] > HTTP/1.1 POST https://example.com/
129
129
  [fetch] > content-type: application/json
130
130
  [fetch] > Connection: keep-alive
131
- [fetch] > User-Agent: Bun/1.2.3-canary.20250215T140625
131
+ [fetch] > User-Agent: Bun/1.2.3-canary.20250217T140554
132
132
  [fetch] > Accept: */*
133
133
  [fetch] > Host: example.com
134
134
  [fetch] > Accept-Encoding: gzip, deflate, br
@@ -170,7 +170,7 @@ This prints the following to the console:
170
170
  [fetch] > HTTP/1.1 POST https://example.com/
171
171
  [fetch] > content-type: application/json
172
172
  [fetch] > Connection: keep-alive
173
- [fetch] > User-Agent: Bun/1.2.3-canary.20250215T140625
173
+ [fetch] > User-Agent: Bun/1.2.3-canary.20250217T140554
174
174
  [fetch] > Accept: */*
175
175
  [fetch] > Host: example.com
176
176
  [fetch] > Accept-Encoding: gzip, deflate, br
package/docs/test/dom.md CHANGED
@@ -55,7 +55,7 @@ Let's run this test with `bun test`:
55
55
 
56
56
  ```bash
57
57
  $ bun test
58
- bun test v1.2.3-canary.20250215T140625
58
+ bun test v1.2.3-canary.20250217T140554
59
59
 
60
60
  dom.test.ts:
61
61
  ✓ dom test [0.82ms]
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.3-canary.20250215T140625",
2
+ "version": "1.2.3-canary.20250217T140554",
3
3
  "name": "bun-types",
4
4
  "license": "MIT",
5
5
  "main": "",