worked on GarageApp stuff
This commit is contained in:
parent
60aaf17af3
commit
eb606572b0
51919 changed files with 2168177 additions and 18 deletions
105
node_modules/bun-types/CLAUDE.md
generated
vendored
Normal file
105
node_modules/bun-types/CLAUDE.md
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
Default to using Bun instead of Node.js.
|
||||
|
||||
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
||||
- Use `bun test` instead of `jest` or `vitest`
|
||||
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
||||
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
||||
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
||||
- Bun automatically loads .env, so don't use dotenv.
|
||||
|
||||
## APIs
|
||||
|
||||
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
||||
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
||||
- `Bun.redis` for Redis. Don't use `ioredis`.
|
||||
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
||||
- `WebSocket` is built-in. Don't use `ws`.
|
||||
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||
- Bun.$`ls` instead of execa.
|
||||
|
||||
## Testing
|
||||
|
||||
Use `bun test` to run tests.
|
||||
|
||||
```ts#index.test.ts
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("hello world", () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
## Frontend
|
||||
|
||||
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
||||
|
||||
Server:
|
||||
|
||||
```ts#index.ts
|
||||
import index from "./index.html"
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
"/": index,
|
||||
"/api/users/:id": {
|
||||
GET: (req) => {
|
||||
return new Response(JSON.stringify({ id: req.params.id }));
|
||||
},
|
||||
},
|
||||
},
|
||||
// optional websocket support
|
||||
websocket: {
|
||||
open: (ws) => {
|
||||
ws.send("Hello, world!");
|
||||
},
|
||||
message: (ws, message) => {
|
||||
ws.send(message);
|
||||
},
|
||||
close: (ws) => {
|
||||
// handle close
|
||||
}
|
||||
},
|
||||
development: {
|
||||
hmr: true,
|
||||
console: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
||||
|
||||
```html#index.html
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello, world!</h1>
|
||||
<script type="module" src="./frontend.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
With the following `frontend.tsx`:
|
||||
|
||||
```tsx#frontend.tsx
|
||||
import React from "react";
|
||||
|
||||
// import .css files directly and it works
|
||||
import './index.css';
|
||||
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
const root = createRoot(document.body);
|
||||
|
||||
export default function Frontend() {
|
||||
return <h1>Hello, world!</h1>;
|
||||
}
|
||||
|
||||
root.render(<Frontend />);
|
||||
```
|
||||
|
||||
Then, run index.ts
|
||||
|
||||
```sh
|
||||
bun --hot ./index.ts
|
||||
```
|
||||
|
||||
For more information, read the Bun API docs in `docs/**.md`.
|
||||
33
node_modules/bun-types/README.md
generated
vendored
Normal file
33
node_modules/bun-types/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# TypeScript types for Bun
|
||||
|
||||
<p align="center">
|
||||
<a href="https://bun.com"><img src="https://bun.com/logo@2x.png" alt="Logo"></a>
|
||||
</p>
|
||||
|
||||
These are the type definitions for Bun's JavaScript runtime APIs.
|
||||
|
||||
# Installation
|
||||
|
||||
Install the `@types/bun` npm package:
|
||||
|
||||
```bash
|
||||
# yarn/npm/pnpm work too
|
||||
# @types/bun is an ordinary npm package
|
||||
bun add -D @types/bun
|
||||
```
|
||||
|
||||
That's it! VS Code and TypeScript automatically load `@types/*` packages into your project, so the `Bun` global and all `bun:*` modules should be available immediately.
|
||||
|
||||
# Contributing
|
||||
|
||||
The `@types/bun` package is a shim that loads `bun-types`. The `bun-types` package lives in the Bun repo under `packages/bun-types`.
|
||||
|
||||
To add a new file, add it under `packages/bun-types`. Then add a [triple-slash directive](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) pointing to it inside [./index.d.ts](./index.d.ts).
|
||||
|
||||
```diff
|
||||
+ /// <reference path="./newfile.d.ts" />
|
||||
```
|
||||
|
||||
```bash
|
||||
bun build
|
||||
```
|
||||
8339
node_modules/bun-types/bun.d.ts
generated
vendored
Normal file
8339
node_modules/bun-types/bun.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
node_modules/bun-types/bun.ns.d.ts
generated
vendored
Normal file
7
node_modules/bun-types/bun.ns.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import * as BunModule from "bun";
|
||||
|
||||
declare global {
|
||||
export import Bun = BunModule;
|
||||
}
|
||||
|
||||
export {};
|
||||
92
node_modules/bun-types/deprecated.d.ts
generated
vendored
Normal file
92
node_modules/bun-types/deprecated.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
declare module "bun" {
|
||||
interface BunMessageEvent<T> {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
initMessageEvent(
|
||||
type: string,
|
||||
bubbles?: boolean,
|
||||
cancelable?: boolean,
|
||||
data?: any,
|
||||
origin?: string,
|
||||
lastEventId?: string,
|
||||
source?: null,
|
||||
): void;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link SQL.Query Bun.SQL.Query} */
|
||||
type SQLQuery<T = any> = SQL.Query<T>;
|
||||
|
||||
/** @deprecated Use {@link SQL.TransactionContextCallback Bun.SQL.TransactionContextCallback} */
|
||||
type SQLTransactionContextCallback<T> = SQL.TransactionContextCallback<T>;
|
||||
|
||||
/** @deprecated Use {@link SQL.SavepointContextCallback Bun.SQL.SavepointContextCallback} */
|
||||
type SQLSavepointContextCallback<T> = SQL.SavepointContextCallback<T>;
|
||||
|
||||
/** @deprecated Use {@link SQL.Options Bun.SQL.Options} */
|
||||
type SQLOptions = SQL.Options;
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to `ErrorLike`
|
||||
*/
|
||||
type Errorlike = ErrorLike;
|
||||
|
||||
interface TLSOptions {
|
||||
/**
|
||||
* File path to a TLS key
|
||||
*
|
||||
* To enable TLS, this option is required.
|
||||
*
|
||||
* @deprecated since v0.6.3 - Use `key: Bun.file(path)` instead.
|
||||
*/
|
||||
keyFile?: string;
|
||||
|
||||
/**
|
||||
* File path to a TLS certificate
|
||||
*
|
||||
* To enable TLS, this option is required.
|
||||
*
|
||||
* @deprecated since v0.6.3 - Use `cert: Bun.file(path)` instead.
|
||||
*/
|
||||
certFile?: string;
|
||||
|
||||
/**
|
||||
* File path to a .pem file for a custom root CA
|
||||
*
|
||||
* @deprecated since v0.6.3 - Use `ca: Bun.file(path)` instead.
|
||||
*/
|
||||
caFile?: string;
|
||||
}
|
||||
|
||||
/** @deprecated This type is unused in Bun's declarations and may be removed in the future */
|
||||
type ReadableIO = ReadableStream<Uint8Array> | number | undefined;
|
||||
}
|
||||
|
||||
declare namespace NodeJS {
|
||||
interface Process {
|
||||
/**
|
||||
* @deprecated This is deprecated; use the "node:assert" module instead.
|
||||
*/
|
||||
assert(value: unknown, message?: string | Error): asserts value;
|
||||
}
|
||||
}
|
||||
|
||||
interface CustomEvent<T = any> {
|
||||
/** @deprecated */
|
||||
initCustomEvent(type: string, bubbles?: boolean, cancelable?: boolean, detail?: T): void;
|
||||
}
|
||||
|
||||
interface DOMException {
|
||||
/** @deprecated */
|
||||
readonly code: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to `BuildMessage`
|
||||
*/
|
||||
declare var BuildError: typeof BuildMessage;
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to `ResolveMessage`
|
||||
*/
|
||||
declare var ResolveError: typeof ResolveMessage;
|
||||
187
node_modules/bun-types/devserver.d.ts
generated
vendored
Normal file
187
node_modules/bun-types/devserver.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
declare module "bun" {
|
||||
type HMREventNames =
|
||||
| "beforeUpdate"
|
||||
| "afterUpdate"
|
||||
| "beforeFullReload"
|
||||
| "beforePrune"
|
||||
| "invalidate"
|
||||
| "error"
|
||||
| "ws:disconnect"
|
||||
| "ws:connect";
|
||||
|
||||
/**
|
||||
* The event names for the dev server
|
||||
*/
|
||||
type HMREvent = `bun:${HMREventNames}` | (string & {});
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
/**
|
||||
* Hot module replacement APIs. This value is `undefined` in production and
|
||||
* can be used in an `if` statement to check if HMR APIs are available
|
||||
*
|
||||
* ```ts
|
||||
* if (import.meta.hot) {
|
||||
* // HMR APIs are available
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* However, this check is usually not needed as Bun will dead-code-eliminate
|
||||
* calls to all of the HMR APIs in production builds.
|
||||
*
|
||||
* https://bun.com/docs/bundler/hmr
|
||||
*/
|
||||
hot: {
|
||||
/**
|
||||
* `import.meta.hot.data` maintains state between module instances during
|
||||
* hot replacement, enabling data transfer from previous to new versions.
|
||||
* When `import.meta.hot.data` is written to, Bun will mark this module as
|
||||
* capable of self-accepting (equivalent of calling `accept()`).
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const root = import.meta.hot.data.root ??= createRoot(elem);
|
||||
* root.render(<App />); // re-use an existing root
|
||||
* ```
|
||||
*
|
||||
* In production, `data` is inlined to be `{}`. This is handy because Bun
|
||||
* knows it can minify `{}.prop ??= value` into `value` in production.
|
||||
*/
|
||||
data: any;
|
||||
|
||||
/**
|
||||
* Indicate that this module can be replaced simply by re-evaluating the
|
||||
* file. After a hot update, importers of this module will be
|
||||
* automatically patched.
|
||||
*
|
||||
* When `import.meta.hot.accept` is not used, the page will reload when
|
||||
* the file updates, and a console message shows which files were checked.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { getCount } from "./foo";
|
||||
*
|
||||
* console.log("count is ", getCount());
|
||||
*
|
||||
* import.meta.hot.accept();
|
||||
* ```
|
||||
*/
|
||||
accept(): void;
|
||||
|
||||
/**
|
||||
* Indicate that this module can be replaced by evaluating the new module,
|
||||
* and then calling the callback with the new module. In this mode, the
|
||||
* importers do not get patched. This is to match Vite, which is unable
|
||||
* to patch their import statements. Prefer using `import.meta.hot.accept()`
|
||||
* without an argument as it usually makes your code easier to understand.
|
||||
*
|
||||
* When `import.meta.hot.accept` is not used, the page will reload when
|
||||
* the file updates, and a console message shows which files were checked.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* export const count = 0;
|
||||
*
|
||||
* import.meta.hot.accept((newModule) => {
|
||||
* if (newModule) {
|
||||
* // newModule is undefined when SyntaxError happened
|
||||
* console.log('updated: count is now ', newModule.count)
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* In production, calls to this are dead-code-eliminated.
|
||||
*/
|
||||
accept(cb: (newModule: any | undefined) => void): void;
|
||||
|
||||
/**
|
||||
* Indicate that a dependency's module can be accepted. When the dependency
|
||||
* is updated, the callback will be called with the new module.
|
||||
*
|
||||
* When `import.meta.hot.accept` is not used, the page will reload when
|
||||
* the file updates, and a console message shows which files were checked.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import.meta.hot.accept('./foo', (newModule) => {
|
||||
* if (newModule) {
|
||||
* // newModule is undefined when SyntaxError happened
|
||||
* console.log('updated: count is now ', newModule.count)
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
accept(specifier: string, callback: (newModule: any) => void): void;
|
||||
|
||||
/**
|
||||
* Indicate that a dependency's module can be accepted. This variant
|
||||
* accepts an array of dependencies, where the callback will receive
|
||||
* the one updated module, and `undefined` for the rest.
|
||||
*
|
||||
* When `import.meta.hot.accept` is not used, the page will reload when
|
||||
* the file updates, and a console message shows which files were checked.
|
||||
*/
|
||||
accept(specifiers: string[], callback: (newModules: (any | undefined)[]) => void): void;
|
||||
|
||||
/**
|
||||
* Attach an on-dispose callback. This is called:
|
||||
* - Just before the module is replaced with another copy (before the next is loaded)
|
||||
* - After the module is detached (removing all imports to this module)
|
||||
*
|
||||
* This callback is not called on route navigation or when the browser tab closes.
|
||||
*
|
||||
* Returning a promise will delay module replacement until the module is
|
||||
* disposed. All dispose callbacks are called in parallel.
|
||||
*/
|
||||
dispose(cb: (data: any) => void | Promise<void>): void;
|
||||
|
||||
/**
|
||||
* No-op
|
||||
* @deprecated
|
||||
*/
|
||||
decline(): void;
|
||||
|
||||
// NOTE TO CONTRIBUTORS ////////////////////////////////////////
|
||||
// Callback is currently never called for `.prune()` //
|
||||
// so the types are commented out until we support it. //
|
||||
////////////////////////////////////////////////////////////////
|
||||
// /**
|
||||
// * Attach a callback that is called when the module is removed from the module graph.
|
||||
// *
|
||||
// * This can be used to clean up resources that were created when the module was loaded.
|
||||
// * Unlike `import.meta.hot.dispose()`, this pairs much better with `accept` and `data` to manage stateful resources.
|
||||
// *
|
||||
// * @example
|
||||
// * ```ts
|
||||
// * export const ws = (import.meta.hot.data.ws ??= new WebSocket(location.origin));
|
||||
// *
|
||||
// * import.meta.hot.prune(() => {
|
||||
// * ws.close();
|
||||
// * });
|
||||
// * ```
|
||||
// */
|
||||
// prune(callback: () => void): void;
|
||||
|
||||
/**
|
||||
* Listen for an event from the dev server
|
||||
*
|
||||
* For compatibility with Vite, event names are also available via vite:* prefix instead of bun:*.
|
||||
*
|
||||
* https://bun.com/docs/bundler/hmr#import-meta-hot-on-and-off
|
||||
* @param event The event to listen to
|
||||
* @param callback The callback to call when the event is emitted
|
||||
*/
|
||||
on(event: Bun.HMREvent, callback: () => void): void;
|
||||
|
||||
/**
|
||||
* Stop listening for an event from the dev server
|
||||
*
|
||||
* For compatibility with Vite, event names are also available via vite:* prefix instead of bun:*.
|
||||
*
|
||||
* https://bun.com/docs/bundler/hmr#import-meta-hot-on-and-off
|
||||
* @param event The event to stop listening to
|
||||
* @param callback The callback to stop listening to
|
||||
*/
|
||||
off(event: Bun.HMREvent, callback: () => void): void;
|
||||
};
|
||||
}
|
||||
1038
node_modules/bun-types/docs/api/binary-data.md
generated
vendored
Normal file
1038
node_modules/bun-types/docs/api/binary-data.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
197
node_modules/bun-types/docs/api/cc.md
generated
vendored
Normal file
197
node_modules/bun-types/docs/api/cc.md
generated
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
`bun:ffi` has experimental support for compiling and running C from JavaScript with low overhead.
|
||||
|
||||
## Usage (cc in `bun:ffi`)
|
||||
|
||||
See the [introduction blog post](https://bun.com/blog/compile-and-run-c-in-js) for more information.
|
||||
|
||||
JavaScript:
|
||||
|
||||
```ts#hello.js
|
||||
import { cc } from "bun:ffi";
|
||||
import source from "./hello.c" with { type: "file" };
|
||||
|
||||
const {
|
||||
symbols: { hello },
|
||||
} = cc({
|
||||
source,
|
||||
symbols: {
|
||||
hello: {
|
||||
args: [],
|
||||
returns: "int",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log("What is the answer to the universe?", hello());
|
||||
```
|
||||
|
||||
C source:
|
||||
|
||||
```c#hello.c
|
||||
int hello() {
|
||||
return 42;
|
||||
}
|
||||
```
|
||||
|
||||
When you run `hello.js`, it will print:
|
||||
|
||||
```sh
|
||||
$ bun hello.js
|
||||
What is the answer to the universe? 42
|
||||
```
|
||||
|
||||
Under the hood, `cc` uses [TinyCC](https://bellard.org/tcc/) to compile the C code and then link it with the JavaScript runtime, efficiently converting types in-place.
|
||||
|
||||
### Primitive types
|
||||
|
||||
The same `FFIType` values in [`dlopen`](/docs/api/ffi) are supported in `cc`.
|
||||
|
||||
| `FFIType` | C Type | Aliases |
|
||||
| ---------- | -------------- | --------------------------- |
|
||||
| cstring | `char*` | |
|
||||
| function | `(void*)(*)()` | `fn`, `callback` |
|
||||
| ptr | `void*` | `pointer`, `void*`, `char*` |
|
||||
| i8 | `int8_t` | `int8_t` |
|
||||
| i16 | `int16_t` | `int16_t` |
|
||||
| i32 | `int32_t` | `int32_t`, `int` |
|
||||
| i64 | `int64_t` | `int64_t` |
|
||||
| i64_fast | `int64_t` | |
|
||||
| u8 | `uint8_t` | `uint8_t` |
|
||||
| u16 | `uint16_t` | `uint16_t` |
|
||||
| u32 | `uint32_t` | `uint32_t` |
|
||||
| u64 | `uint64_t` | `uint64_t` |
|
||||
| u64_fast | `uint64_t` | |
|
||||
| f32 | `float` | `float` |
|
||||
| f64 | `double` | `double` |
|
||||
| bool | `bool` | |
|
||||
| char | `char` | |
|
||||
| napi_env | `napi_env` | |
|
||||
| napi_value | `napi_value` | |
|
||||
|
||||
### Strings, objects, and non-primitive types
|
||||
|
||||
To make it easier to work with strings, objects, and other non-primitive types that don't map 1:1 to C types, `cc` supports N-API.
|
||||
|
||||
To pass or receive a JavaScript values without any type conversions from a C function, you can use `napi_value`.
|
||||
|
||||
You can also pass a `napi_env` to receive the N-API environment used to call the JavaScript function.
|
||||
|
||||
#### Returning a C string to JavaScript
|
||||
|
||||
For example, if you have a string in C, you can return it to JavaScript like this:
|
||||
|
||||
```ts#hello.js
|
||||
import { cc } from "bun:ffi";
|
||||
import source from "./hello.c" with { type: "file" };
|
||||
|
||||
const {
|
||||
symbols: { hello },
|
||||
} = cc({
|
||||
source,
|
||||
symbols: {
|
||||
hello: {
|
||||
args: ["napi_env"],
|
||||
returns: "napi_value",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = hello();
|
||||
```
|
||||
|
||||
And in C:
|
||||
|
||||
```c#hello.c
|
||||
#include <node/node_api.h>
|
||||
|
||||
napi_value hello(napi_env env) {
|
||||
napi_value result;
|
||||
napi_create_string_utf8(env, "Hello, Napi!", NAPI_AUTO_LENGTH, &result);
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
You can also use this to return other types like objects and arrays:
|
||||
|
||||
```c#hello.c
|
||||
#include <node/node_api.h>
|
||||
|
||||
napi_value hello(napi_env env) {
|
||||
napi_value result;
|
||||
napi_create_object(env, &result);
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### `cc` Reference
|
||||
|
||||
#### `library: string[]`
|
||||
|
||||
The `library` array is used to specify the libraries that should be linked with the C code.
|
||||
|
||||
```ts
|
||||
type Library = string[];
|
||||
|
||||
cc({
|
||||
source: "hello.c",
|
||||
library: ["sqlite3"],
|
||||
});
|
||||
```
|
||||
|
||||
#### `symbols`
|
||||
|
||||
The `symbols` object is used to specify the functions and variables that should be exposed to JavaScript.
|
||||
|
||||
```ts
|
||||
type Symbols = {
|
||||
[key: string]: {
|
||||
args: FFIType[];
|
||||
returns: FFIType;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
#### `source`
|
||||
|
||||
The `source` is a file path to the C code that should be compiled and linked with the JavaScript runtime.
|
||||
|
||||
```ts
|
||||
type Source = string | URL | BunFile;
|
||||
|
||||
cc({
|
||||
source: "hello.c",
|
||||
symbols: {
|
||||
hello: {
|
||||
args: [],
|
||||
returns: "int",
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### `flags: string | string[]`
|
||||
|
||||
The `flags` is an optional array of strings that should be passed to the TinyCC compiler.
|
||||
|
||||
```ts
|
||||
type Flags = string | string[];
|
||||
```
|
||||
|
||||
These are flags like `-I` for include directories and `-D` for preprocessor definitions.
|
||||
|
||||
#### `define: Record<string, string>`
|
||||
|
||||
The `define` is an optional object that should be passed to the TinyCC compiler.
|
||||
|
||||
```ts
|
||||
type Defines = Record<string, string>;
|
||||
|
||||
cc({
|
||||
source: "hello.c",
|
||||
define: {
|
||||
"NDEBUG": "1",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
These are preprocessor definitions passed to the TinyCC compiler.
|
||||
262
node_modules/bun-types/docs/api/color.md
generated
vendored
Normal file
262
node_modules/bun-types/docs/api/color.md
generated
vendored
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
`Bun.color(input, outputFormat?)` leverages Bun's CSS parser to parse, normalize, and convert colors from user input to a variety of output formats, including:
|
||||
|
||||
| Format | Example |
|
||||
| ------------ | -------------------------------- |
|
||||
| `"css"` | `"red"` |
|
||||
| `"ansi"` | `"\x1b[38;2;255;0;0m"` |
|
||||
| `"ansi-16"` | `"\x1b[38;5;\tm"` |
|
||||
| `"ansi-256"` | `"\x1b[38;5;196m"` |
|
||||
| `"ansi-16m"` | `"\x1b[38;2;255;0;0m"` |
|
||||
| `"number"` | `0x1a2b3c` |
|
||||
| `"rgb"` | `"rgb(255, 99, 71)"` |
|
||||
| `"rgba"` | `"rgba(255, 99, 71, 0.5)"` |
|
||||
| `"hsl"` | `"hsl(120, 50%, 50%)"` |
|
||||
| `"hex"` | `"#1a2b3c"` |
|
||||
| `"HEX"` | `"#1A2B3C"` |
|
||||
| `"{rgb}"` | `{ r: 255, g: 99, b: 71 }` |
|
||||
| `"{rgba}"` | `{ r: 255, g: 99, b: 71, a: 1 }` |
|
||||
| `"[rgb]"` | `[ 255, 99, 71 ]` |
|
||||
| `"[rgba]"` | `[ 255, 99, 71, 255]` |
|
||||
|
||||
There are many different ways to use this API:
|
||||
|
||||
- Validate and normalize colors to persist in a database (`number` is the most database-friendly)
|
||||
- Convert colors to different formats
|
||||
- Colorful logging beyond the 16 colors many use today (use `ansi` if you don't want to figure out what the user's terminal supports, otherwise use `ansi-16`, `ansi-256`, or `ansi-16m` for how many colors the terminal supports)
|
||||
- Format colors for use in CSS injected into HTML
|
||||
- Get the `r`, `g`, `b`, and `a` color components as JavaScript objects or numbers from a CSS color string
|
||||
|
||||
You can think of this as an alternative to the popular npm packages [`color`](https://github.com/Qix-/color) and [`tinycolor2`](https://github.com/bgrins/TinyColor) except with full support for parsing CSS color strings and zero dependencies built directly into Bun.
|
||||
|
||||
### Flexible input
|
||||
|
||||
You can pass in any of the following:
|
||||
|
||||
- Standard CSS color names like `"red"`
|
||||
- Numbers like `0xff0000`
|
||||
- Hex strings like `"#f00"`
|
||||
- RGB strings like `"rgb(255, 0, 0)"`
|
||||
- RGBA strings like `"rgba(255, 0, 0, 1)"`
|
||||
- HSL strings like `"hsl(0, 100%, 50%)"`
|
||||
- HSLA strings like `"hsla(0, 100%, 50%, 1)"`
|
||||
- RGB objects like `{ r: 255, g: 0, b: 0 }`
|
||||
- RGBA objects like `{ r: 255, g: 0, b: 0, a: 1 }`
|
||||
- RGB arrays like `[255, 0, 0]`
|
||||
- RGBA arrays like `[255, 0, 0, 255]`
|
||||
- LAB strings like `"lab(50% 50% 50%)"`
|
||||
- ... anything else that CSS can parse as a single color value
|
||||
|
||||
### Format colors as CSS
|
||||
|
||||
The `"css"` format outputs valid CSS for use in stylesheets, inline styles, CSS variables, css-in-js, etc. It returns the most compact representation of the color as a string.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "css"); // "red"
|
||||
Bun.color(0xff0000, "css"); // "#f000"
|
||||
Bun.color("#f00", "css"); // "red"
|
||||
Bun.color("#ff0000", "css"); // "red"
|
||||
Bun.color("rgb(255, 0, 0)", "css"); // "red"
|
||||
Bun.color("rgba(255, 0, 0, 1)", "css"); // "red"
|
||||
Bun.color("hsl(0, 100%, 50%)", "css"); // "red"
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "css"); // "red"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "css"); // "red"
|
||||
Bun.color({ r: 255, g: 0, b: 0, a: 1 }, "css"); // "red"
|
||||
Bun.color([255, 0, 0], "css"); // "red"
|
||||
Bun.color([255, 0, 0, 255], "css"); // "red"
|
||||
```
|
||||
|
||||
If the input is unknown or fails to parse, `Bun.color` returns `null`.
|
||||
|
||||
### Format colors as ANSI (for terminals)
|
||||
|
||||
The `"ansi"` format outputs ANSI escape codes for use in terminals to make text colorful.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color(0xff0000, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("#f00", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("#ff0000", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("rgb(255, 0, 0)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("rgba(255, 0, 0, 1)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("hsl(0, 100%, 50%)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color({ r: 255, g: 0, b: 0, a: 1 }, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color([255, 0, 0], "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color([255, 0, 0, 255], "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
```
|
||||
|
||||
This gets the color depth of stdout and automatically chooses one of `"ansi-16m"`, `"ansi-256"`, `"ansi-16"` based on the environment variables. If stdout doesn't support any form of ANSI color, it returns an empty string. As with the rest of Bun's color API, if the input is unknown or fails to parse, it returns `null`.
|
||||
|
||||
#### 24-bit ANSI colors (`ansi-16m`)
|
||||
|
||||
The `"ansi-16m"` format outputs 24-bit ANSI colors for use in terminals to make text colorful. 24-bit color means you can display 16 million colors on supported terminals, and requires a modern terminal that supports it.
|
||||
|
||||
This converts the input color to RGBA, and then outputs that as an ANSI color.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color(0xff0000, "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color("#f00", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color("#ff0000", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
```
|
||||
|
||||
#### 256 ANSI colors (`ansi-256`)
|
||||
|
||||
The `"ansi-256"` format approximates the input color to the nearest of the 256 ANSI colors supported by some terminals.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color(0xff0000, "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color("#f00", "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color("#ff0000", "ansi-256"); // "\u001b[38;5;196m"
|
||||
```
|
||||
|
||||
To convert from RGBA to one of the 256 ANSI colors, we ported the algorithm that [`tmux` uses](https://github.com/tmux/tmux/blob/dae2868d1227b95fd076fb4a5efa6256c7245943/colour.c#L44-L55).
|
||||
|
||||
#### 16 ANSI colors (`ansi-16`)
|
||||
|
||||
The `"ansi-16"` format approximates the input color to the nearest of the 16 ANSI colors supported by most terminals.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color(0xff0000, "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color("#f00", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color("#ff0000", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
```
|
||||
|
||||
This works by first converting the input to a 24-bit RGB color space, then to `ansi-256`, and then we convert that to the nearest 16 ANSI color.
|
||||
|
||||
### Format colors as numbers
|
||||
|
||||
The `"number"` format outputs a 24-bit number for use in databases, configuration, or any other use case where a compact representation of the color is desired.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "number"); // 16711680
|
||||
Bun.color(0xff0000, "number"); // 16711680
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "number"); // 16711680
|
||||
Bun.color([255, 0, 0], "number"); // 16711680
|
||||
Bun.color("rgb(255, 0, 0)", "number"); // 16711680
|
||||
Bun.color("rgba(255, 0, 0, 1)", "number"); // 16711680
|
||||
Bun.color("hsl(0, 100%, 50%)", "number"); // 16711680
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "number"); // 16711680
|
||||
```
|
||||
|
||||
### Get the red, green, blue, and alpha channels
|
||||
|
||||
You can use the `"{rgba}"`, `"{rgb}"`, `"[rgba]"` and `"[rgb]"` formats to get the red, green, blue, and alpha channels as objects or arrays.
|
||||
|
||||
#### `{rgba}` object
|
||||
|
||||
The `"{rgba}"` format outputs an object with the red, green, blue, and alpha channels.
|
||||
|
||||
```ts
|
||||
type RGBAObject = {
|
||||
// 0 - 255
|
||||
r: number;
|
||||
// 0 - 255
|
||||
g: number;
|
||||
// 0 - 255
|
||||
b: number;
|
||||
// 0 - 1
|
||||
a: number;
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "{rgba}"); // { r: 128, g: 128, b: 128, a: 1 }
|
||||
Bun.color("red", "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color(0xff0000, "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color([255, 0, 0], "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
```
|
||||
|
||||
To behave similarly to CSS, the `a` channel is a decimal number between `0` and `1`.
|
||||
|
||||
The `"{rgb}"` format is similar, but it doesn't include the alpha channel.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "{rgb}"); // { r: 128, g: 128, b: 128 }
|
||||
Bun.color("red", "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color(0xff0000, "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color([255, 0, 0], "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
```
|
||||
|
||||
#### `[rgba]` array
|
||||
|
||||
The `"[rgba]"` format outputs an array with the red, green, blue, and alpha channels.
|
||||
|
||||
```ts
|
||||
// All values are 0 - 255
|
||||
type RGBAArray = [number, number, number, number];
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "[rgba]"); // [128, 128, 128, 255]
|
||||
Bun.color("red", "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color(0xff0000, "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color([255, 0, 0], "[rgba]"); // [255, 0, 0, 255]
|
||||
```
|
||||
|
||||
Unlike the `"{rgba}"` format, the alpha channel is an integer between `0` and `255`. This is useful for typed arrays where each channel must be the same underlying type.
|
||||
|
||||
The `"[rgb]"` format is similar, but it doesn't include the alpha channel.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "[rgb]"); // [128, 128, 128]
|
||||
Bun.color("red", "[rgb]"); // [255, 0, 0]
|
||||
Bun.color(0xff0000, "[rgb]"); // [255, 0, 0]
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "[rgb]"); // [255, 0, 0]
|
||||
Bun.color([255, 0, 0], "[rgb]"); // [255, 0, 0]
|
||||
```
|
||||
|
||||
### Format colors as hex strings
|
||||
|
||||
The `"hex"` format outputs a lowercase hex string for use in CSS or other contexts.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "hex"); // "#808080"
|
||||
Bun.color("red", "hex"); // "#ff0000"
|
||||
Bun.color(0xff0000, "hex"); // "#ff0000"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "hex"); // "#ff0000"
|
||||
Bun.color([255, 0, 0], "hex"); // "#ff0000"
|
||||
```
|
||||
|
||||
The `"HEX"` format is similar, but it outputs a hex string with uppercase letters instead of lowercase letters.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "HEX"); // "#808080"
|
||||
Bun.color("red", "HEX"); // "#FF0000"
|
||||
Bun.color(0xff0000, "HEX"); // "#FF0000"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "HEX"); // "#FF0000"
|
||||
Bun.color([255, 0, 0], "HEX"); // "#FF0000"
|
||||
```
|
||||
|
||||
### Bundle-time client-side color formatting
|
||||
|
||||
Like many of Bun's APIs, you can use macros to invoke `Bun.color` at bundle-time for use in client-side JavaScript builds:
|
||||
|
||||
```ts#client-side.ts
|
||||
import { color } from "bun" with { type: "macro" };
|
||||
|
||||
console.log(color("#f00", "css"));
|
||||
```
|
||||
|
||||
Then, build the client-side code:
|
||||
|
||||
```sh
|
||||
bun build ./client-side.ts
|
||||
```
|
||||
|
||||
This will output the following to `client-side.js`:
|
||||
|
||||
```js
|
||||
// client-side.ts
|
||||
console.log("red");
|
||||
```
|
||||
57
node_modules/bun-types/docs/api/console.md
generated
vendored
Normal file
57
node_modules/bun-types/docs/api/console.md
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{% callout %}
|
||||
**Note** — Bun provides a browser- and Node.js-compatible [console](https://developer.mozilla.org/en-US/docs/Web/API/console) global. This page only documents Bun-native APIs.
|
||||
{% /callout %}
|
||||
|
||||
## Object inspection depth
|
||||
|
||||
Bun allows you to configure how deeply nested objects are displayed in `console.log()` output:
|
||||
|
||||
- **CLI flag**: Use `--console-depth <number>` to set the depth for a single run
|
||||
- **Configuration**: Set `console.depth` in your `bunfig.toml` for persistent configuration
|
||||
- **Default**: Objects are inspected to a depth of `2` levels
|
||||
|
||||
```js
|
||||
const nested = { a: { b: { c: { d: "deep" } } } };
|
||||
console.log(nested);
|
||||
// Default (depth 2): { a: { b: [Object] } }
|
||||
// With depth 4: { a: { b: { c: { d: 'deep' } } } }
|
||||
```
|
||||
|
||||
The CLI flag takes precedence over the configuration file setting.
|
||||
|
||||
## Reading from stdin
|
||||
|
||||
In Bun, the `console` object can be used as an `AsyncIterable` to sequentially read lines from `process.stdin`.
|
||||
|
||||
```ts
|
||||
for await (const line of console) {
|
||||
console.log(line);
|
||||
}
|
||||
```
|
||||
|
||||
This is useful for implementing interactive programs, like the following addition calculator.
|
||||
|
||||
```ts#adder.ts
|
||||
console.log(`Let's add some numbers!`);
|
||||
console.write(`Count: 0\n> `);
|
||||
|
||||
let count = 0;
|
||||
for await (const line of console) {
|
||||
count += Number(line);
|
||||
console.write(`Count: ${count}\n> `);
|
||||
}
|
||||
```
|
||||
|
||||
To run the file:
|
||||
|
||||
```bash
|
||||
$ bun adder.ts
|
||||
Let's add some numbers!
|
||||
Count: 0
|
||||
> 5
|
||||
Count: 5
|
||||
> 5
|
||||
Count: 10
|
||||
> 5
|
||||
Count: 15
|
||||
```
|
||||
449
node_modules/bun-types/docs/api/cookie.md
generated
vendored
Normal file
449
node_modules/bun-types/docs/api/cookie.md
generated
vendored
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
Bun provides native APIs for working with HTTP cookies through `Bun.Cookie` and `Bun.CookieMap`. These APIs offer fast, easy-to-use methods for parsing, generating, and manipulating cookies in HTTP requests and responses.
|
||||
|
||||
## CookieMap class
|
||||
|
||||
`Bun.CookieMap` provides a Map-like interface for working with collections of cookies. It implements the `Iterable` interface, allowing you to use it with `for...of` loops and other iteration methods.
|
||||
|
||||
```ts
|
||||
// Empty cookie map
|
||||
const cookies = new Bun.CookieMap();
|
||||
|
||||
// From a cookie string
|
||||
const cookies1 = new Bun.CookieMap("name=value; foo=bar");
|
||||
|
||||
// From an object
|
||||
const cookies2 = new Bun.CookieMap({
|
||||
session: "abc123",
|
||||
theme: "dark",
|
||||
});
|
||||
|
||||
// From an array of name/value pairs
|
||||
const cookies3 = new Bun.CookieMap([
|
||||
["session", "abc123"],
|
||||
["theme", "dark"],
|
||||
]);
|
||||
```
|
||||
|
||||
### In HTTP servers
|
||||
|
||||
In Bun's HTTP server, the `cookies` property on the request object (in `routes`) is an instance of `CookieMap`:
|
||||
|
||||
```ts
|
||||
const server = Bun.serve({
|
||||
routes: {
|
||||
"/": req => {
|
||||
// Access request cookies
|
||||
const cookies = req.cookies;
|
||||
|
||||
// Get a specific cookie
|
||||
const sessionCookie = cookies.get("session");
|
||||
if (sessionCookie != null) {
|
||||
console.log(sessionCookie);
|
||||
}
|
||||
|
||||
// Check if a cookie exists
|
||||
if (cookies.has("theme")) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// Set a cookie, it will be automatically applied to the response
|
||||
cookies.set("visited", "true");
|
||||
|
||||
return new Response("Hello");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Server listening at: " + server.url);
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
#### `get(name: string): string | null`
|
||||
|
||||
Retrieves a cookie by name. Returns `null` if the cookie doesn't exist.
|
||||
|
||||
```ts
|
||||
// Get by name
|
||||
const cookie = cookies.get("session");
|
||||
|
||||
if (cookie != null) {
|
||||
console.log(cookie);
|
||||
}
|
||||
```
|
||||
|
||||
#### `has(name: string): boolean`
|
||||
|
||||
Checks if a cookie with the given name exists.
|
||||
|
||||
```ts
|
||||
// Check if cookie exists
|
||||
if (cookies.has("session")) {
|
||||
// Cookie exists
|
||||
}
|
||||
```
|
||||
|
||||
#### `set(name: string, value: string): void`
|
||||
|
||||
#### `set(options: CookieInit): void`
|
||||
|
||||
#### `set(cookie: Cookie): void`
|
||||
|
||||
Adds or updates a cookie in the map. Cookies default to `{ path: "/", sameSite: "lax" }`.
|
||||
|
||||
```ts
|
||||
// Set by name and value
|
||||
cookies.set("session", "abc123");
|
||||
|
||||
// Set using options object
|
||||
cookies.set({
|
||||
name: "theme",
|
||||
value: "dark",
|
||||
maxAge: 3600,
|
||||
secure: true,
|
||||
});
|
||||
|
||||
// Set using Cookie instance
|
||||
const cookie = new Bun.Cookie("visited", "true");
|
||||
cookies.set(cookie);
|
||||
```
|
||||
|
||||
#### `delete(name: string): void`
|
||||
|
||||
#### `delete(options: CookieStoreDeleteOptions): void`
|
||||
|
||||
Removes a cookie from the map. When applied to a Response, this adds a cookie with an empty string value and an expiry date in the past. A cookie will only delete successfully on the browser if the domain and path is the same as it was when the cookie was created.
|
||||
|
||||
```ts
|
||||
// Delete by name using default domain and path.
|
||||
cookies.delete("session");
|
||||
|
||||
// Delete with domain/path options.
|
||||
cookies.delete({
|
||||
name: "session",
|
||||
domain: "example.com",
|
||||
path: "/admin",
|
||||
});
|
||||
```
|
||||
|
||||
#### `toJSON(): Record<string, string>`
|
||||
|
||||
Converts the cookie map to a serializable format.
|
||||
|
||||
```ts
|
||||
const json = cookies.toJSON();
|
||||
```
|
||||
|
||||
#### `toSetCookieHeaders(): string[]`
|
||||
|
||||
Returns an array of values for Set-Cookie headers that can be used to apply all cookie changes.
|
||||
|
||||
When using `Bun.serve()`, you don't need to call this method explicitly. Any changes made to the `req.cookies` map are automatically applied to the response headers. This method is primarily useful when working with other HTTP server implementations.
|
||||
|
||||
```js
|
||||
import { createServer } from "node:http";
|
||||
import { CookieMap } from "bun";
|
||||
|
||||
const server = createServer((req, res) => {
|
||||
const cookieHeader = req.headers.cookie || "";
|
||||
const cookies = new CookieMap(cookieHeader);
|
||||
|
||||
cookies.set("view-count", Number(cookies.get("view-count") || "0") + 1);
|
||||
cookies.delete("session");
|
||||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/plain",
|
||||
"Set-Cookie": cookies.toSetCookieHeaders(),
|
||||
});
|
||||
res.end(`Found ${cookies.size} cookies`);
|
||||
});
|
||||
|
||||
server.listen(3000, () => {
|
||||
console.log("Server running at http://localhost:3000/");
|
||||
});
|
||||
```
|
||||
|
||||
### Iteration
|
||||
|
||||
`CookieMap` provides several methods for iteration:
|
||||
|
||||
```ts
|
||||
// Iterate over [name, cookie] entries
|
||||
for (const [name, value] of cookies) {
|
||||
console.log(`${name}: ${value}`);
|
||||
}
|
||||
|
||||
// Using entries()
|
||||
for (const [name, value] of cookies.entries()) {
|
||||
console.log(`${name}: ${value}`);
|
||||
}
|
||||
|
||||
// Using keys()
|
||||
for (const name of cookies.keys()) {
|
||||
console.log(name);
|
||||
}
|
||||
|
||||
// Using values()
|
||||
for (const value of cookies.values()) {
|
||||
console.log(value);
|
||||
}
|
||||
|
||||
// Using forEach
|
||||
cookies.forEach((value, name) => {
|
||||
console.log(`${name}: ${value}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
#### `size: number`
|
||||
|
||||
Returns the number of cookies in the map.
|
||||
|
||||
```ts
|
||||
console.log(cookies.size); // Number of cookies
|
||||
```
|
||||
|
||||
## Cookie class
|
||||
|
||||
`Bun.Cookie` represents an HTTP cookie with its name, value, and attributes.
|
||||
|
||||
```ts
|
||||
import { Cookie } from "bun";
|
||||
|
||||
// Create a basic cookie
|
||||
const cookie = new Bun.Cookie("name", "value");
|
||||
|
||||
// Create a cookie with options
|
||||
const secureSessionCookie = new Bun.Cookie("session", "abc123", {
|
||||
domain: "example.com",
|
||||
path: "/admin",
|
||||
expires: new Date(Date.now() + 86400000), // 1 day
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
|
||||
// Parse from a cookie string
|
||||
const parsedCookie = new Bun.Cookie("name=value; Path=/; HttpOnly");
|
||||
|
||||
// Create from an options object
|
||||
const objCookie = new Bun.Cookie({
|
||||
name: "theme",
|
||||
value: "dark",
|
||||
maxAge: 3600,
|
||||
secure: true,
|
||||
});
|
||||
```
|
||||
|
||||
### Constructors
|
||||
|
||||
```ts
|
||||
// Basic constructor with name/value
|
||||
new Bun.Cookie(name: string, value: string);
|
||||
|
||||
// Constructor with name, value, and options
|
||||
new Bun.Cookie(name: string, value: string, options: CookieInit);
|
||||
|
||||
// Constructor from cookie string
|
||||
new Bun.Cookie(cookieString: string);
|
||||
|
||||
// Constructor from cookie object
|
||||
new Bun.Cookie(options: CookieInit);
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
```ts
|
||||
cookie.name; // string - Cookie name
|
||||
cookie.value; // string - Cookie value
|
||||
cookie.domain; // string | null - Domain scope (null if not specified)
|
||||
cookie.path; // string - URL path scope (defaults to "/")
|
||||
cookie.expires; // number | undefined - Expiration timestamp (ms since epoch)
|
||||
cookie.secure; // boolean - Require HTTPS
|
||||
cookie.sameSite; // "strict" | "lax" | "none" - SameSite setting
|
||||
cookie.partitioned; // boolean - Whether the cookie is partitioned (CHIPS)
|
||||
cookie.maxAge; // number | undefined - Max age in seconds
|
||||
cookie.httpOnly; // boolean - Accessible only via HTTP (not JavaScript)
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
#### `isExpired(): boolean`
|
||||
|
||||
Checks if the cookie has expired.
|
||||
|
||||
```ts
|
||||
// Expired cookie (Date in the past)
|
||||
const expiredCookie = new Bun.Cookie("name", "value", {
|
||||
expires: new Date(Date.now() - 1000),
|
||||
});
|
||||
console.log(expiredCookie.isExpired()); // true
|
||||
|
||||
// Valid cookie (Using maxAge instead of expires)
|
||||
const validCookie = new Bun.Cookie("name", "value", {
|
||||
maxAge: 3600, // 1 hour in seconds
|
||||
});
|
||||
console.log(validCookie.isExpired()); // false
|
||||
|
||||
// Session cookie (no expiration)
|
||||
const sessionCookie = new Bun.Cookie("name", "value");
|
||||
console.log(sessionCookie.isExpired()); // false
|
||||
```
|
||||
|
||||
#### `serialize(): string`
|
||||
|
||||
#### `toString(): string`
|
||||
|
||||
Returns a string representation of the cookie suitable for a `Set-Cookie` header.
|
||||
|
||||
```ts
|
||||
const cookie = new Bun.Cookie("session", "abc123", {
|
||||
domain: "example.com",
|
||||
path: "/admin",
|
||||
expires: new Date(Date.now() + 86400000),
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
|
||||
console.log(cookie.serialize());
|
||||
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Sun, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=strict"
|
||||
console.log(cookie.toString());
|
||||
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Sun, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=strict"
|
||||
```
|
||||
|
||||
#### `toJSON(): CookieInit`
|
||||
|
||||
Converts the cookie to a plain object suitable for JSON serialization.
|
||||
|
||||
```ts
|
||||
const cookie = new Bun.Cookie("session", "abc123", {
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
const json = cookie.toJSON();
|
||||
// => {
|
||||
// name: "session",
|
||||
// value: "abc123",
|
||||
// path: "/",
|
||||
// secure: true,
|
||||
// httpOnly: true,
|
||||
// sameSite: "lax",
|
||||
// partitioned: false
|
||||
// }
|
||||
|
||||
// Works with JSON.stringify
|
||||
const jsonString = JSON.stringify(cookie);
|
||||
```
|
||||
|
||||
### Static methods
|
||||
|
||||
#### `Cookie.parse(cookieString: string): Cookie`
|
||||
|
||||
Parses a cookie string into a `Cookie` instance.
|
||||
|
||||
```ts
|
||||
const cookie = Bun.Cookie.parse("name=value; Path=/; Secure; SameSite=Lax");
|
||||
|
||||
console.log(cookie.name); // "name"
|
||||
console.log(cookie.value); // "value"
|
||||
console.log(cookie.path); // "/"
|
||||
console.log(cookie.secure); // true
|
||||
console.log(cookie.sameSite); // "lax"
|
||||
```
|
||||
|
||||
#### `Cookie.from(name: string, value: string, options?: CookieInit): Cookie`
|
||||
|
||||
Factory method to create a cookie.
|
||||
|
||||
```ts
|
||||
const cookie = Bun.Cookie.from("session", "abc123", {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
maxAge: 3600,
|
||||
});
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
```ts
|
||||
interface CookieInit {
|
||||
name?: string;
|
||||
value?: string;
|
||||
domain?: string;
|
||||
/** Defaults to '/'. To allow the browser to set the path, use an empty string. */
|
||||
path?: string;
|
||||
expires?: number | Date | string;
|
||||
secure?: boolean;
|
||||
/** Defaults to `lax`. */
|
||||
sameSite?: CookieSameSite;
|
||||
httpOnly?: boolean;
|
||||
partitioned?: boolean;
|
||||
maxAge?: number;
|
||||
}
|
||||
|
||||
interface CookieStoreDeleteOptions {
|
||||
name: string;
|
||||
domain?: string | null;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
interface CookieStoreGetOptions {
|
||||
name?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
type CookieSameSite = "strict" | "lax" | "none";
|
||||
|
||||
class Cookie {
|
||||
constructor(name: string, value: string, options?: CookieInit);
|
||||
constructor(cookieString: string);
|
||||
constructor(cookieObject?: CookieInit);
|
||||
|
||||
readonly name: string;
|
||||
value: string;
|
||||
domain?: string;
|
||||
path: string;
|
||||
expires?: Date;
|
||||
secure: boolean;
|
||||
sameSite: CookieSameSite;
|
||||
partitioned: boolean;
|
||||
maxAge?: number;
|
||||
httpOnly: boolean;
|
||||
|
||||
isExpired(): boolean;
|
||||
|
||||
serialize(): string;
|
||||
toString(): string;
|
||||
toJSON(): CookieInit;
|
||||
|
||||
static parse(cookieString: string): Cookie;
|
||||
static from(name: string, value: string, options?: CookieInit): Cookie;
|
||||
}
|
||||
|
||||
class CookieMap implements Iterable<[string, string]> {
|
||||
constructor(init?: string[][] | Record<string, string> | string);
|
||||
|
||||
get(name: string): string | null;
|
||||
|
||||
toSetCookieHeaders(): string[];
|
||||
|
||||
has(name: string): boolean;
|
||||
set(name: string, value: string, options?: CookieInit): void;
|
||||
set(options: CookieInit): void;
|
||||
delete(name: string): void;
|
||||
delete(options: CookieStoreDeleteOptions): void;
|
||||
delete(name: string, options: Omit<CookieStoreDeleteOptions, "name">): void;
|
||||
toJSON(): Record<string, string>;
|
||||
|
||||
readonly size: number;
|
||||
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
keys(): IterableIterator<string>;
|
||||
values(): IterableIterator<string>;
|
||||
forEach(callback: (value: string, key: string, map: CookieMap) => void): void;
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
}
|
||||
```
|
||||
110
node_modules/bun-types/docs/api/dns.md
generated
vendored
Normal file
110
node_modules/bun-types/docs/api/dns.md
generated
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
Bun implements the `node:dns` module.
|
||||
|
||||
```ts
|
||||
import * as dns from "node:dns";
|
||||
|
||||
const addrs = await dns.promises.resolve4("bun.com", { ttl: true });
|
||||
console.log(addrs);
|
||||
// => [{ address: "172.67.161.226", family: 4, ttl: 0 }, ...]
|
||||
```
|
||||
|
||||
## DNS caching in Bun
|
||||
|
||||
In Bun v1.1.9, we added support for DNS caching. This cache makes repeated connections to the same hosts faster.
|
||||
|
||||
At the time of writing, we cache up to 255 entries for a maximum of 30 seconds (each). If any connections to a host fail, we remove the entry from the cache. When multiple connections are made to the same host simultaneously, DNS lookups are deduplicated to avoid making multiple requests for the same host.
|
||||
|
||||
This cache is automatically used by:
|
||||
|
||||
- `bun install`
|
||||
- `fetch()`
|
||||
- `node:http` (client)
|
||||
- `Bun.connect`
|
||||
- `node:net`
|
||||
- `node:tls`
|
||||
|
||||
### When should I prefetch a DNS entry?
|
||||
|
||||
Web browsers expose [`<link rel="dns-prefetch">`](https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch) to allow developers to prefetch DNS entries. This is useful when you know you'll need to connect to a host in the near future and want to avoid the initial DNS lookup.
|
||||
|
||||
In Bun, you can use the `dns.prefetch` API to achieve the same effect.
|
||||
|
||||
```ts
|
||||
import { dns } from "bun";
|
||||
|
||||
dns.prefetch("my.database-host.com", 5432);
|
||||
```
|
||||
|
||||
An example where you might want to use this is a database driver. When your application first starts up, you can prefetch the DNS entry for the database host so that by the time it finishes loading everything, the DNS query to resolve the database host may already be completed.
|
||||
|
||||
### `dns.prefetch`
|
||||
|
||||
{% callout %}
|
||||
**🚧** — This API is experimental and may change in the future.
|
||||
{% /callout %}
|
||||
|
||||
To prefetch a DNS entry, you can use the `dns.prefetch` API. This API is useful when you know you'll need to connect to a host soon and want to avoid the initial DNS lookup.
|
||||
|
||||
```ts
|
||||
dns.prefetch(hostname: string, port: number): void;
|
||||
```
|
||||
|
||||
Here's an example:
|
||||
|
||||
```ts
|
||||
import { dns } from "bun";
|
||||
|
||||
dns.prefetch("bun.com", 443);
|
||||
//
|
||||
// ... sometime later ...
|
||||
await fetch("https://bun.com");
|
||||
```
|
||||
|
||||
### `dns.getCacheStats()`
|
||||
|
||||
{% callout %}
|
||||
**🚧** — This API is experimental and may change in the future.
|
||||
{% /callout %}
|
||||
|
||||
To get the current cache stats, you can use the `dns.getCacheStats` API.
|
||||
|
||||
This API returns an object with the following properties:
|
||||
|
||||
```ts
|
||||
{
|
||||
// Cache hits
|
||||
cacheHitsCompleted: number;
|
||||
cacheHitsInflight: number;
|
||||
cacheMisses: number;
|
||||
// Number of items in the DNS cache
|
||||
size: number;
|
||||
|
||||
// Number of times a connection failed
|
||||
errors: number;
|
||||
|
||||
// Number of times a connection was requested at all (including cache hits and misses)
|
||||
totalCount: number;
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { dns } from "bun";
|
||||
|
||||
const stats = dns.getCacheStats();
|
||||
console.log(stats);
|
||||
// => { cacheHitsCompleted: 0, cacheHitsInflight: 0, cacheMisses: 0, size: 0, errors: 0, totalCount: 0 }
|
||||
```
|
||||
|
||||
### Configuring DNS cache TTL
|
||||
|
||||
Bun defaults to 30 seconds for the TTL of DNS cache entries. To change this, you can set the environment variable `$BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS`. For example, to set the TTL to 5 seconds:
|
||||
|
||||
```sh
|
||||
BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts
|
||||
```
|
||||
|
||||
#### Why is 30 seconds the default?
|
||||
|
||||
Unfortunately, the system API underneath (`getaddrinfo`) does not provide a way to get the TTL of a DNS entry. This means we have to pick a number arbitrarily. We chose 30 seconds because it's long enough to see the benefits of caching, and short enough to be unlikely to cause issues if a DNS entry changes. [Amazon Web Services recommends 5 seconds](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/jvm-ttl-dns.html) for the Java Virtual Machine, however the JVM defaults to cache indefinitely.
|
||||
463
node_modules/bun-types/docs/api/fetch.md
generated
vendored
Normal file
463
node_modules/bun-types/docs/api/fetch.md
generated
vendored
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
Bun implements the WHATWG `fetch` standard, with some extensions to meet the needs of server-side JavaScript.
|
||||
|
||||
Bun also implements `node:http`, but `fetch` is generally recommended instead.
|
||||
|
||||
## Sending an HTTP request
|
||||
|
||||
To send an HTTP request, use `fetch`
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
console.log(response.status); // => 200
|
||||
|
||||
const text = await response.text(); // or response.json(), response.formData(), etc.
|
||||
```
|
||||
|
||||
`fetch` also works with HTTPS URLs.
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://example.com");
|
||||
```
|
||||
|
||||
You can also pass `fetch` a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object.
|
||||
|
||||
```ts
|
||||
const request = new Request("http://example.com", {
|
||||
method: "POST",
|
||||
body: "Hello, world!",
|
||||
});
|
||||
|
||||
const response = await fetch(request);
|
||||
```
|
||||
|
||||
### Sending a POST request
|
||||
|
||||
To send a POST request, pass an object with the `method` property set to `"POST"`.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
method: "POST",
|
||||
body: "Hello, world!",
|
||||
});
|
||||
```
|
||||
|
||||
`body` can be a string, a `FormData` object, an `ArrayBuffer`, a `Blob`, and more. See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#setting_a_body) for more information.
|
||||
|
||||
### Proxying requests
|
||||
|
||||
To proxy a request, pass an object with the `proxy` property set to a URL.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
proxy: "http://proxy.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Custom headers
|
||||
|
||||
To set custom headers, pass an object with the `headers` property set to an object.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
headers: {
|
||||
"X-Custom-Header": "value",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also set headers using the [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object.
|
||||
|
||||
```ts
|
||||
const headers = new Headers();
|
||||
headers.append("X-Custom-Header", "value");
|
||||
|
||||
const response = await fetch("http://example.com", {
|
||||
headers,
|
||||
});
|
||||
```
|
||||
|
||||
### Response bodies
|
||||
|
||||
To read the response body, use one of the following methods:
|
||||
|
||||
- `response.text(): Promise<string>`: Returns a promise that resolves with the response body as a string.
|
||||
- `response.json(): Promise<any>`: Returns a promise that resolves with the response body as a JSON object.
|
||||
- `response.formData(): Promise<FormData>`: Returns a promise that resolves with the response body as a `FormData` object.
|
||||
- `response.bytes(): Promise<Uint8Array>`: Returns a promise that resolves with the response body as a `Uint8Array`.
|
||||
- `response.arrayBuffer(): Promise<ArrayBuffer>`: Returns a promise that resolves with the response body as an `ArrayBuffer`.
|
||||
- `response.blob(): Promise<Blob>`: Returns a promise that resolves with the response body as a `Blob`.
|
||||
|
||||
#### Streaming response bodies
|
||||
|
||||
You can use async iterators to stream the response body.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
for await (const chunk of response.body) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
You can also more directly access the `ReadableStream` object.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
const stream = response.body;
|
||||
|
||||
const reader = stream.getReader();
|
||||
const { value, done } = await reader.read();
|
||||
```
|
||||
|
||||
### Streaming request bodies
|
||||
|
||||
You can also stream data in request bodies using a `ReadableStream`:
|
||||
|
||||
```ts
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("Hello");
|
||||
controller.enqueue(" ");
|
||||
controller.enqueue("World");
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
|
||||
const response = await fetch("http://example.com", {
|
||||
method: "POST",
|
||||
body: stream,
|
||||
});
|
||||
```
|
||||
|
||||
When using streams with HTTP(S):
|
||||
|
||||
- The data is streamed directly to the network without buffering the entire body in memory
|
||||
- If the connection is lost, the stream will be canceled
|
||||
- The `Content-Length` header is not automatically set unless the stream has a known size
|
||||
|
||||
When using streams with S3:
|
||||
|
||||
- For PUT/POST requests, Bun automatically uses multipart upload
|
||||
- The stream is consumed in chunks and uploaded in parallel
|
||||
- Progress can be monitored through the S3 options
|
||||
|
||||
### Fetching a URL with a timeout
|
||||
|
||||
To fetch a URL with a timeout, use `AbortSignal.timeout`:
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
signal: AbortSignal.timeout(1000),
|
||||
});
|
||||
```
|
||||
|
||||
#### Canceling a request
|
||||
|
||||
To cancel a request, use an `AbortController`:
|
||||
|
||||
```ts
|
||||
const controller = new AbortController();
|
||||
|
||||
const response = await fetch("http://example.com", {
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
controller.abort();
|
||||
```
|
||||
|
||||
### Unix domain sockets
|
||||
|
||||
To fetch a URL using a Unix domain socket, use the `unix: string` option:
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://hostname/a/path", {
|
||||
unix: "/var/run/path/to/unix.sock",
|
||||
method: "POST",
|
||||
body: JSON.stringify({ message: "Hello from Bun!" }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
To use a client certificate, use the `tls` option:
|
||||
|
||||
```ts
|
||||
await fetch("https://example.com", {
|
||||
tls: {
|
||||
key: Bun.file("/path/to/key.pem"),
|
||||
cert: Bun.file("/path/to/cert.pem"),
|
||||
// ca: [Bun.file("/path/to/ca.pem")],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Custom TLS Validation
|
||||
|
||||
To customize the TLS validation, use the `checkServerIdentity` option in `tls`
|
||||
|
||||
```ts
|
||||
await fetch("https://example.com", {
|
||||
tls: {
|
||||
checkServerIdentity: (hostname, peerCertificate) => {
|
||||
// Return an Error if the certificate is invalid
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This is similar to how it works in Node's `net` module.
|
||||
|
||||
#### Disable TLS validation
|
||||
|
||||
To disable TLS validation, set `rejectUnauthorized` to `false`:
|
||||
|
||||
```ts
|
||||
await fetch("https://example.com", {
|
||||
tls: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This is especially useful to avoid SSL errors when using self-signed certificates, but this disables TLS validation and should be used with caution.
|
||||
|
||||
### Request options
|
||||
|
||||
In addition to the standard fetch options, Bun provides several extensions:
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
// Control automatic response decompression (default: true)
|
||||
decompress: true,
|
||||
|
||||
// Disable connection reuse for this request
|
||||
keepalive: false,
|
||||
|
||||
// Debug logging level
|
||||
verbose: true, // or "curl" for more detailed output
|
||||
});
|
||||
```
|
||||
|
||||
### Protocol support
|
||||
|
||||
Beyond HTTP(S), Bun's fetch supports several additional protocols:
|
||||
|
||||
#### S3 URLs - `s3://`
|
||||
|
||||
Bun supports fetching from S3 buckets directly.
|
||||
|
||||
```ts
|
||||
// Using environment variables for credentials
|
||||
const response = await fetch("s3://my-bucket/path/to/object");
|
||||
|
||||
// Or passing credentials explicitly
|
||||
const response = await fetch("s3://my-bucket/path/to/object", {
|
||||
s3: {
|
||||
accessKeyId: "YOUR_ACCESS_KEY",
|
||||
secretAccessKey: "YOUR_SECRET_KEY",
|
||||
region: "us-east-1",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note: Only PUT and POST methods support request bodies when using S3. For uploads, Bun automatically uses multipart upload for streaming bodies.
|
||||
|
||||
You can read more about Bun's S3 support in the [S3](https://bun.com/docs/api/s3) documentation.
|
||||
|
||||
#### File URLs - `file://`
|
||||
|
||||
You can fetch local files using the `file:` protocol:
|
||||
|
||||
```ts
|
||||
const response = await fetch("file:///path/to/file.txt");
|
||||
const text = await response.text();
|
||||
```
|
||||
|
||||
On Windows, paths are automatically normalized:
|
||||
|
||||
```ts
|
||||
// Both work on Windows
|
||||
const response = await fetch("file:///C:/path/to/file.txt");
|
||||
const response2 = await fetch("file:///c:/path\\to/file.txt");
|
||||
```
|
||||
|
||||
#### Data URLs - `data:`
|
||||
|
||||
Bun supports the `data:` URL scheme:
|
||||
|
||||
```ts
|
||||
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
|
||||
const text = await response.text(); // "Hello, World!"
|
||||
```
|
||||
|
||||
#### Blob URLs - `blob:`
|
||||
|
||||
You can fetch blobs using URLs created by `URL.createObjectURL()`:
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const response = await fetch(url);
|
||||
```
|
||||
|
||||
### Error handling
|
||||
|
||||
Bun's fetch implementation includes several specific error cases:
|
||||
|
||||
- Using a request body with GET/HEAD methods will throw an error (which is expected for the fetch API)
|
||||
- Attempting to use both `proxy` and `unix` options together will throw an error
|
||||
- TLS certificate validation failures when `rejectUnauthorized` is true (or undefined)
|
||||
- S3 operations may throw specific errors related to authentication or permissions
|
||||
|
||||
### Content-Type handling
|
||||
|
||||
Bun automatically sets the `Content-Type` header for request bodies when not explicitly provided:
|
||||
|
||||
- For `Blob` objects, uses the blob's `type`
|
||||
- For `FormData`, sets appropriate multipart boundary
|
||||
- For JSON objects, sets `application/json`
|
||||
|
||||
## Debugging
|
||||
|
||||
To help with debugging, you can pass `verbose: true` to `fetch`:
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
verbose: true,
|
||||
});
|
||||
```
|
||||
|
||||
This will print the request and response headers to your terminal:
|
||||
|
||||
```sh
|
||||
[fetch] > HTTP/1.1 GET http://example.com/
|
||||
[fetch] > Connection: keep-alive
|
||||
[fetch] > User-Agent: Bun/1.2.19
|
||||
[fetch] > Accept: */*
|
||||
[fetch] > Host: example.com
|
||||
[fetch] > Accept-Encoding: gzip, deflate, br
|
||||
|
||||
[fetch] < 200 OK
|
||||
[fetch] < Content-Encoding: gzip
|
||||
[fetch] < Age: 201555
|
||||
[fetch] < Cache-Control: max-age=604800
|
||||
[fetch] < Content-Type: text/html; charset=UTF-8
|
||||
[fetch] < Date: Sun, 21 Jul 2024 02:41:14 GMT
|
||||
[fetch] < Etag: "3147526947+gzip"
|
||||
[fetch] < Expires: Sun, 28 Jul 2024 02:41:14 GMT
|
||||
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
|
||||
[fetch] < Server: ECAcc (sac/254F)
|
||||
[fetch] < Vary: Accept-Encoding
|
||||
[fetch] < X-Cache: HIT
|
||||
[fetch] < Content-Length: 648
|
||||
```
|
||||
|
||||
Note: `verbose: boolean` is not part of the Web standard `fetch` API and is specific to Bun.
|
||||
|
||||
## Performance
|
||||
|
||||
Before an HTTP request can be sent, the DNS lookup must be performed. This can take a significant amount of time, especially if the DNS server is slow or the network connection is poor.
|
||||
|
||||
After the DNS lookup, the TCP socket must be connected and the TLS handshake might need to be performed. This can also take a significant amount of time.
|
||||
|
||||
After the request completes, consuming the response body can also take a significant amount of time and memory.
|
||||
|
||||
At every step of the way, Bun provides APIs to help you optimize the performance of your application.
|
||||
|
||||
### DNS prefetching
|
||||
|
||||
To prefetch a DNS entry, you can use the `dns.prefetch` API. This API is useful when you know you'll need to connect to a host soon and want to avoid the initial DNS lookup.
|
||||
|
||||
```ts
|
||||
import { dns } from "bun";
|
||||
|
||||
dns.prefetch("bun.com");
|
||||
```
|
||||
|
||||
#### DNS caching
|
||||
|
||||
By default, Bun caches and deduplicates DNS queries in-memory for up to 30 seconds. You can see the cache stats by calling `dns.getCacheStats()`:
|
||||
|
||||
To learn more about DNS caching in Bun, see the [DNS caching](https://bun.com/docs/api/dns) documentation.
|
||||
|
||||
### Preconnect to a host
|
||||
|
||||
To preconnect to a host, you can use the `fetch.preconnect` API. This API is useful when you know you'll need to connect to a host soon and want to start the initial DNS lookup, TCP socket connection, and TLS handshake early.
|
||||
|
||||
```ts
|
||||
import { fetch } from "bun";
|
||||
|
||||
fetch.preconnect("https://bun.com");
|
||||
```
|
||||
|
||||
Note: calling `fetch` immediately after `fetch.preconnect` will not make your request faster. Preconnecting only helps if you know you'll need to connect to a host soon, but you're not ready to make the request yet.
|
||||
|
||||
#### Preconnect at startup
|
||||
|
||||
To preconnect to a host at startup, you can pass `--fetch-preconnect`:
|
||||
|
||||
```sh
|
||||
$ bun --fetch-preconnect https://bun.com ./my-script.ts
|
||||
```
|
||||
|
||||
This is sort of like `<link rel="preconnect">` in HTML.
|
||||
|
||||
This feature is not implemented on Windows yet. If you're interested in using this feature on Windows, please file an issue and we can implement support for it on Windows.
|
||||
|
||||
### Connection pooling & HTTP keep-alive
|
||||
|
||||
Bun automatically reuses connections to the same host. This is known as connection pooling. This can significantly reduce the time it takes to establish a connection. You don't need to do anything to enable this; it's automatic.
|
||||
|
||||
#### Simultaneous connection limit
|
||||
|
||||
By default, Bun limits the maximum number of simultaneous `fetch` requests to 256. We do this for several reasons:
|
||||
|
||||
- It improves overall system stability. Operating systems have an upper limit on the number of simultaneous open TCP sockets, usually in the low thousands. Nearing this limit causes your entire computer to behave strangely. Applications hang and crash.
|
||||
- It encourages HTTP Keep-Alive connection reuse. For short-lived HTTP requests, the slowest step is often the initial connection setup. Reusing connections can save a lot of time.
|
||||
|
||||
When the limit is exceeded, the requests are queued and sent as soon as the next request ends.
|
||||
|
||||
You can increase the maximum number of simultaneous connections via the `BUN_CONFIG_MAX_HTTP_REQUESTS` environment variable:
|
||||
|
||||
```sh
|
||||
$ BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts
|
||||
```
|
||||
|
||||
The max value for this limit is currently set to 65,336. The maximum port number is 65,535, so it's quite difficult for any one computer to exceed this limit.
|
||||
|
||||
### Response buffering
|
||||
|
||||
Bun goes to great lengths to optimize the performance of reading the response body. The fastest way to read the response body is to use one of these methods:
|
||||
|
||||
- `response.text(): Promise<string>`
|
||||
- `response.json(): Promise<any>`
|
||||
- `response.formData(): Promise<FormData>`
|
||||
- `response.bytes(): Promise<Uint8Array>`
|
||||
- `response.arrayBuffer(): Promise<ArrayBuffer>`
|
||||
- `response.blob(): Promise<Blob>`
|
||||
|
||||
You can also use `Bun.write` to write the response body to a file on disk:
|
||||
|
||||
```ts
|
||||
import { write } from "bun";
|
||||
|
||||
await write("output.txt", response);
|
||||
```
|
||||
|
||||
### Implementation details
|
||||
|
||||
- Connection pooling is enabled by default but can be disabled per-request with `keepalive: false`. The `"Connection: close"` header can also be used to disable keep-alive.
|
||||
- Large file uploads are optimized using the operating system's `sendfile` syscall under specific conditions:
|
||||
- The file must be larger than 32KB
|
||||
- The request must not be using a proxy
|
||||
- On macOS, only regular files (not pipes, sockets, or devices) can use `sendfile`
|
||||
- When these conditions aren't met, or when using S3/streaming uploads, Bun falls back to reading the file into memory
|
||||
- This optimization is particularly effective for HTTP (not HTTPS) requests where the file can be sent directly from the kernel to the network stack
|
||||
- S3 operations automatically handle signing requests and merging authentication headers
|
||||
|
||||
Note: Many of these features are Bun-specific extensions to the standard fetch API.
|
||||
557
node_modules/bun-types/docs/api/ffi.md
generated
vendored
Normal file
557
node_modules/bun-types/docs/api/ffi.md
generated
vendored
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
{% callout %}
|
||||
**⚠️ Warning** — `bun:ffi` is **experimental**, with known bugs and limitations, and should not be relied on in production. The most stable way to interact with native code from Bun is to write a [Node-API module](/docs/api/node-api).
|
||||
{% /callout %}
|
||||
|
||||
Use the built-in `bun:ffi` module to efficiently call native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc).
|
||||
|
||||
## dlopen usage (`bun:ffi`)
|
||||
|
||||
To print the version number of `sqlite3`:
|
||||
|
||||
```ts
|
||||
import { dlopen, FFIType, suffix } from "bun:ffi";
|
||||
|
||||
// `suffix` is either "dylib", "so", or "dll" depending on the platform
|
||||
// you don't have to use "suffix", it's just there for convenience
|
||||
const path = `libsqlite3.${suffix}`;
|
||||
|
||||
const {
|
||||
symbols: {
|
||||
sqlite3_libversion, // the function to call
|
||||
},
|
||||
} = dlopen(
|
||||
path, // a library name or file path
|
||||
{
|
||||
sqlite3_libversion: {
|
||||
// no arguments, returns a string
|
||||
args: [],
|
||||
returns: FFIType.cstring,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
console.log(`SQLite 3 version: ${sqlite3_libversion()}`);
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
According to [our benchmark](https://github.com/oven-sh/bun/tree/main/bench/ffi), `bun:ffi` is roughly 2-6x faster than Node.js FFI via `Node-API`.
|
||||
|
||||
{% image src="/images/ffi.png" height="400" /%}
|
||||
|
||||
Bun generates & just-in-time compiles C bindings that efficiently convert values between JavaScript types and native types. To compile C, Bun embeds [TinyCC](https://github.com/TinyCC/tinycc), a small and fast C compiler.
|
||||
|
||||
## Usage
|
||||
|
||||
### Zig
|
||||
|
||||
```zig
|
||||
// add.zig
|
||||
pub export fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
To compile:
|
||||
|
||||
```bash
|
||||
$ zig build-lib add.zig -dynamic -OReleaseFast
|
||||
```
|
||||
|
||||
Pass a path to the shared library and a map of symbols to import into `dlopen`:
|
||||
|
||||
```ts
|
||||
import { dlopen, FFIType, suffix } from "bun:ffi";
|
||||
const { i32 } = FFIType;
|
||||
|
||||
const path = `libadd.${suffix}`;
|
||||
|
||||
const lib = dlopen(path, {
|
||||
add: {
|
||||
args: [i32, i32],
|
||||
returns: i32,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(lib.symbols.add(1, 2));
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
```rust
|
||||
// add.rs
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
```
|
||||
|
||||
To compile:
|
||||
|
||||
```bash
|
||||
$ rustc --crate-type cdylib add.rs
|
||||
```
|
||||
|
||||
### C++
|
||||
|
||||
```c
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" int32_t add(int32_t a, int32_t b) {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
To compile:
|
||||
|
||||
```bash
|
||||
$ zig build-lib add.cpp -dynamic -lc -lc++
|
||||
```
|
||||
|
||||
## FFI types
|
||||
|
||||
The following `FFIType` values are supported.
|
||||
|
||||
| `FFIType` | C Type | Aliases |
|
||||
| ---------- | -------------- | --------------------------- |
|
||||
| buffer | `char*` | |
|
||||
| cstring | `char*` | |
|
||||
| function | `(void*)(*)()` | `fn`, `callback` |
|
||||
| ptr | `void*` | `pointer`, `void*`, `char*` |
|
||||
| i8 | `int8_t` | `int8_t` |
|
||||
| i16 | `int16_t` | `int16_t` |
|
||||
| i32 | `int32_t` | `int32_t`, `int` |
|
||||
| i64 | `int64_t` | `int64_t` |
|
||||
| i64_fast | `int64_t` | |
|
||||
| u8 | `uint8_t` | `uint8_t` |
|
||||
| u16 | `uint16_t` | `uint16_t` |
|
||||
| u32 | `uint32_t` | `uint32_t` |
|
||||
| u64 | `uint64_t` | `uint64_t` |
|
||||
| u64_fast | `uint64_t` | |
|
||||
| f32 | `float` | `float` |
|
||||
| f64 | `double` | `double` |
|
||||
| bool | `bool` | |
|
||||
| char | `char` | |
|
||||
| napi_env | `napi_env` | |
|
||||
| napi_value | `napi_value` | |
|
||||
|
||||
Note: `buffer` arguments must be a `TypedArray` or `DataView`.
|
||||
|
||||
## Strings
|
||||
|
||||
JavaScript strings and C-like strings are different, and that complicates using strings with native libraries.
|
||||
|
||||
{% details summary="How are JavaScript strings and C strings different?" %}
|
||||
JavaScript strings:
|
||||
|
||||
- UTF16 (2 bytes per letter) or potentially latin1, depending on the JavaScript engine & what characters are used
|
||||
- `length` stored separately
|
||||
- Immutable
|
||||
|
||||
C strings:
|
||||
|
||||
- UTF8 (1 byte per letter), usually
|
||||
- The length is not stored. Instead, the string is null-terminated which means the length is the index of the first `\0` it finds
|
||||
- Mutable
|
||||
|
||||
{% /details %}
|
||||
|
||||
To solve this, `bun:ffi` exports `CString` which extends JavaScript's built-in `String` to support null-terminated strings and add a few extras:
|
||||
|
||||
```ts
|
||||
class CString extends String {
|
||||
/**
|
||||
* Given a `ptr`, this will automatically search for the closing `\0` character and transcode from UTF-8 to UTF-16 if necessary.
|
||||
*/
|
||||
constructor(ptr: number, byteOffset?: number, byteLength?: number): string;
|
||||
|
||||
/**
|
||||
* The ptr to the C string
|
||||
*
|
||||
* This `CString` instance is a clone of the string, so it
|
||||
* is safe to continue using this instance after the `ptr` has been
|
||||
* freed.
|
||||
*/
|
||||
ptr: number;
|
||||
byteOffset?: number;
|
||||
byteLength?: number;
|
||||
}
|
||||
```
|
||||
|
||||
To convert from a null-terminated string pointer to a JavaScript string:
|
||||
|
||||
```ts
|
||||
const myString = new CString(ptr);
|
||||
```
|
||||
|
||||
To convert from a pointer with a known length to a JavaScript string:
|
||||
|
||||
```ts
|
||||
const myString = new CString(ptr, 0, byteLength);
|
||||
```
|
||||
|
||||
The `new CString()` constructor clones the C string, so it is safe to continue using `myString` after `ptr` has been freed.
|
||||
|
||||
```ts
|
||||
my_library_free(myString.ptr);
|
||||
|
||||
// this is safe because myString is a clone
|
||||
console.log(myString);
|
||||
```
|
||||
|
||||
When used in `returns`, `FFIType.cstring` coerces the pointer to a JavaScript `string`. When used in `args`, `FFIType.cstring` is identical to `ptr`.
|
||||
|
||||
## Function pointers
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — Async functions are not yet supported.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
To call a function pointer from JavaScript, use `CFunction`. This is useful if using Node-API (napi) with Bun, and you've already loaded some symbols.
|
||||
|
||||
```ts
|
||||
import { CFunction } from "bun:ffi";
|
||||
|
||||
let myNativeLibraryGetVersion = /* somehow, you got this pointer */
|
||||
|
||||
const getVersion = new CFunction({
|
||||
returns: "cstring",
|
||||
args: [],
|
||||
ptr: myNativeLibraryGetVersion,
|
||||
});
|
||||
getVersion();
|
||||
```
|
||||
|
||||
If you have multiple function pointers, you can define them all at once with `linkSymbols`:
|
||||
|
||||
```ts
|
||||
import { linkSymbols } from "bun:ffi";
|
||||
|
||||
// getVersionPtrs defined elsewhere
|
||||
const [majorPtr, minorPtr, patchPtr] = getVersionPtrs();
|
||||
|
||||
const lib = linkSymbols({
|
||||
// Unlike with dlopen(), the names here can be whatever you want
|
||||
getMajor: {
|
||||
returns: "cstring",
|
||||
args: [],
|
||||
|
||||
// Since this doesn't use dlsym(), you have to provide a valid ptr
|
||||
// That ptr could be a number or a bigint
|
||||
// An invalid pointer will crash your program.
|
||||
ptr: majorPtr,
|
||||
},
|
||||
getMinor: {
|
||||
returns: "cstring",
|
||||
args: [],
|
||||
ptr: minorPtr,
|
||||
},
|
||||
getPatch: {
|
||||
returns: "cstring",
|
||||
args: [],
|
||||
ptr: patchPtr,
|
||||
},
|
||||
});
|
||||
|
||||
const [major, minor, patch] = [
|
||||
lib.symbols.getMajor(),
|
||||
lib.symbols.getMinor(),
|
||||
lib.symbols.getPatch(),
|
||||
];
|
||||
```
|
||||
|
||||
## Callbacks
|
||||
|
||||
Use `JSCallback` to create JavaScript callback functions that can be passed to C/FFI functions. The C/FFI function can call into the JavaScript/TypeScript code. This is useful for asynchronous code or whenever you want to call into JavaScript code from C.
|
||||
|
||||
```ts
|
||||
import { dlopen, JSCallback, ptr, CString } from "bun:ffi";
|
||||
|
||||
const {
|
||||
symbols: { search },
|
||||
close,
|
||||
} = dlopen("libmylib", {
|
||||
search: {
|
||||
returns: "usize",
|
||||
args: ["cstring", "callback"],
|
||||
},
|
||||
});
|
||||
|
||||
const searchIterator = new JSCallback(
|
||||
(ptr, length) => /hello/.test(new CString(ptr, length)),
|
||||
{
|
||||
returns: "bool",
|
||||
args: ["ptr", "usize"],
|
||||
},
|
||||
);
|
||||
|
||||
const str = Buffer.from("wwutwutwutwutwutwutwutwutwutwutut\0", "utf8");
|
||||
if (search(ptr(str), searchIterator)) {
|
||||
// found a match!
|
||||
}
|
||||
|
||||
// Sometime later:
|
||||
setTimeout(() => {
|
||||
searchIterator.close();
|
||||
close();
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
When you're done with a JSCallback, you should call `close()` to free the memory.
|
||||
|
||||
### Experimental thread-safe callbacks
|
||||
|
||||
`JSCallback` has experimental support for thread-safe callbacks. This will be needed if you pass a callback function into a different thread from its instantiation context. You can enable it with the optional `threadsafe` parameter.
|
||||
|
||||
Currently, thread-safe callbacks work best when run from another thread that is running JavaScript code, i.e. a [`Worker`](/docs/api/workers). A future version of Bun will enable them to be called from any thread (such as new threads spawned by your native library that Bun is not aware of).
|
||||
|
||||
```ts
|
||||
const searchIterator = new JSCallback(
|
||||
(ptr, length) => /hello/.test(new CString(ptr, length)),
|
||||
{
|
||||
returns: "bool",
|
||||
args: ["ptr", "usize"],
|
||||
threadsafe: true, // Optional. Defaults to `false`
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
**⚡️ Performance tip** — For a slight performance boost, directly pass `JSCallback.prototype.ptr` instead of the `JSCallback` object:
|
||||
|
||||
```ts
|
||||
const onResolve = new JSCallback(arg => arg === 42, {
|
||||
returns: "bool",
|
||||
args: ["i32"],
|
||||
});
|
||||
const setOnResolve = new CFunction({
|
||||
returns: "bool",
|
||||
args: ["function"],
|
||||
ptr: myNativeLibrarySetOnResolve,
|
||||
});
|
||||
|
||||
// This code runs slightly faster:
|
||||
setOnResolve(onResolve.ptr);
|
||||
|
||||
// Compared to this:
|
||||
setOnResolve(onResolve);
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Pointers
|
||||
|
||||
Bun represents [pointers](<https://en.wikipedia.org/wiki/Pointer_(computer_programming)>) as a `number` in JavaScript.
|
||||
|
||||
{% details summary="How does a 64 bit pointer fit in a JavaScript number?" %}
|
||||
64-bit processors support up to [52 bits of addressable space](https://en.wikipedia.org/wiki/64-bit_computing#Limits_of_processors). [JavaScript numbers](https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64) support 53 bits of usable space, so that leaves us with about 11 bits of extra space.
|
||||
|
||||
**Why not `BigInt`?** `BigInt` is slower. JavaScript engines allocate a separate `BigInt` which means they can't fit into a regular JavaScript value. If you pass a `BigInt` to a function, it will be converted to a `number`
|
||||
{% /details %}
|
||||
|
||||
To convert from a `TypedArray` to a pointer:
|
||||
|
||||
```ts
|
||||
import { ptr } from "bun:ffi";
|
||||
let myTypedArray = new Uint8Array(32);
|
||||
const myPtr = ptr(myTypedArray);
|
||||
```
|
||||
|
||||
To convert from a pointer to an `ArrayBuffer`:
|
||||
|
||||
```ts
|
||||
import { ptr, toArrayBuffer } from "bun:ffi";
|
||||
let myTypedArray = new Uint8Array(32);
|
||||
const myPtr = ptr(myTypedArray);
|
||||
|
||||
// toArrayBuffer accepts a `byteOffset` and `byteLength`
|
||||
// if `byteLength` is not provided, it is assumed to be a null-terminated pointer
|
||||
myTypedArray = new Uint8Array(toArrayBuffer(myPtr, 0, 32), 0, 32);
|
||||
```
|
||||
|
||||
To read data from a pointer, you have two options. For long-lived pointers, use a `DataView`:
|
||||
|
||||
```ts
|
||||
import { toArrayBuffer } from "bun:ffi";
|
||||
let myDataView = new DataView(toArrayBuffer(myPtr, 0, 32));
|
||||
|
||||
console.log(
|
||||
myDataView.getUint8(0, true),
|
||||
myDataView.getUint8(1, true),
|
||||
myDataView.getUint8(2, true),
|
||||
myDataView.getUint8(3, true),
|
||||
);
|
||||
```
|
||||
|
||||
For short-lived pointers, use `read`:
|
||||
|
||||
```ts
|
||||
import { read } from "bun:ffi";
|
||||
|
||||
console.log(
|
||||
// ptr, byteOffset
|
||||
read.u8(myPtr, 0),
|
||||
read.u8(myPtr, 1),
|
||||
read.u8(myPtr, 2),
|
||||
read.u8(myPtr, 3),
|
||||
);
|
||||
```
|
||||
|
||||
The `read` function behaves similarly to `DataView`, but it's usually faster because it doesn't need to create a `DataView` or `ArrayBuffer`.
|
||||
|
||||
| `FFIType` | `read` function |
|
||||
| --------- | --------------- |
|
||||
| ptr | `read.ptr` |
|
||||
| i8 | `read.i8` |
|
||||
| i16 | `read.i16` |
|
||||
| i32 | `read.i32` |
|
||||
| i64 | `read.i64` |
|
||||
| u8 | `read.u8` |
|
||||
| u16 | `read.u16` |
|
||||
| u32 | `read.u32` |
|
||||
| u64 | `read.u64` |
|
||||
| f32 | `read.f32` |
|
||||
| f64 | `read.f64` |
|
||||
|
||||
### Memory management
|
||||
|
||||
`bun:ffi` does not manage memory for you. You must free the memory when you're done with it.
|
||||
|
||||
#### From JavaScript
|
||||
|
||||
If you want to track when a `TypedArray` is no longer in use from JavaScript, you can use a [FinalizationRegistry](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry).
|
||||
|
||||
#### From C, Rust, Zig, etc
|
||||
|
||||
If you want to track when a `TypedArray` is no longer in use from C or FFI, you can pass a callback and an optional context pointer to `toArrayBuffer` or `toBuffer`. This function is called at some point later, once the garbage collector frees the underlying `ArrayBuffer` JavaScript object.
|
||||
|
||||
The expected signature is the same as in [JavaScriptCore's C API](https://developer.apple.com/documentation/javascriptcore/jstypedarraybytesdeallocator?language=objc):
|
||||
|
||||
```c
|
||||
typedef void (*JSTypedArrayBytesDeallocator)(void *bytes, void *deallocatorContext);
|
||||
```
|
||||
|
||||
```ts
|
||||
import { toArrayBuffer } from "bun:ffi";
|
||||
|
||||
// with a deallocatorContext:
|
||||
toArrayBuffer(
|
||||
bytes,
|
||||
byteOffset,
|
||||
|
||||
byteLength,
|
||||
|
||||
// this is an optional pointer to a callback
|
||||
deallocatorContext,
|
||||
|
||||
// this is a pointer to a function
|
||||
jsTypedArrayBytesDeallocator,
|
||||
);
|
||||
|
||||
// without a deallocatorContext:
|
||||
toArrayBuffer(
|
||||
bytes,
|
||||
byteOffset,
|
||||
|
||||
byteLength,
|
||||
|
||||
// this is a pointer to a function
|
||||
jsTypedArrayBytesDeallocator,
|
||||
);
|
||||
```
|
||||
|
||||
### Memory safety
|
||||
|
||||
Using raw pointers outside of FFI is extremely not recommended. A future version of Bun may add a CLI flag to disable `bun:ffi`.
|
||||
|
||||
### Pointer alignment
|
||||
|
||||
If an API expects a pointer sized to something other than `char` or `u8`, make sure the `TypedArray` is also that size. A `u64*` is not exactly the same as `[8]u8*` due to alignment.
|
||||
|
||||
### Passing a pointer
|
||||
|
||||
Where FFI functions expect a pointer, pass a `TypedArray` of equivalent size:
|
||||
|
||||
```ts
|
||||
import { dlopen, FFIType } from "bun:ffi";
|
||||
|
||||
const {
|
||||
symbols: { encode_png },
|
||||
} = dlopen(myLibraryPath, {
|
||||
encode_png: {
|
||||
// FFIType's can be specified as strings too
|
||||
args: ["ptr", "u32", "u32"],
|
||||
returns: FFIType.ptr,
|
||||
},
|
||||
});
|
||||
|
||||
const pixels = new Uint8ClampedArray(128 * 128 * 4);
|
||||
pixels.fill(254);
|
||||
pixels.subarray(0, 32 * 32 * 2).fill(0);
|
||||
|
||||
const out = encode_png(
|
||||
// pixels will be passed as a pointer
|
||||
pixels,
|
||||
|
||||
128,
|
||||
128,
|
||||
);
|
||||
```
|
||||
|
||||
The [auto-generated wrapper](https://github.com/oven-sh/bun/blob/6a65631cbdcae75bfa1e64323a6ad613a922cd1a/src/bun.js/ffi.exports.js#L180-L182) converts the pointer to a `TypedArray`.
|
||||
|
||||
{% details summary="Hardmode" %}
|
||||
|
||||
If you don't want the automatic conversion or you want a pointer to a specific byte offset within the `TypedArray`, you can also directly get the pointer to the `TypedArray`:
|
||||
|
||||
```ts
|
||||
import { dlopen, FFIType, ptr } from "bun:ffi";
|
||||
|
||||
const {
|
||||
symbols: { encode_png },
|
||||
} = dlopen(myLibraryPath, {
|
||||
encode_png: {
|
||||
// FFIType's can be specified as strings too
|
||||
args: ["ptr", "u32", "u32"],
|
||||
returns: FFIType.ptr,
|
||||
},
|
||||
});
|
||||
|
||||
const pixels = new Uint8ClampedArray(128 * 128 * 4);
|
||||
pixels.fill(254);
|
||||
|
||||
// this returns a number! not a BigInt!
|
||||
const myPtr = ptr(pixels);
|
||||
|
||||
const out = encode_png(
|
||||
myPtr,
|
||||
|
||||
// dimensions:
|
||||
128,
|
||||
128,
|
||||
);
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
### Reading pointers
|
||||
|
||||
```ts
|
||||
const out = encode_png(
|
||||
// pixels will be passed as a pointer
|
||||
pixels,
|
||||
|
||||
// dimensions:
|
||||
128,
|
||||
128,
|
||||
);
|
||||
|
||||
// assuming it is 0-terminated, it can be read like this:
|
||||
let png = new Uint8Array(toArrayBuffer(out));
|
||||
|
||||
// save it to disk:
|
||||
await Bun.write("out.png", png);
|
||||
```
|
||||
366
node_modules/bun-types/docs/api/file-io.md
generated
vendored
Normal file
366
node_modules/bun-types/docs/api/file-io.md
generated
vendored
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
{% callout %}
|
||||
|
||||
<!-- **Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. Existing Node.js projects may use Bun's [nearly complete](https://bun.com/docs/runtime/nodejs-apis#node-fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module. -->
|
||||
|
||||
**Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. For operations that are not yet available with `Bun.file`, such as `mkdir` or `readdir`, you can use Bun's [nearly complete](https://bun.com/docs/runtime/nodejs-apis#node-fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
Bun provides a set of optimized APIs for reading and writing files.
|
||||
|
||||
## Reading files (`Bun.file()`)
|
||||
|
||||
`Bun.file(path): BunFile`
|
||||
|
||||
Create a `BunFile` instance with the `Bun.file(path)` function. A `BunFile` represents a lazily-loaded file; initializing it does not actually read the file from disk.
|
||||
|
||||
```ts
|
||||
const foo = Bun.file("foo.txt"); // relative to cwd
|
||||
foo.size; // number of bytes
|
||||
foo.type; // MIME type
|
||||
```
|
||||
|
||||
The reference conforms to the [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) interface, so the contents can be read in various formats.
|
||||
|
||||
```ts
|
||||
const foo = Bun.file("foo.txt");
|
||||
|
||||
await foo.text(); // contents as a string
|
||||
await foo.stream(); // contents as ReadableStream
|
||||
await foo.arrayBuffer(); // contents as ArrayBuffer
|
||||
await foo.bytes(); // contents as Uint8Array
|
||||
```
|
||||
|
||||
File references can also be created using numerical [file descriptors](https://en.wikipedia.org/wiki/File_descriptor) or `file://` URLs.
|
||||
|
||||
```ts
|
||||
Bun.file(1234);
|
||||
Bun.file(new URL(import.meta.url)); // reference to the current file
|
||||
```
|
||||
|
||||
A `BunFile` can point to a location on disk where a file does not exist.
|
||||
|
||||
```ts
|
||||
const notreal = Bun.file("notreal.txt");
|
||||
notreal.size; // 0
|
||||
notreal.type; // "text/plain;charset=utf-8"
|
||||
const exists = await notreal.exists(); // false
|
||||
```
|
||||
|
||||
The default MIME type is `text/plain;charset=utf-8`, but it can be overridden by passing a second argument to `Bun.file`.
|
||||
|
||||
```ts
|
||||
const notreal = Bun.file("notreal.json", { type: "application/json" });
|
||||
notreal.type; // => "application/json;charset=utf-8"
|
||||
```
|
||||
|
||||
For convenience, Bun exposes `stdin`, `stdout` and `stderr` as instances of `BunFile`.
|
||||
|
||||
```ts
|
||||
Bun.stdin; // readonly
|
||||
Bun.stdout;
|
||||
Bun.stderr;
|
||||
```
|
||||
|
||||
### Deleting files (`file.delete()`)
|
||||
|
||||
You can delete a file by calling the `.delete()` function.
|
||||
|
||||
```ts
|
||||
await Bun.file("logs.json").delete();
|
||||
```
|
||||
|
||||
## Writing files (`Bun.write()`)
|
||||
|
||||
`Bun.write(destination, data): Promise<number>`
|
||||
|
||||
The `Bun.write` function is a multi-tool for writing payloads of all kinds to disk.
|
||||
|
||||
The first argument is the `destination` which can have any of the following types:
|
||||
|
||||
- `string`: A path to a location on the file system. Use the `"path"` module to manipulate paths.
|
||||
- `URL`: A `file://` descriptor.
|
||||
- `BunFile`: A file reference.
|
||||
|
||||
The second argument is the data to be written. It can be any of the following:
|
||||
|
||||
- `string`
|
||||
- `Blob` (including `BunFile`)
|
||||
- `ArrayBuffer` or `SharedArrayBuffer`
|
||||
- `TypedArray` (`Uint8Array`, et. al.)
|
||||
- `Response`
|
||||
|
||||
All possible permutations are handled using the fastest available system calls on the current platform.
|
||||
|
||||
{% details summary="See syscalls" %}
|
||||
|
||||
{% table %}
|
||||
|
||||
- Output
|
||||
- Input
|
||||
- System call
|
||||
- Platform
|
||||
|
||||
---
|
||||
|
||||
- file
|
||||
- file
|
||||
- copy_file_range
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- file
|
||||
- pipe
|
||||
- sendfile
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- pipe
|
||||
- pipe
|
||||
- splice
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- terminal
|
||||
- file
|
||||
- sendfile
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- terminal
|
||||
- terminal
|
||||
- sendfile
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- socket
|
||||
- file or pipe
|
||||
- sendfile (if http, not https)
|
||||
- Linux
|
||||
|
||||
---
|
||||
|
||||
- file (doesn't exist)
|
||||
- file (path)
|
||||
- clonefile
|
||||
- macOS
|
||||
|
||||
---
|
||||
|
||||
- file (exists)
|
||||
- file
|
||||
- fcopyfile
|
||||
- macOS
|
||||
|
||||
---
|
||||
|
||||
- file
|
||||
- Blob or string
|
||||
- write
|
||||
- macOS
|
||||
|
||||
---
|
||||
|
||||
- file
|
||||
- Blob or string
|
||||
- write
|
||||
- Linux
|
||||
|
||||
{% /table %}
|
||||
|
||||
{% /details %}
|
||||
|
||||
To write a string to disk:
|
||||
|
||||
```ts
|
||||
const data = `It was the best of times, it was the worst of times.`;
|
||||
await Bun.write("output.txt", data);
|
||||
```
|
||||
|
||||
To copy a file to another location on disk:
|
||||
|
||||
```js
|
||||
const input = Bun.file("input.txt");
|
||||
const output = Bun.file("output.txt"); // doesn't exist yet!
|
||||
await Bun.write(output, input);
|
||||
```
|
||||
|
||||
To write a byte array to disk:
|
||||
|
||||
```ts
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode("datadatadata"); // Uint8Array
|
||||
await Bun.write("output.txt", data);
|
||||
```
|
||||
|
||||
To write a file to `stdout`:
|
||||
|
||||
```ts
|
||||
const input = Bun.file("input.txt");
|
||||
await Bun.write(Bun.stdout, input);
|
||||
```
|
||||
|
||||
To write the body of an HTTP response to disk:
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://bun.com");
|
||||
await Bun.write("index.html", response);
|
||||
```
|
||||
|
||||
## Incremental writing with `FileSink`
|
||||
|
||||
Bun provides a native incremental file writing API called `FileSink`. To retrieve a `FileSink` instance from a `BunFile`:
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer();
|
||||
```
|
||||
|
||||
To incrementally write to the file, call `.write()`.
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer();
|
||||
|
||||
writer.write("it was the best of times\n");
|
||||
writer.write("it was the worst of times\n");
|
||||
```
|
||||
|
||||
These chunks will be buffered internally. To flush the buffer to disk, use `.flush()`. This returns the number of flushed bytes.
|
||||
|
||||
```ts
|
||||
writer.flush(); // write buffer to disk
|
||||
```
|
||||
|
||||
The buffer will also auto-flush when the `FileSink`'s _high water mark_ is reached; that is, when its internal buffer is full. This value can be configured.
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB
|
||||
```
|
||||
|
||||
To flush the buffer and close the file:
|
||||
|
||||
```ts
|
||||
writer.end();
|
||||
```
|
||||
|
||||
Note that, by default, the `bun` process will stay alive until this `FileSink` is explicitly closed with `.end()`. To opt out of this behavior, you can "unref" the instance.
|
||||
|
||||
```ts
|
||||
writer.unref();
|
||||
|
||||
// to "re-ref" it later
|
||||
writer.ref();
|
||||
```
|
||||
|
||||
## Directories
|
||||
|
||||
Bun's implementation of `node:fs` is fast, and we haven't implemented a Bun-specific API for reading directories just yet. For now, you should use `node:fs` for working with directories in Bun.
|
||||
|
||||
### Reading directories (readdir)
|
||||
|
||||
To read a directory in Bun, use `readdir` from `node:fs`.
|
||||
|
||||
```ts
|
||||
import { readdir } from "node:fs/promises";
|
||||
|
||||
// read all the files in the current directory
|
||||
const files = await readdir(import.meta.dir);
|
||||
```
|
||||
|
||||
#### Reading directories recursively
|
||||
|
||||
To recursively read a directory in Bun, use `readdir` with `recursive: true`.
|
||||
|
||||
```ts
|
||||
import { readdir } from "node:fs/promises";
|
||||
|
||||
// read all the files in the current directory, recursively
|
||||
const files = await readdir("../", { recursive: true });
|
||||
```
|
||||
|
||||
### Creating directories (mkdir)
|
||||
|
||||
To recursively create a directory, use `mkdir` in `node:fs`:
|
||||
|
||||
```ts
|
||||
import { mkdir } from "node:fs/promises";
|
||||
|
||||
await mkdir("path/to/dir", { recursive: true });
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
The following is a 3-line implementation of the Linux `cat` command.
|
||||
|
||||
```ts#cat.ts
|
||||
// Usage
|
||||
// $ bun ./cat.ts ./path-to-file
|
||||
|
||||
import { resolve } from "path";
|
||||
|
||||
const path = resolve(process.argv.at(-1));
|
||||
await Bun.write(Bun.stdout, Bun.file(path));
|
||||
```
|
||||
|
||||
To run the file:
|
||||
|
||||
```bash
|
||||
$ bun ./cat.ts ./path-to-file
|
||||
```
|
||||
|
||||
It runs 2x faster than GNU `cat` for large files on Linux.
|
||||
|
||||
{% image src="/images/cat.jpg" /%}
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
interface Bun {
|
||||
stdin: BunFile;
|
||||
stdout: BunFile;
|
||||
stderr: BunFile;
|
||||
|
||||
file(path: string | number | URL, options?: { type?: string }): BunFile;
|
||||
|
||||
write(
|
||||
destination: string | number | BunFile | URL,
|
||||
input:
|
||||
| string
|
||||
| Blob
|
||||
| ArrayBuffer
|
||||
| SharedArrayBuffer
|
||||
| TypedArray
|
||||
| Response,
|
||||
): Promise<number>;
|
||||
}
|
||||
|
||||
interface BunFile {
|
||||
readonly size: number;
|
||||
readonly type: string;
|
||||
|
||||
text(): Promise<string>;
|
||||
stream(): ReadableStream;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
json(): Promise<any>;
|
||||
writer(params: { highWaterMark?: number }): FileSink;
|
||||
exists(): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface FileSink {
|
||||
write(
|
||||
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
|
||||
): number;
|
||||
flush(): number | Promise<number>;
|
||||
end(error?: Error): number | Promise<number>;
|
||||
start(options?: { highWaterMark?: number }): void;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
}
|
||||
```
|
||||
112
node_modules/bun-types/docs/api/file-system-router.md
generated
vendored
Normal file
112
node_modules/bun-types/docs/api/file-system-router.md
generated
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
Bun provides a fast API for resolving routes against file-system paths. This API is primarily intended for library authors. At the moment only Next.js-style file-system routing is supported, but other styles may be added in the future.
|
||||
|
||||
## Next.js-style
|
||||
|
||||
The `FileSystemRouter` class can resolve routes against a `pages` directory. (The Next.js 13 `app` directory is not yet supported.) Consider the following `pages` directory:
|
||||
|
||||
```txt
|
||||
pages
|
||||
├── index.tsx
|
||||
├── settings.tsx
|
||||
├── blog
|
||||
│ ├── [slug].tsx
|
||||
│ └── index.tsx
|
||||
└── [[...catchall]].tsx
|
||||
```
|
||||
|
||||
The `FileSystemRouter` can be used to resolve routes against this directory:
|
||||
|
||||
```ts
|
||||
const router = new Bun.FileSystemRouter({
|
||||
style: "nextjs",
|
||||
dir: "./pages",
|
||||
origin: "https://mydomain.com",
|
||||
assetPrefix: "_next/static/"
|
||||
});
|
||||
router.match("/");
|
||||
|
||||
// =>
|
||||
{
|
||||
filePath: "/path/to/pages/index.tsx",
|
||||
kind: "exact",
|
||||
name: "/",
|
||||
pathname: "/",
|
||||
src: "https://mydomain.com/_next/static/pages/index.tsx"
|
||||
}
|
||||
```
|
||||
|
||||
Query parameters will be parsed and returned in the `query` property.
|
||||
|
||||
```ts
|
||||
router.match("/settings?foo=bar");
|
||||
|
||||
// =>
|
||||
{
|
||||
filePath: "/Users/colinmcd94/Documents/bun/fun/pages/settings.tsx",
|
||||
kind: "dynamic",
|
||||
name: "/settings",
|
||||
pathname: "/settings?foo=bar",
|
||||
src: "https://mydomain.com/_next/static/pages/settings.tsx",
|
||||
query: {
|
||||
foo: "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The router will automatically parse URL parameters and return them in the `params` property:
|
||||
|
||||
```ts
|
||||
router.match("/blog/my-cool-post");
|
||||
|
||||
// =>
|
||||
{
|
||||
filePath: "/Users/colinmcd94/Documents/bun/fun/pages/blog/[slug].tsx",
|
||||
kind: "dynamic",
|
||||
name: "/blog/[slug]",
|
||||
pathname: "/blog/my-cool-post",
|
||||
src: "https://mydomain.com/_next/static/pages/blog/[slug].tsx",
|
||||
params: {
|
||||
slug: "my-cool-post"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `.match()` method also accepts `Request` and `Response` objects. The `url` property will be used to resolve the route.
|
||||
|
||||
```ts
|
||||
router.match(new Request("https://example.com/blog/my-cool-post"));
|
||||
```
|
||||
|
||||
The router will read the directory contents on initialization. To re-scan the files, use the `.reload()` method.
|
||||
|
||||
```ts
|
||||
router.reload();
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
interface Bun {
|
||||
class FileSystemRouter {
|
||||
constructor(params: {
|
||||
dir: string;
|
||||
style: "nextjs";
|
||||
origin?: string;
|
||||
assetPrefix?: string;
|
||||
fileExtensions?: string[];
|
||||
});
|
||||
|
||||
reload(): void;
|
||||
|
||||
match(path: string | Request | Response): {
|
||||
filePath: string;
|
||||
kind: "exact" | "catch-all" | "optional-catch-all" | "dynamic";
|
||||
name: string;
|
||||
pathname: string;
|
||||
src: string;
|
||||
params?: Record<string, string>;
|
||||
query?: Record<string, string>;
|
||||
} | null
|
||||
}
|
||||
}
|
||||
```
|
||||
19
node_modules/bun-types/docs/api/file.md
generated
vendored
Normal file
19
node_modules/bun-types/docs/api/file.md
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Bun.js has fast paths for common use cases that make Web APIs live up to the performance demands of servers and CLIs.
|
||||
|
||||
`Bun.file(path)` returns a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that represents a lazily-loaded file.
|
||||
|
||||
When you pass a file blob to `Bun.write`, Bun automatically uses a faster system call:
|
||||
|
||||
```js
|
||||
const blob = Bun.file("input.txt");
|
||||
await Bun.write("output.txt", blob);
|
||||
```
|
||||
|
||||
On Linux, this uses the [`copy_file_range`](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) syscall and on macOS, this becomes `clonefile` (or [`fcopyfile`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/copyfile.3.html)).
|
||||
|
||||
`Bun.write` also supports [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. It automatically converts to a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
|
||||
|
||||
```js
|
||||
// Eventually, this will stream the response to disk but today it buffers
|
||||
await Bun.write("index.html", await fetch("https://example.com"));
|
||||
```
|
||||
157
node_modules/bun-types/docs/api/glob.md
generated
vendored
Normal file
157
node_modules/bun-types/docs/api/glob.md
generated
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
Bun includes a fast native implementation of file globbing.
|
||||
|
||||
## Quickstart
|
||||
|
||||
**Scan a directory for files matching `*.ts`**:
|
||||
|
||||
```ts
|
||||
import { Glob } from "bun";
|
||||
|
||||
const glob = new Glob("**/*.ts");
|
||||
|
||||
// Scans the current working directory and each of its sub-directories recursively
|
||||
for await (const file of glob.scan(".")) {
|
||||
console.log(file); // => "index.ts"
|
||||
}
|
||||
```
|
||||
|
||||
**Match a string against a glob pattern**:
|
||||
|
||||
```ts
|
||||
import { Glob } from "bun";
|
||||
|
||||
const glob = new Glob("*.ts");
|
||||
|
||||
glob.match("index.ts"); // => true
|
||||
glob.match("index.js"); // => false
|
||||
```
|
||||
|
||||
`Glob` is a class which implements the following interface:
|
||||
|
||||
```ts
|
||||
class Glob {
|
||||
scan(root: string | ScanOptions): AsyncIterable<string>;
|
||||
scanSync(root: string | ScanOptions): Iterable<string>;
|
||||
|
||||
match(path: string): boolean;
|
||||
}
|
||||
|
||||
interface ScanOptions {
|
||||
/**
|
||||
* The root directory to start matching from. Defaults to `process.cwd()`
|
||||
*/
|
||||
cwd?: string;
|
||||
|
||||
/**
|
||||
* Allow patterns to match entries that begin with a period (`.`).
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
dot?: boolean;
|
||||
|
||||
/**
|
||||
* Return the absolute path for entries.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
absolute?: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether to traverse descendants of symbolic link directories.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
followSymlinks?: boolean;
|
||||
|
||||
/**
|
||||
* Throw an error when symbolic link is broken
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
throwErrorOnBrokenSymlink?: boolean;
|
||||
|
||||
/**
|
||||
* Return only files.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
onlyFiles?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## Supported Glob Patterns
|
||||
|
||||
Bun supports the following glob patterns:
|
||||
|
||||
### `?` - Match any single character
|
||||
|
||||
```ts
|
||||
const glob = new Glob("???.ts");
|
||||
glob.match("foo.ts"); // => true
|
||||
glob.match("foobar.ts"); // => false
|
||||
```
|
||||
|
||||
### `*` - Matches zero or more characters, except for path separators (`/` or `\`)
|
||||
|
||||
```ts
|
||||
const glob = new Glob("*.ts");
|
||||
glob.match("index.ts"); // => true
|
||||
glob.match("src/index.ts"); // => false
|
||||
```
|
||||
|
||||
### `**` - Match any number of characters including `/`
|
||||
|
||||
```ts
|
||||
const glob = new Glob("**/*.ts");
|
||||
glob.match("index.ts"); // => true
|
||||
glob.match("src/index.ts"); // => true
|
||||
glob.match("src/index.js"); // => false
|
||||
```
|
||||
|
||||
### `[ab]` - Matches one of the characters contained in the brackets, as well as character ranges
|
||||
|
||||
```ts
|
||||
const glob = new Glob("ba[rz].ts");
|
||||
glob.match("bar.ts"); // => true
|
||||
glob.match("baz.ts"); // => true
|
||||
glob.match("bat.ts"); // => false
|
||||
```
|
||||
|
||||
You can use character ranges (e.g `[0-9]`, `[a-z]`) as well as the negation operators `^` or `!` to match anything _except_ the characters contained within the braces (e.g `[^ab]`, `[!a-z]`)
|
||||
|
||||
```ts
|
||||
const glob = new Glob("ba[a-z][0-9][^4-9].ts");
|
||||
glob.match("bar01.ts"); // => true
|
||||
glob.match("baz83.ts"); // => true
|
||||
glob.match("bat22.ts"); // => true
|
||||
glob.match("bat24.ts"); // => false
|
||||
glob.match("ba0a8.ts"); // => false
|
||||
```
|
||||
|
||||
### `{a,b,c}` - Match any of the given patterns
|
||||
|
||||
```ts
|
||||
const glob = new Glob("{a,b,c}.ts");
|
||||
glob.match("a.ts"); // => true
|
||||
glob.match("b.ts"); // => true
|
||||
glob.match("c.ts"); // => true
|
||||
glob.match("d.ts"); // => false
|
||||
```
|
||||
|
||||
These match patterns can be deeply nested (up to 10 levels), and contain any of the wildcards from above.
|
||||
|
||||
### `!` - Negates the result at the start of a pattern
|
||||
|
||||
```ts
|
||||
const glob = new Glob("!index.ts");
|
||||
glob.match("index.ts"); // => false
|
||||
glob.match("foo.ts"); // => true
|
||||
```
|
||||
|
||||
### `\` - Escapes any of the special characters above
|
||||
|
||||
```ts
|
||||
const glob = new Glob("\\!index.ts");
|
||||
glob.match("!index.ts"); // => true
|
||||
glob.match("index.ts"); // => false
|
||||
```
|
||||
387
node_modules/bun-types/docs/api/globals.md
generated
vendored
Normal file
387
node_modules/bun-types/docs/api/globals.md
generated
vendored
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
Bun implements the following globals.
|
||||
|
||||
{% table %}
|
||||
|
||||
- Global
|
||||
- Source
|
||||
- Notes
|
||||
|
||||
---
|
||||
|
||||
- [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
|
||||
- Web
|
||||
- Intended for command-line tools
|
||||
|
||||
---
|
||||
|
||||
- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)
|
||||
- Node.js
|
||||
- See [Node.js > `Buffer`](https://bun.com/docs/runtime/nodejs-apis#node-buffer)
|
||||
|
||||
---
|
||||
|
||||
- `Bun`
|
||||
- Bun
|
||||
- Subject to change as additional APIs are added
|
||||
|
||||
---
|
||||
|
||||
- [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
|
||||
- Web
|
||||
- Intended for command-line tools
|
||||
|
||||
---
|
||||
|
||||
- [`__dirname`](https://nodejs.org/api/globals.html#__dirname)
|
||||
- Node.js
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`__filename`](https://nodejs.org/api/globals.html#__filename)
|
||||
- Node.js
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`atob()`](https://developer.mozilla.org/en-US/docs/Web/API/atob)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`btoa()`](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- `BuildMessage`
|
||||
- Bun
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`clearImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearImmediate)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`clearInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearInterval)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`clearTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`Crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/crypto)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||
- Web
|
||||
- Also [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent).
|
||||
|
||||
---
|
||||
|
||||
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`exports`](https://nodejs.org/api/globals.html#exports)
|
||||
- Node.js
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`global`](https://nodejs.org/api/globals.html#global)
|
||||
- Node.js
|
||||
- See [Node.js > `global`](https://bun.com/docs/runtime/nodejs-apis#global).
|
||||
|
||||
---
|
||||
|
||||
- [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)
|
||||
- Cross-platform
|
||||
- Aliases to `global`
|
||||
|
||||
---
|
||||
|
||||
- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`HTMLRewriter`](https://bun.com/docs/api/html-rewriter)
|
||||
- Cloudflare
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`module`](https://nodejs.org/api/globals.html#module)
|
||||
- Node.js
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/performance)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`process`](https://nodejs.org/api/process.html)
|
||||
- Node.js
|
||||
- See [Node.js > `process`](https://bun.com/docs/runtime/nodejs-apis#node-process)
|
||||
|
||||
---
|
||||
|
||||
- [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
|
||||
- Web
|
||||
- Intended for command-line tools
|
||||
|
||||
---
|
||||
|
||||
- [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`ReadableByteStreamController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableByteStreamController)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`ReadableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`require()`](https://nodejs.org/api/globals.html#require)
|
||||
- Node.js
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- `ResolveMessage`
|
||||
- Bun
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`setImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`ShadowRealm`](https://github.com/tc39/proposal-shadowrealm)
|
||||
- Web
|
||||
- Stage 3 proposal
|
||||
|
||||
---
|
||||
|
||||
- [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`TransformStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStreamDefaultController)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`WebAssembly`](https://nodejs.org/api/globals.html#webassembly)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`WritableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController)
|
||||
- Web
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
- [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)
|
||||
- Web
|
||||
-
|
||||
|
||||
{% /table %}
|
||||
318
node_modules/bun-types/docs/api/hashing.md
generated
vendored
Normal file
318
node_modules/bun-types/docs/api/hashing.md
generated
vendored
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
{% callout %}
|
||||
|
||||
Bun implements the `createHash` and `createHmac` functions from [`node:crypto`](https://nodejs.org/api/crypto.html) in addition to the Bun-native APIs documented below.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## `Bun.password`
|
||||
|
||||
`Bun.password` is a collection of utility functions for hashing and verifying passwords with various cryptographically secure algorithms.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = await Bun.password.hash(password);
|
||||
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh6E8DQRhEXg/M/SqYCNu6gVdRRNs$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
|
||||
|
||||
const isMatch = await Bun.password.verify(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
The second argument to `Bun.password.hash` accepts a params object that lets you pick and configure the hashing algorithm.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
// use argon2 (default)
|
||||
const argonHash = await Bun.password.hash(password, {
|
||||
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
|
||||
memoryCost: 4, // memory usage in kibibytes
|
||||
timeCost: 3, // the number of iterations
|
||||
});
|
||||
|
||||
// use bcrypt
|
||||
const bcryptHash = await Bun.password.hash(password, {
|
||||
algorithm: "bcrypt",
|
||||
cost: 4, // number between 4-31
|
||||
});
|
||||
```
|
||||
|
||||
The algorithm used to create the hash is stored in the hash itself. When using `bcrypt`, the returned hash is encoded in [Modular Crypt Format](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html) for compatibility with most existing `bcrypt` implementations; with `argon2` the result is encoded in the newer [PHC format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md).
|
||||
|
||||
The `verify` function automatically detects the algorithm based on the input hash and use the correct verification method. It can correctly infer the algorithm from both PHC- or MCF-encoded hashes.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = await Bun.password.hash(password, {
|
||||
/* config */
|
||||
});
|
||||
|
||||
const isMatch = await Bun.password.verify(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
Synchronous versions of all functions are also available. Keep in mind that these functions are computationally expensive, so using a blocking API may degrade application performance.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = Bun.password.hashSync(password, {
|
||||
/* config */
|
||||
});
|
||||
|
||||
const isMatch = Bun.password.verifySync(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
### Salt
|
||||
|
||||
When you use `Bun.password.hash`, a salt is automatically generated and included in the hash.
|
||||
|
||||
### bcrypt - Modular Crypt Format
|
||||
|
||||
In the following [Modular Crypt Format](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html) hash (used by `bcrypt`):
|
||||
|
||||
Input:
|
||||
|
||||
```ts
|
||||
await Bun.password.hash("hello", {
|
||||
algorithm: "bcrypt",
|
||||
});
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```sh
|
||||
$2b$10$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi;
|
||||
```
|
||||
|
||||
The format is composed of:
|
||||
|
||||
- `bcrypt`: `$2b`
|
||||
- `rounds`: `$10` - rounds (log10 of the actual number of rounds)
|
||||
- `salt`: `$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi`
|
||||
- `hash`: `$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4`
|
||||
|
||||
By default, the bcrypt library truncates passwords longer than 72 bytes. In Bun, if you pass `Bun.password.hash` a password longer than 72 bytes and use the `bcrypt` algorithm, the password will be hashed via SHA-512 before being passed to bcrypt.
|
||||
|
||||
```ts
|
||||
await Bun.password.hash("hello".repeat(100), {
|
||||
algorithm: "bcrypt",
|
||||
});
|
||||
```
|
||||
|
||||
So instead of sending bcrypt a 500-byte password silently truncated to 72 bytes, Bun will hash the password using SHA-512 and send the hashed password to bcrypt (only if it exceeds 72 bytes). This is a more secure default behavior.
|
||||
|
||||
### argon2 - PHC format
|
||||
|
||||
In the following [PHC format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) hash (used by `argon2`):
|
||||
|
||||
Input:
|
||||
|
||||
```ts
|
||||
await Bun.password.hash("hello", {
|
||||
algorithm: "argon2id",
|
||||
});
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```sh
|
||||
$argon2id$v=19$m=65536,t=2,p=1$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOs$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI
|
||||
```
|
||||
|
||||
The format is composed of:
|
||||
|
||||
- `algorithm`: `$argon2id`
|
||||
- `version`: `$v=19`
|
||||
- `memory cost`: `65536`
|
||||
- `iterations`: `t=2`
|
||||
- `parallelism`: `p=1`
|
||||
- `salt`: `$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOs`
|
||||
- `hash`: `$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI`
|
||||
|
||||
## `Bun.hash`
|
||||
|
||||
`Bun.hash` is a collection of utilities for _non-cryptographic_ hashing. Non-cryptographic hashing algorithms are optimized for speed of computation over collision-resistance or security.
|
||||
|
||||
The standard `Bun.hash` functions uses [Wyhash](https://github.com/wangyi-fudan/wyhash) to generate a 64-bit hash from an input of arbitrary size.
|
||||
|
||||
```ts
|
||||
Bun.hash("some data here");
|
||||
// 11562320457524636935n
|
||||
```
|
||||
|
||||
The input can be a string, `TypedArray`, `DataView`, `ArrayBuffer`, or `SharedArrayBuffer`.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array([1, 2, 3, 4]);
|
||||
|
||||
Bun.hash("some data here");
|
||||
Bun.hash(arr);
|
||||
Bun.hash(arr.buffer);
|
||||
Bun.hash(new DataView(arr.buffer));
|
||||
```
|
||||
|
||||
Optionally, an integer seed can be specified as the second parameter. For 64-bit hashes seeds above `Number.MAX_SAFE_INTEGER` should be given as BigInt to avoid loss of precision.
|
||||
|
||||
```ts
|
||||
Bun.hash("some data here", 1234);
|
||||
// 15724820720172937558n
|
||||
```
|
||||
|
||||
Additional hashing algorithms are available as properties on `Bun.hash`. The API is the same for each, only changing the return type from number for 32-bit hashes to bigint for 64-bit hashes.
|
||||
|
||||
```ts
|
||||
Bun.hash.wyhash("data", 1234); // equivalent to Bun.hash()
|
||||
Bun.hash.crc32("data", 1234);
|
||||
Bun.hash.adler32("data", 1234);
|
||||
Bun.hash.cityHash32("data", 1234);
|
||||
Bun.hash.cityHash64("data", 1234);
|
||||
Bun.hash.xxHash32("data", 1234);
|
||||
Bun.hash.xxHash64("data", 1234);
|
||||
Bun.hash.xxHash3("data", 1234);
|
||||
Bun.hash.murmur32v3("data", 1234);
|
||||
Bun.hash.murmur32v2("data", 1234);
|
||||
Bun.hash.murmur64v2("data", 1234);
|
||||
Bun.hash.rapidhash("data", 1234);
|
||||
```
|
||||
|
||||
## `Bun.CryptoHasher`
|
||||
|
||||
`Bun.CryptoHasher` is a general-purpose utility class that lets you incrementally compute a hash of string or binary data using a range of cryptographic hash algorithms. The following algorithms are supported:
|
||||
|
||||
- `"blake2b256"`
|
||||
- `"blake2b512"`
|
||||
- `"md4"`
|
||||
- `"md5"`
|
||||
- `"ripemd160"`
|
||||
- `"sha1"`
|
||||
- `"sha224"`
|
||||
- `"sha256"`
|
||||
- `"sha384"`
|
||||
- `"sha512"`
|
||||
- `"sha512-224"`
|
||||
- `"sha512-256"`
|
||||
- `"sha3-224"`
|
||||
- `"sha3-256"`
|
||||
- `"sha3-384"`
|
||||
- `"sha3-512"`
|
||||
- `"shake128"`
|
||||
- `"shake256"`
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256");
|
||||
hasher.update("hello world");
|
||||
hasher.digest();
|
||||
// Uint8Array(32) [ <byte>, <byte>, ... ]
|
||||
```
|
||||
|
||||
Once initialized, data can be incrementally fed to to the hasher using `.update()`. This method accepts `string`, `TypedArray`, and `ArrayBuffer`.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256");
|
||||
|
||||
hasher.update("hello world");
|
||||
hasher.update(new Uint8Array([1, 2, 3]));
|
||||
hasher.update(new ArrayBuffer(10));
|
||||
```
|
||||
|
||||
If a `string` is passed, an optional second parameter can be used to specify the encoding (default `'utf-8'`). The following encodings are supported:
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- Binary encodings
|
||||
- `"base64"` `"base64url"` `"hex"` `"binary"`
|
||||
|
||||
---
|
||||
|
||||
- Character encodings
|
||||
- `"utf8"` `"utf-8"` `"utf16le"` `"latin1"`
|
||||
|
||||
---
|
||||
|
||||
- Legacy character encodings
|
||||
- `"ascii"` `"binary"` `"ucs2"` `"ucs-2"`
|
||||
|
||||
{% /table %}
|
||||
|
||||
```ts
|
||||
hasher.update("hello world"); // defaults to utf8
|
||||
hasher.update("hello world", "hex");
|
||||
hasher.update("hello world", "base64");
|
||||
hasher.update("hello world", "latin1");
|
||||
```
|
||||
|
||||
After the data has been feed into the hasher, a final hash can be computed using `.digest()`. By default, this method returns a `Uint8Array` containing the hash.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256");
|
||||
hasher.update("hello world");
|
||||
|
||||
hasher.digest();
|
||||
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
|
||||
```
|
||||
|
||||
The `.digest()` method can optionally return the hash as a string. To do so, specify an encoding:
|
||||
|
||||
```ts
|
||||
hasher.digest("base64");
|
||||
// => "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="
|
||||
|
||||
hasher.digest("hex");
|
||||
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
||||
```
|
||||
|
||||
Alternatively, the method can write the hash into a pre-existing `TypedArray` instance. This may be desirable in some performance-sensitive applications.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(32);
|
||||
|
||||
hasher.digest(arr);
|
||||
|
||||
console.log(arr);
|
||||
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
|
||||
```
|
||||
|
||||
### HMAC in `Bun.CryptoHasher`
|
||||
|
||||
`Bun.CryptoHasher` can be used to compute HMAC digests. To do so, pass the key to the constructor.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
|
||||
hasher.update("hello world");
|
||||
console.log(hasher.digest("hex"));
|
||||
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
|
||||
```
|
||||
|
||||
When using HMAC, a more limited set of algorithms are supported:
|
||||
|
||||
- `"blake2b512"`
|
||||
- `"md5"`
|
||||
- `"sha1"`
|
||||
- `"sha224"`
|
||||
- `"sha256"`
|
||||
- `"sha384"`
|
||||
- `"sha512-224"`
|
||||
- `"sha512-256"`
|
||||
- `"sha512"`
|
||||
|
||||
Unlike the non-HMAC `Bun.CryptoHasher`, the HMAC `Bun.CryptoHasher` instance is not reset after `.digest()` is called, and attempting to use the same instance again will throw an error.
|
||||
|
||||
Other methods like `.copy()` and `.update()` are supported (as long as it's before `.digest()`), but methods like `.digest()` that finalize the hasher are not.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
|
||||
hasher.update("hello world");
|
||||
|
||||
const copy = hasher.copy();
|
||||
copy.update("!");
|
||||
console.log(copy.digest("hex"));
|
||||
// => "3840176c3d8923f59ac402b7550404b28ab11cb0ef1fa199130a5c37864b5497"
|
||||
|
||||
console.log(hasher.digest("hex"));
|
||||
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
|
||||
```
|
||||
334
node_modules/bun-types/docs/api/html-rewriter.md
generated
vendored
Normal file
334
node_modules/bun-types/docs/api/html-rewriter.md
generated
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
HTMLRewriter lets you use CSS selectors to transform HTML documents. It works with `Request`, `Response`, as well as `string`. Bun's implementation is based on Cloudflare's [lol-html](https://github.com/cloudflare/lol-html).
|
||||
|
||||
## Usage
|
||||
|
||||
A common usecase is rewriting URLs in HTML content. Here's an example that rewrites image sources and link URLs to use a CDN domain:
|
||||
|
||||
```ts
|
||||
// Replace all images with a rickroll
|
||||
const rewriter = new HTMLRewriter().on("img", {
|
||||
element(img) {
|
||||
// Famous rickroll video thumbnail
|
||||
img.setAttribute(
|
||||
"src",
|
||||
"https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
|
||||
);
|
||||
|
||||
// Wrap the image in a link to the video
|
||||
img.before(
|
||||
'<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">',
|
||||
{ html: true },
|
||||
);
|
||||
img.after("</a>", { html: true });
|
||||
|
||||
// Add some fun alt text
|
||||
img.setAttribute("alt", "Definitely not a rickroll");
|
||||
},
|
||||
});
|
||||
|
||||
// An example HTML document
|
||||
const html = `
|
||||
<html>
|
||||
<body>
|
||||
<img src="/cat.jpg">
|
||||
<img src="dog.png">
|
||||
<img src="https://example.com/bird.webp">
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const result = rewriter.transform(html);
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
This replaces all images with a thumbnail of Rick Astley and wraps each `<img>` in a link, producing a diff like this:
|
||||
|
||||
```html-diff
|
||||
<html>
|
||||
<body>
|
||||
- <img src="/cat.jpg">
|
||||
- <img src="dog.png">
|
||||
- <img src="https://example.com/bird.webp">
|
||||
+ <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">
|
||||
+ <img src="https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg" alt="Definitely not a rickroll">
|
||||
+ </a>
|
||||
+ <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">
|
||||
+ <img src="https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg" alt="Definitely not a rickroll">
|
||||
+ </a>
|
||||
+ <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">
|
||||
+ <img src="https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg" alt="Definitely not a rickroll">
|
||||
+ </a>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Now every image on the page will be replaced with a thumbnail of Rick Astley, and clicking any image will lead to [a very famous video](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
|
||||
|
||||
### Input types
|
||||
|
||||
HTMLRewriter can transform HTML from various sources. The input is automatically handled based on its type:
|
||||
|
||||
```ts
|
||||
// From Response
|
||||
rewriter.transform(new Response("<div>content</div>"));
|
||||
|
||||
// From string
|
||||
rewriter.transform("<div>content</div>");
|
||||
|
||||
// From ArrayBuffer
|
||||
rewriter.transform(new TextEncoder().encode("<div>content</div>").buffer);
|
||||
|
||||
// From Blob
|
||||
rewriter.transform(new Blob(["<div>content</div>"]));
|
||||
|
||||
// From File
|
||||
rewriter.transform(Bun.file("index.html"));
|
||||
```
|
||||
|
||||
Note that Cloudflare Workers implementation of HTMLRewriter only supports `Response` objects.
|
||||
|
||||
### Element Handlers
|
||||
|
||||
The `on(selector, handlers)` method allows you to register handlers for HTML elements that match a CSS selector. The handlers are called for each matching element during parsing:
|
||||
|
||||
```ts
|
||||
rewriter.on("div.content", {
|
||||
// Handle elements
|
||||
element(element) {
|
||||
element.setAttribute("class", "new-content");
|
||||
element.append("<p>New content</p>", { html: true });
|
||||
},
|
||||
// Handle text nodes
|
||||
text(text) {
|
||||
text.replace("new text");
|
||||
},
|
||||
// Handle comments
|
||||
comments(comment) {
|
||||
comment.remove();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The handlers can be asynchronous and return a Promise. Note that async operations will block the transformation until they complete:
|
||||
|
||||
```ts
|
||||
rewriter.on("div", {
|
||||
async element(element) {
|
||||
await Bun.sleep(1000);
|
||||
element.setInnerContent("<span>replace</span>", { html: true });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### CSS Selector Support
|
||||
|
||||
The `on()` method supports a wide range of CSS selectors:
|
||||
|
||||
```ts
|
||||
// Tag selectors
|
||||
rewriter.on("p", handler);
|
||||
|
||||
// Class selectors
|
||||
rewriter.on("p.red", handler);
|
||||
|
||||
// ID selectors
|
||||
rewriter.on("h1#header", handler);
|
||||
|
||||
// Attribute selectors
|
||||
rewriter.on("p[data-test]", handler); // Has attribute
|
||||
rewriter.on('p[data-test="one"]', handler); // Exact match
|
||||
rewriter.on('p[data-test="one" i]', handler); // Case-insensitive
|
||||
rewriter.on('p[data-test="one" s]', handler); // Case-sensitive
|
||||
rewriter.on('p[data-test~="two"]', handler); // Word match
|
||||
rewriter.on('p[data-test^="a"]', handler); // Starts with
|
||||
rewriter.on('p[data-test$="1"]', handler); // Ends with
|
||||
rewriter.on('p[data-test*="b"]', handler); // Contains
|
||||
rewriter.on('p[data-test|="a"]', handler); // Dash-separated
|
||||
|
||||
// Combinators
|
||||
rewriter.on("div span", handler); // Descendant
|
||||
rewriter.on("div > span", handler); // Direct child
|
||||
|
||||
// Pseudo-classes
|
||||
rewriter.on("p:nth-child(2)", handler);
|
||||
rewriter.on("p:first-child", handler);
|
||||
rewriter.on("p:nth-of-type(2)", handler);
|
||||
rewriter.on("p:first-of-type", handler);
|
||||
rewriter.on("p:not(:first-child)", handler);
|
||||
|
||||
// Universal selector
|
||||
rewriter.on("*", handler);
|
||||
```
|
||||
|
||||
### Element Operations
|
||||
|
||||
Elements provide various methods for manipulation. All modification methods return the element instance for chaining:
|
||||
|
||||
```ts
|
||||
rewriter.on("div", {
|
||||
element(el) {
|
||||
// Attributes
|
||||
el.setAttribute("class", "new-class").setAttribute("data-id", "123");
|
||||
|
||||
const classAttr = el.getAttribute("class"); // "new-class"
|
||||
const hasId = el.hasAttribute("id"); // boolean
|
||||
el.removeAttribute("class");
|
||||
|
||||
// Content manipulation
|
||||
el.setInnerContent("New content"); // Escapes HTML by default
|
||||
el.setInnerContent("<p>HTML content</p>", { html: true }); // Parses HTML
|
||||
el.setInnerContent(""); // Clear content
|
||||
|
||||
// Position manipulation
|
||||
el.before("Content before")
|
||||
.after("Content after")
|
||||
.prepend("First child")
|
||||
.append("Last child");
|
||||
|
||||
// HTML content insertion
|
||||
el.before("<span>before</span>", { html: true })
|
||||
.after("<span>after</span>", { html: true })
|
||||
.prepend("<span>first</span>", { html: true })
|
||||
.append("<span>last</span>", { html: true });
|
||||
|
||||
// Removal
|
||||
el.remove(); // Remove element and contents
|
||||
el.removeAndKeepContent(); // Remove only the element tags
|
||||
|
||||
// Properties
|
||||
console.log(el.tagName); // Lowercase tag name
|
||||
console.log(el.namespaceURI); // Element's namespace URI
|
||||
console.log(el.selfClosing); // Whether element is self-closing (e.g. <div />)
|
||||
console.log(el.canHaveContent); // Whether element can contain content (false for void elements like <br>)
|
||||
console.log(el.removed); // Whether element was removed
|
||||
|
||||
// Attributes iteration
|
||||
for (const [name, value] of el.attributes) {
|
||||
console.log(name, value);
|
||||
}
|
||||
|
||||
// End tag handling
|
||||
el.onEndTag(endTag => {
|
||||
endTag.before("Before end tag");
|
||||
endTag.after("After end tag");
|
||||
endTag.remove(); // Remove the end tag
|
||||
console.log(endTag.name); // Tag name in lowercase
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Text Operations
|
||||
|
||||
Text handlers provide methods for text manipulation. Text chunks represent portions of text content and provide information about their position in the text node:
|
||||
|
||||
```ts
|
||||
rewriter.on("p", {
|
||||
text(text) {
|
||||
// Content
|
||||
console.log(text.text); // Text content
|
||||
console.log(text.lastInTextNode); // Whether this is the last chunk
|
||||
console.log(text.removed); // Whether text was removed
|
||||
|
||||
// Manipulation
|
||||
text.before("Before text").after("After text").replace("New text").remove();
|
||||
|
||||
// HTML content insertion
|
||||
text
|
||||
.before("<span>before</span>", { html: true })
|
||||
.after("<span>after</span>", { html: true })
|
||||
.replace("<span>replace</span>", { html: true });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Comment Operations
|
||||
|
||||
Comment handlers allow comment manipulation with similar methods to text nodes:
|
||||
|
||||
```ts
|
||||
rewriter.on("*", {
|
||||
comments(comment) {
|
||||
// Content
|
||||
console.log(comment.text); // Comment text
|
||||
comment.text = "New comment text"; // Set comment text
|
||||
console.log(comment.removed); // Whether comment was removed
|
||||
|
||||
// Manipulation
|
||||
comment
|
||||
.before("Before comment")
|
||||
.after("After comment")
|
||||
.replace("New comment")
|
||||
.remove();
|
||||
|
||||
// HTML content insertion
|
||||
comment
|
||||
.before("<span>before</span>", { html: true })
|
||||
.after("<span>after</span>", { html: true })
|
||||
.replace("<span>replace</span>", { html: true });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Document Handlers
|
||||
|
||||
The `onDocument(handlers)` method allows you to handle document-level events. These handlers are called for events that occur at the document level rather than within specific elements:
|
||||
|
||||
```ts
|
||||
rewriter.onDocument({
|
||||
// Handle doctype
|
||||
doctype(doctype) {
|
||||
console.log(doctype.name); // "html"
|
||||
console.log(doctype.publicId); // public identifier if present
|
||||
console.log(doctype.systemId); // system identifier if present
|
||||
},
|
||||
// Handle text nodes
|
||||
text(text) {
|
||||
console.log(text.text);
|
||||
},
|
||||
// Handle comments
|
||||
comments(comment) {
|
||||
console.log(comment.text);
|
||||
},
|
||||
// Handle document end
|
||||
end(end) {
|
||||
end.append("<!-- Footer -->", { html: true });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Response Handling
|
||||
|
||||
When transforming a Response:
|
||||
|
||||
- The status code, headers, and other response properties are preserved
|
||||
- The body is transformed while maintaining streaming capabilities
|
||||
- Content-encoding (like gzip) is handled automatically
|
||||
- The original response body is marked as used after transformation
|
||||
- Headers are cloned to the new response
|
||||
|
||||
## Error Handling
|
||||
|
||||
HTMLRewriter operations can throw errors in several cases:
|
||||
|
||||
- Invalid selector syntax in `on()` method
|
||||
- Invalid HTML content in transformation methods
|
||||
- Stream errors when processing Response bodies
|
||||
- Memory allocation failures
|
||||
- Invalid input types (e.g., passing Symbol)
|
||||
- Body already used errors
|
||||
|
||||
Errors should be caught and handled appropriately:
|
||||
|
||||
```ts
|
||||
try {
|
||||
const result = rewriter.transform(input);
|
||||
// Process result
|
||||
} catch (error) {
|
||||
console.error("HTMLRewriter error:", error);
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
You can also read the [Cloudflare documentation](https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/), which this API is intended to be compatible with.
|
||||
1344
node_modules/bun-types/docs/api/http.md
generated
vendored
Normal file
1344
node_modules/bun-types/docs/api/http.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
node_modules/bun-types/docs/api/import-meta.md
generated
vendored
Normal file
69
node_modules/bun-types/docs/api/import-meta.md
generated
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
The `import.meta` object is a way for a module to access information about itself. It's part of the JavaScript language, but its contents are not standardized. Each "host" (browser, runtime, etc) is free to implement any properties it wishes on the `import.meta` object.
|
||||
|
||||
Bun implements the following properties.
|
||||
|
||||
```ts#/path/to/project/file.ts
|
||||
import.meta.dir; // => "/path/to/project"
|
||||
import.meta.file; // => "file.ts"
|
||||
import.meta.path; // => "/path/to/project/file.ts"
|
||||
import.meta.url; // => "file:///path/to/project/file.ts"
|
||||
|
||||
import.meta.main; // `true` if this file is directly executed by `bun run`
|
||||
// `false` otherwise
|
||||
|
||||
import.meta.resolve("zod"); // => "file:///path/to/project/node_modules/zod/index.js"
|
||||
```
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.dir`
|
||||
- Absolute path to the directory containing the current file, e.g. `/path/to/project`. Equivalent to `__dirname` in CommonJS modules (and Node.js)
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.dirname`
|
||||
- An alias to `import.meta.dir`, for Node.js compatibility
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.env`
|
||||
- An alias to `process.env`.
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.file`
|
||||
- The name of the current file, e.g. `index.tsx`
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.path`
|
||||
- Absolute path to the current file, e.g. `/path/to/project/index.ts`. Equivalent to `__filename` in CommonJS modules (and Node.js)
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.filename`
|
||||
- An alias to `import.meta.path`, for Node.js compatibility
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.main`
|
||||
- Indicates whether the current file is the entrypoint to the current `bun` process. Is the file being directly executed by `bun run` or is it being imported?
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.resolve`
|
||||
- Resolve a module specifier (e.g. `"zod"` or `"./file.tsx"`) to a url. Equivalent to [`import.meta.resolve` in browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#resolve)
|
||||
|
||||
```ts
|
||||
import.meta.resolve("zod");
|
||||
// => "file:///path/to/project/node_modules/zod/index.ts"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
- `import.meta.url`
|
||||
- A `string` url to the current file, e.g. `file:///path/to/project/index.ts`. Equivalent to [`import.meta.url` in browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#url)
|
||||
|
||||
{% /table %}
|
||||
14
node_modules/bun-types/docs/api/node-api.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/api/node-api.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Node-API is an interface for building native add-ons to Node.js. Bun implements 95% of this interface from scratch, so most existing Node-API extensions will work with Bun out of the box. Track the completion status of it in [this issue](https://github.com/oven-sh/bun/issues/158).
|
||||
|
||||
As in Node.js, `.node` files (Node-API modules) can be required directly in Bun.
|
||||
|
||||
```js
|
||||
const napi = require("./my-node-module.node");
|
||||
```
|
||||
|
||||
Alternatively, use `process.dlopen`:
|
||||
|
||||
```js
|
||||
let mod = { exports: {} };
|
||||
process.dlopen(mod, "./my-node-module.node");
|
||||
```
|
||||
492
node_modules/bun-types/docs/api/redis.md
generated
vendored
Normal file
492
node_modules/bun-types/docs/api/redis.md
generated
vendored
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
Bun provides native bindings for working with Redis databases with a modern, Promise-based API. The interface is designed to be simple and performant, with built-in connection management, fully typed responses, and TLS support. **New in Bun v1.2.9**
|
||||
|
||||
```ts
|
||||
import { redis } from "bun";
|
||||
|
||||
// Set a key
|
||||
await redis.set("greeting", "Hello from Bun!");
|
||||
|
||||
// Get a key
|
||||
const greeting = await redis.get("greeting");
|
||||
console.log(greeting); // "Hello from Bun!"
|
||||
|
||||
// Increment a counter
|
||||
await redis.set("counter", 0);
|
||||
await redis.incr("counter");
|
||||
|
||||
// Check if a key exists
|
||||
const exists = await redis.exists("greeting");
|
||||
|
||||
// Delete a key
|
||||
await redis.del("greeting");
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use the Redis client, you first need to create a connection:
|
||||
|
||||
```ts
|
||||
import { redis, RedisClient } from "bun";
|
||||
|
||||
// Using the default client (reads connection info from environment)
|
||||
// process.env.REDIS_URL is used by default
|
||||
await redis.set("hello", "world");
|
||||
const result = await redis.get("hello");
|
||||
|
||||
// Creating a custom client
|
||||
const client = new RedisClient("redis://username:password@localhost:6379");
|
||||
await client.set("counter", "0");
|
||||
await client.incr("counter");
|
||||
```
|
||||
|
||||
By default, the client reads connection information from the following environment variables (in order of precedence):
|
||||
|
||||
- `REDIS_URL`
|
||||
- If not set, defaults to `"redis://localhost:6379"`
|
||||
|
||||
### Connection Lifecycle
|
||||
|
||||
The Redis client automatically handles connections in the background:
|
||||
|
||||
```ts
|
||||
// No connection is made until a command is executed
|
||||
const client = new RedisClient();
|
||||
|
||||
// First command initiates the connection
|
||||
await client.set("key", "value");
|
||||
|
||||
// Connection remains open for subsequent commands
|
||||
await client.get("key");
|
||||
|
||||
// Explicitly close the connection when done
|
||||
client.close();
|
||||
```
|
||||
|
||||
You can also manually control the connection lifecycle:
|
||||
|
||||
```ts
|
||||
const client = new RedisClient();
|
||||
|
||||
// Explicitly connect
|
||||
await client.connect();
|
||||
|
||||
// Run commands
|
||||
await client.set("key", "value");
|
||||
|
||||
// Disconnect when done
|
||||
client.close();
|
||||
```
|
||||
|
||||
## Basic Operations
|
||||
|
||||
### String Operations
|
||||
|
||||
```ts
|
||||
// Set a key
|
||||
await redis.set("user:1:name", "Alice");
|
||||
|
||||
// Get a key
|
||||
const name = await redis.get("user:1:name");
|
||||
|
||||
// Delete a key
|
||||
await redis.del("user:1:name");
|
||||
|
||||
// Check if a key exists
|
||||
const exists = await redis.exists("user:1:name");
|
||||
|
||||
// Set expiration (in seconds)
|
||||
await redis.set("session:123", "active");
|
||||
await redis.expire("session:123", 3600); // expires in 1 hour
|
||||
|
||||
// Get time to live (in seconds)
|
||||
const ttl = await redis.ttl("session:123");
|
||||
```
|
||||
|
||||
### Numeric Operations
|
||||
|
||||
```ts
|
||||
// Set initial value
|
||||
await redis.set("counter", "0");
|
||||
|
||||
// Increment by 1
|
||||
await redis.incr("counter");
|
||||
|
||||
// Decrement by 1
|
||||
await redis.decr("counter");
|
||||
```
|
||||
|
||||
### Hash Operations
|
||||
|
||||
```ts
|
||||
// Set multiple fields in a hash
|
||||
await redis.hmset("user:123", [
|
||||
"name",
|
||||
"Alice",
|
||||
"email",
|
||||
"alice@example.com",
|
||||
"active",
|
||||
"true",
|
||||
]);
|
||||
|
||||
// Get multiple fields from a hash
|
||||
const userFields = await redis.hmget("user:123", ["name", "email"]);
|
||||
console.log(userFields); // ["Alice", "alice@example.com"]
|
||||
|
||||
// Increment a numeric field in a hash
|
||||
await redis.hincrby("user:123", "visits", 1);
|
||||
|
||||
// Increment a float field in a hash
|
||||
await redis.hincrbyfloat("user:123", "score", 1.5);
|
||||
```
|
||||
|
||||
### Set Operations
|
||||
|
||||
```ts
|
||||
// Add member to set
|
||||
await redis.sadd("tags", "javascript");
|
||||
|
||||
// Remove member from set
|
||||
await redis.srem("tags", "javascript");
|
||||
|
||||
// Check if member exists in set
|
||||
const isMember = await redis.sismember("tags", "javascript");
|
||||
|
||||
// Get all members of a set
|
||||
const allTags = await redis.smembers("tags");
|
||||
|
||||
// Get a random member
|
||||
const randomTag = await redis.srandmember("tags");
|
||||
|
||||
// Pop (remove and return) a random member
|
||||
const poppedTag = await redis.spop("tags");
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Command Execution and Pipelining
|
||||
|
||||
The client automatically pipelines commands, improving performance by sending multiple commands in a batch and processing responses as they arrive.
|
||||
|
||||
```ts
|
||||
// Commands are automatically pipelined by default
|
||||
const [infoResult, listResult] = await Promise.all([
|
||||
redis.get("user:1:name"),
|
||||
redis.get("user:2:email"),
|
||||
]);
|
||||
```
|
||||
|
||||
To disable automatic pipelining, you can set the `enableAutoPipelining` option to `false`:
|
||||
|
||||
```ts
|
||||
const client = new RedisClient("redis://localhost:6379", {
|
||||
enableAutoPipelining: false,
|
||||
});
|
||||
```
|
||||
|
||||
### Raw Commands
|
||||
|
||||
When you need to use commands that don't have convenience methods, you can use the `send` method:
|
||||
|
||||
```ts
|
||||
// Run any Redis command
|
||||
const info = await redis.send("INFO", []);
|
||||
|
||||
// LPUSH to a list
|
||||
await redis.send("LPUSH", ["mylist", "value1", "value2"]);
|
||||
|
||||
// Get list range
|
||||
const list = await redis.send("LRANGE", ["mylist", "0", "-1"]);
|
||||
```
|
||||
|
||||
The `send` method allows you to use any Redis command, even ones that don't have dedicated methods in the client. The first argument is the command name, and the second argument is an array of string arguments.
|
||||
|
||||
### Connection Events
|
||||
|
||||
You can register handlers for connection events:
|
||||
|
||||
```ts
|
||||
const client = new RedisClient();
|
||||
|
||||
// Called when successfully connected to Redis server
|
||||
client.onconnect = () => {
|
||||
console.log("Connected to Redis server");
|
||||
};
|
||||
|
||||
// Called when disconnected from Redis server
|
||||
client.onclose = error => {
|
||||
console.error("Disconnected from Redis server:", error);
|
||||
};
|
||||
|
||||
// Manually connect/disconnect
|
||||
await client.connect();
|
||||
client.close();
|
||||
```
|
||||
|
||||
### Connection Status and Monitoring
|
||||
|
||||
```ts
|
||||
// Check if connected
|
||||
console.log(client.connected); // boolean indicating connection status
|
||||
|
||||
// Check amount of data buffered (in bytes)
|
||||
console.log(client.bufferedAmount);
|
||||
```
|
||||
|
||||
### Type Conversion
|
||||
|
||||
The Redis client handles automatic type conversion for Redis responses:
|
||||
|
||||
- Integer responses are returned as JavaScript numbers
|
||||
- Bulk strings are returned as JavaScript strings
|
||||
- Simple strings are returned as JavaScript strings
|
||||
- Null bulk strings are returned as `null`
|
||||
- Array responses are returned as JavaScript arrays
|
||||
- Error responses throw JavaScript errors with appropriate error codes
|
||||
- Boolean responses (RESP3) are returned as JavaScript booleans
|
||||
- Map responses (RESP3) are returned as JavaScript objects
|
||||
- Set responses (RESP3) are returned as JavaScript arrays
|
||||
|
||||
Special handling for specific commands:
|
||||
|
||||
- `EXISTS` returns a boolean instead of a number (1 becomes true, 0 becomes false)
|
||||
- `SISMEMBER` returns a boolean (1 becomes true, 0 becomes false)
|
||||
|
||||
The following commands disable automatic pipelining:
|
||||
|
||||
- `AUTH`
|
||||
- `INFO`
|
||||
- `QUIT`
|
||||
- `EXEC`
|
||||
- `MULTI`
|
||||
- `WATCH`
|
||||
- `SCRIPT`
|
||||
- `SELECT`
|
||||
- `CLUSTER`
|
||||
- `DISCARD`
|
||||
- `UNWATCH`
|
||||
- `PIPELINE`
|
||||
- `SUBSCRIBE`
|
||||
- `UNSUBSCRIBE`
|
||||
- `UNPSUBSCRIBE`
|
||||
|
||||
## Connection Options
|
||||
|
||||
When creating a client, you can pass various options to configure the connection:
|
||||
|
||||
```ts
|
||||
const client = new RedisClient("redis://localhost:6379", {
|
||||
// Connection timeout in milliseconds (default: 10000)
|
||||
connectionTimeout: 5000,
|
||||
|
||||
// Idle timeout in milliseconds (default: 0 = no timeout)
|
||||
idleTimeout: 30000,
|
||||
|
||||
// Whether to automatically reconnect on disconnection (default: true)
|
||||
autoReconnect: true,
|
||||
|
||||
// Maximum number of reconnection attempts (default: 10)
|
||||
maxRetries: 10,
|
||||
|
||||
// Whether to queue commands when disconnected (default: true)
|
||||
enableOfflineQueue: true,
|
||||
|
||||
// Whether to automatically pipeline commands (default: true)
|
||||
enableAutoPipelining: true,
|
||||
|
||||
// TLS options (default: false)
|
||||
tls: true,
|
||||
// Alternatively, provide custom TLS config:
|
||||
// tls: {
|
||||
// rejectUnauthorized: true,
|
||||
// ca: "path/to/ca.pem",
|
||||
// cert: "path/to/cert.pem",
|
||||
// key: "path/to/key.pem",
|
||||
// }
|
||||
});
|
||||
```
|
||||
|
||||
### Reconnection Behavior
|
||||
|
||||
When a connection is lost, the client automatically attempts to reconnect with exponential backoff:
|
||||
|
||||
1. The client starts with a small delay (50ms) and doubles it with each attempt
|
||||
2. Reconnection delay is capped at 2000ms (2 seconds)
|
||||
3. The client attempts to reconnect up to `maxRetries` times (default: 10)
|
||||
4. Commands executed during disconnection are:
|
||||
- Queued if `enableOfflineQueue` is true (default)
|
||||
- Rejected immediately if `enableOfflineQueue` is false
|
||||
|
||||
## Supported URL Formats
|
||||
|
||||
The Redis client supports various URL formats:
|
||||
|
||||
```ts
|
||||
// Standard Redis URL
|
||||
new RedisClient("redis://localhost:6379");
|
||||
new RedisClient("redis://localhost:6379");
|
||||
|
||||
// With authentication
|
||||
new RedisClient("redis://username:password@localhost:6379");
|
||||
|
||||
// With database number
|
||||
new RedisClient("redis://localhost:6379/0");
|
||||
|
||||
// TLS connections
|
||||
new RedisClient("rediss://localhost:6379");
|
||||
new RedisClient("rediss://localhost:6379");
|
||||
new RedisClient("redis+tls://localhost:6379");
|
||||
new RedisClient("redis+tls://localhost:6379");
|
||||
|
||||
// Unix socket connections
|
||||
new RedisClient("redis+unix:///path/to/socket");
|
||||
new RedisClient("redis+unix:///path/to/socket");
|
||||
|
||||
// TLS over Unix socket
|
||||
new RedisClient("redis+tls+unix:///path/to/socket");
|
||||
new RedisClient("redis+tls+unix:///path/to/socket");
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The Redis client throws typed errors for different scenarios:
|
||||
|
||||
```ts
|
||||
try {
|
||||
await redis.get("non-existent-key");
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_REDIS_CONNECTION_CLOSED") {
|
||||
console.error("Connection to Redis server was closed");
|
||||
} else if (error.code === "ERR_REDIS_AUTHENTICATION_FAILED") {
|
||||
console.error("Authentication failed");
|
||||
} else {
|
||||
console.error("Unexpected error:", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Common error codes:
|
||||
|
||||
- `ERR_REDIS_CONNECTION_CLOSED` - Connection to the server was closed
|
||||
- `ERR_REDIS_AUTHENTICATION_FAILED` - Failed to authenticate with the server
|
||||
- `ERR_REDIS_INVALID_RESPONSE` - Received an invalid response from the server
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
### Caching
|
||||
|
||||
```ts
|
||||
async function getUserWithCache(userId) {
|
||||
const cacheKey = `user:${userId}`;
|
||||
|
||||
// Try to get from cache first
|
||||
const cachedUser = await redis.get(cacheKey);
|
||||
if (cachedUser) {
|
||||
return JSON.parse(cachedUser);
|
||||
}
|
||||
|
||||
// Not in cache, fetch from database
|
||||
const user = await database.getUser(userId);
|
||||
|
||||
// Store in cache for 1 hour
|
||||
await redis.set(cacheKey, JSON.stringify(user));
|
||||
await redis.expire(cacheKey, 3600);
|
||||
|
||||
return user;
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```ts
|
||||
async function rateLimit(ip, limit = 100, windowSecs = 3600) {
|
||||
const key = `ratelimit:${ip}`;
|
||||
|
||||
// Increment counter
|
||||
const count = await redis.incr(key);
|
||||
|
||||
// Set expiry if this is the first request in window
|
||||
if (count === 1) {
|
||||
await redis.expire(key, windowSecs);
|
||||
}
|
||||
|
||||
// Check if limit exceeded
|
||||
return {
|
||||
limited: count > limit,
|
||||
remaining: Math.max(0, limit - count),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Session Storage
|
||||
|
||||
```ts
|
||||
async function createSession(userId, data) {
|
||||
const sessionId = crypto.randomUUID();
|
||||
const key = `session:${sessionId}`;
|
||||
|
||||
// Store session with expiration
|
||||
await redis.hmset(key, [
|
||||
"userId",
|
||||
userId.toString(),
|
||||
"created",
|
||||
Date.now().toString(),
|
||||
"data",
|
||||
JSON.stringify(data),
|
||||
]);
|
||||
await redis.expire(key, 86400); // 24 hours
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
async function getSession(sessionId) {
|
||||
const key = `session:${sessionId}`;
|
||||
|
||||
// Get session data
|
||||
const exists = await redis.exists(key);
|
||||
if (!exists) return null;
|
||||
|
||||
const [userId, created, data] = await redis.hmget(key, [
|
||||
"userId",
|
||||
"created",
|
||||
"data",
|
||||
]);
|
||||
|
||||
return {
|
||||
userId: Number(userId),
|
||||
created: Number(created),
|
||||
data: JSON.parse(data),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Bun's Redis client is implemented in Zig and uses the Redis Serialization Protocol (RESP3). It manages connections efficiently and provides automatic reconnection with exponential backoff.
|
||||
|
||||
The client supports pipelining commands, meaning multiple commands can be sent without waiting for the replies to previous commands. This significantly improves performance when sending multiple commands in succession.
|
||||
|
||||
### RESP3 Protocol Support
|
||||
|
||||
Bun's Redis client uses the newer RESP3 protocol by default, which provides more data types and features compared to RESP2:
|
||||
|
||||
- Better error handling with typed errors
|
||||
- Native Boolean responses
|
||||
- Map/Dictionary responses (key-value objects)
|
||||
- Set responses
|
||||
- Double (floating point) values
|
||||
- BigNumber support for large integer values
|
||||
|
||||
When connecting to Redis servers using older versions that don't support RESP3, the client automatically fallbacks to compatible modes.
|
||||
|
||||
## Limitations and Future Plans
|
||||
|
||||
Current limitations of the Redis client we are planning to address in future versions:
|
||||
|
||||
- [ ] No dedicated API for pub/sub functionality (though you can use the raw command API)
|
||||
- [ ] Transactions (MULTI/EXEC) must be done through raw commands for now
|
||||
- [ ] Streams are supported but without dedicated methods
|
||||
|
||||
Unsupported features:
|
||||
|
||||
- Redis Sentinel
|
||||
- Redis Cluster
|
||||
850
node_modules/bun-types/docs/api/s3.md
generated
vendored
Normal file
850
node_modules/bun-types/docs/api/s3.md
generated
vendored
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
Production servers often read, upload, and write files to S3-compatible object storage services instead of the local filesystem. Historically, that means local filesystem APIs you use in development can't be used in production. When you use Bun, things are different.
|
||||
|
||||
{% callout %}
|
||||
|
||||
### Bun's S3 API is fast
|
||||
|
||||
{% image src="https://bun.com/bun-s3-node.gif" alt="Bun's S3 API is fast" caption="Left: Bun v1.1.44. Right: Node.js v23.6.0" /%}
|
||||
|
||||
{% /callout %}
|
||||
|
||||
Bun provides fast, native bindings for interacting with S3-compatible object storage services. Bun's S3 API is designed to be simple and feel similar to fetch's `Response` and `Blob` APIs (like Bun's local filesystem APIs).
|
||||
|
||||
```ts
|
||||
import { s3, write, S3Client } from "bun";
|
||||
|
||||
// Bun.s3 reads environment variables for credentials
|
||||
// file() returns a lazy reference to a file on S3
|
||||
const metadata = s3.file("123.json");
|
||||
|
||||
// Download from S3 as JSON
|
||||
const data = await metadata.json();
|
||||
|
||||
// Upload to S3
|
||||
await write(metadata, JSON.stringify({ name: "John", age: 30 }));
|
||||
|
||||
// Presign a URL (synchronous - no network request needed)
|
||||
const url = metadata.presign({
|
||||
acl: "public-read",
|
||||
expiresIn: 60 * 60 * 24, // 1 day
|
||||
});
|
||||
|
||||
// Delete the file
|
||||
await metadata.delete();
|
||||
```
|
||||
|
||||
S3 is the [de facto standard](https://en.wikipedia.org/wiki/De_facto_standard) internet filesystem. Bun's S3 API works with S3-compatible storage services like:
|
||||
|
||||
- AWS S3
|
||||
- Cloudflare R2
|
||||
- DigitalOcean Spaces
|
||||
- MinIO
|
||||
- Backblaze B2
|
||||
- ...and any other S3-compatible storage service
|
||||
|
||||
## Basic Usage
|
||||
|
||||
There are several ways to interact with Bun's S3 API.
|
||||
|
||||
### `Bun.S3Client` & `Bun.s3`
|
||||
|
||||
`Bun.s3` is equivalent to `new Bun.S3Client()`, relying on environment variables for credentials.
|
||||
|
||||
To explicitly set credentials, pass them to the `Bun.S3Client` constructor.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const client = new S3Client({
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// sessionToken: "..."
|
||||
// acl: "public-read",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
// endpoint: "https://<region>.digitaloceanspaces.com", // DigitalOcean Spaces
|
||||
// endpoint: "http://localhost:9000", // MinIO
|
||||
});
|
||||
|
||||
// Bun.s3 is a global singleton that is equivalent to `new Bun.S3Client()`
|
||||
```
|
||||
|
||||
### Working with S3 Files
|
||||
|
||||
The **`file`** method in `S3Client` returns a **lazy reference to a file on S3**.
|
||||
|
||||
```ts
|
||||
// A lazy reference to a file on S3
|
||||
const s3file: S3File = client.file("123.json");
|
||||
```
|
||||
|
||||
Like `Bun.file(path)`, the `S3Client`'s `file` method is synchronous. It does zero network requests until you call a method that depends on a network request.
|
||||
|
||||
### Reading files from S3
|
||||
|
||||
If you've used the `fetch` API, you're familiar with the `Response` and `Blob` APIs. `S3File` extends `Blob`. The same methods that work on `Blob` also work on `S3File`.
|
||||
|
||||
```ts
|
||||
// Read an S3File as text
|
||||
const text = await s3file.text();
|
||||
|
||||
// Read an S3File as JSON
|
||||
const json = await s3file.json();
|
||||
|
||||
// Read an S3File as an ArrayBuffer
|
||||
const buffer = await s3file.arrayBuffer();
|
||||
|
||||
// Get only the first 1024 bytes
|
||||
const partial = await s3file.slice(0, 1024).text();
|
||||
|
||||
// Stream the file
|
||||
const stream = s3file.stream();
|
||||
for await (const chunk of stream) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
#### Memory optimization
|
||||
|
||||
Methods like `text()`, `json()`, `bytes()`, or `arrayBuffer()` avoid duplicating the string or bytes in memory when possible.
|
||||
|
||||
If the text happens to be ASCII, Bun directly transfers the string to JavaScriptCore (the engine) without transcoding and without duplicating the string in memory. When you use `.bytes()` or `.arrayBuffer()`, it will also avoid duplicating the bytes in memory.
|
||||
|
||||
These helper methods not only simplify the API, they also make it faster.
|
||||
|
||||
### Writing & uploading files to S3
|
||||
|
||||
Writing to S3 is just as simple.
|
||||
|
||||
```ts
|
||||
// Write a string (replacing the file)
|
||||
await s3file.write("Hello World!");
|
||||
|
||||
// Write a Buffer (replacing the file)
|
||||
await s3file.write(Buffer.from("Hello World!"));
|
||||
|
||||
// Write a Response (replacing the file)
|
||||
await s3file.write(new Response("Hello World!"));
|
||||
|
||||
// Write with content type
|
||||
await s3file.write(JSON.stringify({ name: "John", age: 30 }), {
|
||||
type: "application/json",
|
||||
});
|
||||
|
||||
// Write using a writer (streaming)
|
||||
const writer = s3file.writer({ type: "application/json" });
|
||||
writer.write("Hello");
|
||||
writer.write(" World!");
|
||||
await writer.end();
|
||||
|
||||
// Write using Bun.write
|
||||
await Bun.write(s3file, "Hello World!");
|
||||
```
|
||||
|
||||
### Working with large files (streams)
|
||||
|
||||
Bun automatically handles multipart uploads for large files and provides streaming capabilities. The same API that works for local files also works for S3 files.
|
||||
|
||||
```ts
|
||||
// Write a large file
|
||||
const bigFile = Buffer.alloc(10 * 1024 * 1024); // 10MB
|
||||
const writer = s3file.writer({
|
||||
// Automatically retry on network errors up to 3 times
|
||||
retry: 3,
|
||||
|
||||
// Queue up to 10 requests at a time
|
||||
queueSize: 10,
|
||||
|
||||
// Upload in 5 MB chunks
|
||||
partSize: 5 * 1024 * 1024,
|
||||
});
|
||||
for (let i = 0; i < 10; i++) {
|
||||
writer.write(bigFile);
|
||||
await writer.flush();
|
||||
}
|
||||
await writer.end();
|
||||
```
|
||||
|
||||
## Presigning URLs
|
||||
|
||||
When your production service needs to let users upload files to your server, it's often more reliable for the user to upload directly to S3 instead of your server acting as an intermediary.
|
||||
|
||||
To facilitate this, you can presign URLs for S3 files. This generates a URL with a signature that allows a user to securely upload that specific file to S3, without exposing your credentials or granting them unnecessary access to your bucket.
|
||||
|
||||
The default behaviour is to generate a `GET` URL that expires in 24 hours. Bun attempts to infer the content type from the file extension. If inference is not possible, it will default to `application/octet-stream`.
|
||||
|
||||
```ts
|
||||
import { s3 } from "bun";
|
||||
|
||||
// Generate a presigned URL that expires in 24 hours (default)
|
||||
const download = s3.presign("my-file.txt"); // GET, text/plain, expires in 24 hours
|
||||
|
||||
const upload = s3.presign("my-file", {
|
||||
expiresIn: 3600, // 1 hour
|
||||
method: "PUT",
|
||||
type: "application/json", // No extension for inferring, so we can specify the content type to be JSON
|
||||
});
|
||||
|
||||
// You can call .presign() if on a file reference, but avoid doing so
|
||||
// unless you already have a reference (to avoid memory usage).
|
||||
const myFile = s3.file("my-file.txt");
|
||||
const presignedFile = myFile.presign({
|
||||
expiresIn: 3600, // 1 hour
|
||||
});
|
||||
```
|
||||
|
||||
### Setting ACLs
|
||||
|
||||
To set an ACL (access control list) on a presigned URL, pass the `acl` option:
|
||||
|
||||
```ts
|
||||
const url = s3file.presign({
|
||||
acl: "public-read",
|
||||
expiresIn: 3600,
|
||||
});
|
||||
```
|
||||
|
||||
You can pass any of the following ACLs:
|
||||
|
||||
| ACL | Explanation |
|
||||
| ----------------------------- | ------------------------------------------------------------------- |
|
||||
| `"public-read"` | The object is readable by the public. |
|
||||
| `"private"` | The object is readable only by the bucket owner. |
|
||||
| `"public-read-write"` | The object is readable and writable by the public. |
|
||||
| `"authenticated-read"` | The object is readable by the bucket owner and authenticated users. |
|
||||
| `"aws-exec-read"` | The object is readable by the AWS account that made the request. |
|
||||
| `"bucket-owner-read"` | The object is readable by the bucket owner. |
|
||||
| `"bucket-owner-full-control"` | The object is readable and writable by the bucket owner. |
|
||||
| `"log-delivery-write"` | The object is writable by AWS services used for log delivery. |
|
||||
|
||||
### Expiring URLs
|
||||
|
||||
To set an expiration time for a presigned URL, pass the `expiresIn` option.
|
||||
|
||||
```ts
|
||||
const url = s3file.presign({
|
||||
// Seconds
|
||||
expiresIn: 3600, // 1 hour
|
||||
|
||||
// access control list
|
||||
acl: "public-read",
|
||||
|
||||
// HTTP method
|
||||
method: "PUT",
|
||||
});
|
||||
```
|
||||
|
||||
### `method`
|
||||
|
||||
To set the HTTP method for a presigned URL, pass the `method` option.
|
||||
|
||||
```ts
|
||||
const url = s3file.presign({
|
||||
method: "PUT",
|
||||
// method: "DELETE",
|
||||
// method: "GET",
|
||||
// method: "HEAD",
|
||||
// method: "POST",
|
||||
// method: "PUT",
|
||||
});
|
||||
```
|
||||
|
||||
### `new Response(S3File)`
|
||||
|
||||
To quickly redirect users to a presigned URL for an S3 file, pass an `S3File` instance to a `Response` object as the body.
|
||||
|
||||
```ts
|
||||
const response = new Response(s3file);
|
||||
console.log(response);
|
||||
```
|
||||
|
||||
This will automatically redirect the user to the presigned URL for the S3 file, saving you the memory, time, and bandwidth cost of downloading the file to your server and sending it back to the user.
|
||||
|
||||
```ts
|
||||
Response (0 KB) {
|
||||
ok: false,
|
||||
url: "",
|
||||
status: 302,
|
||||
statusText: "",
|
||||
headers: Headers {
|
||||
"location": "https://<account-id>.r2.cloudflarestorage.com/...",
|
||||
},
|
||||
redirected: true,
|
||||
bodyUsed: false
|
||||
}
|
||||
```
|
||||
|
||||
## Support for S3-Compatible Services
|
||||
|
||||
Bun's S3 implementation works with any S3-compatible storage service. Just specify the appropriate endpoint:
|
||||
|
||||
### Using Bun's S3Client with AWS S3
|
||||
|
||||
AWS S3 is the default. You can also pass a `region` option instead of an `endpoint` option for AWS S3.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
// AWS S3
|
||||
const s3 = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// region: "us-east-1",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with Google Cloud Storage
|
||||
|
||||
To use Bun's S3 client with [Google Cloud Storage](https://cloud.google.com/storage), set `endpoint` to `"https://storage.googleapis.com"` in the `S3Client` constructor.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
// Google Cloud Storage
|
||||
const gcs = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
endpoint: "https://storage.googleapis.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with Cloudflare R2
|
||||
|
||||
To use Bun's S3 client with [Cloudflare R2](https://developers.cloudflare.com/r2/), set `endpoint` to the R2 endpoint in the `S3Client` constructor. The R2 endpoint includes your account ID.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
// CloudFlare R2
|
||||
const r2 = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
endpoint: "https://<account-id>.r2.cloudflarestorage.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with DigitalOcean Spaces
|
||||
|
||||
To use Bun's S3 client with [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/), set `endpoint` to the DigitalOcean Spaces endpoint in the `S3Client` constructor.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const spaces = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
// region: "nyc3",
|
||||
endpoint: "https://<region>.digitaloceanspaces.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with MinIO
|
||||
|
||||
To use Bun's S3 client with [MinIO](https://min.io/), set `endpoint` to the URL that MinIO is running on in the `S3Client` constructor.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const minio = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
|
||||
// Make sure to use the correct endpoint URL
|
||||
// It might not be localhost in production!
|
||||
endpoint: "http://localhost:9000",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with supabase
|
||||
|
||||
To use Bun's S3 client with [supabase](https://supabase.com/), set `endpoint` to the supabase endpoint in the `S3Client` constructor. The supabase endpoint includes your account ID and /storage/v1/s3 path. Make sure to set Enable connection via S3 protocol on in the supabase dashboard in https://supabase.com/dashboard/project/<account-id>/settings/storage and to set the region informed in the same section.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const supabase = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
region: "us-west-1",
|
||||
endpoint: "https://<account-id>.supabase.co/storage/v1/s3/storage",
|
||||
});
|
||||
```
|
||||
|
||||
### Using Bun's S3Client with S3 Virtual Hosted-Style endpoints
|
||||
|
||||
When using a S3 Virtual Hosted-Style endpoint, you need to set the `virtualHostedStyle` option to `true` and if no endpoint is provided, Bun will use region and bucket to infer the endpoint to AWS S3, if no region is provided it will use `us-east-1`. If you provide a the endpoint, there are no need to provide the bucket name.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
// AWS S3 endpoint inferred from region and bucket
|
||||
const s3 = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
bucket: "my-bucket",
|
||||
virtualHostedStyle: true,
|
||||
// endpoint: "https://my-bucket.s3.us-east-1.amazonaws.com",
|
||||
// region: "us-east-1",
|
||||
});
|
||||
|
||||
// AWS S3
|
||||
const s3WithEndpoint = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
endpoint: "https://<bucket-name>.s3.<region>.amazonaws.com",
|
||||
virtualHostedStyle: true,
|
||||
});
|
||||
|
||||
// Cloudflare R2
|
||||
const r2WithEndpoint = new S3Client({
|
||||
accessKeyId: "access-key",
|
||||
secretAccessKey: "secret-key",
|
||||
endpoint: "https://<bucket-name>.<account-id>.r2.cloudflarestorage.com",
|
||||
virtualHostedStyle: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
Credentials are one of the hardest parts of using S3, and we've tried to make it as easy as possible. By default, Bun reads the following environment variables for credentials.
|
||||
|
||||
| Option name | Environment variable |
|
||||
| ----------------- | ---------------------- |
|
||||
| `accessKeyId` | `S3_ACCESS_KEY_ID` |
|
||||
| `secretAccessKey` | `S3_SECRET_ACCESS_KEY` |
|
||||
| `region` | `S3_REGION` |
|
||||
| `endpoint` | `S3_ENDPOINT` |
|
||||
| `bucket` | `S3_BUCKET` |
|
||||
| `sessionToken` | `S3_SESSION_TOKEN` |
|
||||
|
||||
If the `S3_*` environment variable is not set, Bun will also check for the `AWS_*` environment variable, for each of the above options.
|
||||
|
||||
| Option name | Fallback environment variable |
|
||||
| ----------------- | ----------------------------- |
|
||||
| `accessKeyId` | `AWS_ACCESS_KEY_ID` |
|
||||
| `secretAccessKey` | `AWS_SECRET_ACCESS_KEY` |
|
||||
| `region` | `AWS_REGION` |
|
||||
| `endpoint` | `AWS_ENDPOINT` |
|
||||
| `bucket` | `AWS_BUCKET` |
|
||||
| `sessionToken` | `AWS_SESSION_TOKEN` |
|
||||
|
||||
These environment variables are read from [`.env` files](/docs/runtime/env) or from the process environment at initialization time (`process.env` is not used for this).
|
||||
|
||||
These defaults are overridden by the options you pass to `s3.file(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3.file()` function without having to specify all the credentials again.
|
||||
|
||||
### `S3Client` objects
|
||||
|
||||
When you're not using environment variables or using multiple buckets, you can create a `S3Client` object to explicitly set credentials.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const client = new S3Client({
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// sessionToken: "..."
|
||||
endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
// endpoint: "http://localhost:9000", // MinIO
|
||||
});
|
||||
|
||||
// Write using a Response
|
||||
await file.write(new Response("Hello World!"));
|
||||
|
||||
// Presign a URL
|
||||
const url = file.presign({
|
||||
expiresIn: 60 * 60 * 24, // 1 day
|
||||
acl: "public-read",
|
||||
});
|
||||
|
||||
// Delete the file
|
||||
await file.delete();
|
||||
```
|
||||
|
||||
### `S3Client.prototype.write`
|
||||
|
||||
To upload or write a file to S3, call `write` on the `S3Client` instance.
|
||||
|
||||
```ts
|
||||
const client = new Bun.S3Client({
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
bucket: "my-bucket",
|
||||
});
|
||||
await client.write("my-file.txt", "Hello World!");
|
||||
await client.write("my-file.txt", new Response("Hello World!"));
|
||||
|
||||
// equivalent to
|
||||
// await client.file("my-file.txt").write("Hello World!");
|
||||
```
|
||||
|
||||
### `S3Client.prototype.delete`
|
||||
|
||||
To delete a file from S3, call `delete` on the `S3Client` instance.
|
||||
|
||||
```ts
|
||||
const client = new Bun.S3Client({
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
});
|
||||
|
||||
await client.delete("my-file.txt");
|
||||
// equivalent to
|
||||
// await client.file("my-file.txt").delete();
|
||||
```
|
||||
|
||||
### `S3Client.prototype.exists`
|
||||
|
||||
To check if a file exists in S3, call `exists` on the `S3Client` instance.
|
||||
|
||||
```ts
|
||||
const client = new Bun.S3Client({
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
});
|
||||
|
||||
const exists = await client.exists("my-file.txt");
|
||||
// equivalent to
|
||||
// const exists = await client.file("my-file.txt").exists();
|
||||
```
|
||||
|
||||
## `S3File`
|
||||
|
||||
`S3File` instances are created by calling the `S3Client` instance method or the `s3.file()` function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous.
|
||||
|
||||
```ts
|
||||
interface S3File extends Blob {
|
||||
slice(start: number, end?: number): S3File;
|
||||
exists(): Promise<boolean>;
|
||||
unlink(): Promise<void>;
|
||||
presign(options: S3Options): string;
|
||||
text(): Promise<string>;
|
||||
json(): Promise<any>;
|
||||
bytes(): Promise<Uint8Array>;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
stream(options: S3Options): ReadableStream;
|
||||
write(
|
||||
data:
|
||||
| string
|
||||
| Uint8Array
|
||||
| ArrayBuffer
|
||||
| Blob
|
||||
| ReadableStream
|
||||
| Response
|
||||
| Request,
|
||||
options?: BlobPropertyBag,
|
||||
): Promise<number>;
|
||||
|
||||
exists(options?: S3Options): Promise<boolean>;
|
||||
unlink(options?: S3Options): Promise<void>;
|
||||
delete(options?: S3Options): Promise<void>;
|
||||
presign(options?: S3Options): string;
|
||||
|
||||
stat(options?: S3Options): Promise<S3Stat>;
|
||||
/**
|
||||
* Size is not synchronously available because it requires a network request.
|
||||
*
|
||||
* @deprecated Use `stat()` instead.
|
||||
*/
|
||||
size: NaN;
|
||||
|
||||
// ... more omitted for brevity
|
||||
}
|
||||
```
|
||||
|
||||
Like `Bun.file()`, `S3File` extends [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob), so all the methods that are available on `Blob` are also available on `S3File`. The same API for reading data from a local file is also available for reading data from S3.
|
||||
|
||||
| Method | Output |
|
||||
| ---------------------------- | ---------------- |
|
||||
| `await s3File.text()` | `string` |
|
||||
| `await s3File.bytes()` | `Uint8Array` |
|
||||
| `await s3File.json()` | `JSON` |
|
||||
| `await s3File.stream()` | `ReadableStream` |
|
||||
| `await s3File.arrayBuffer()` | `ArrayBuffer` |
|
||||
|
||||
That means using `S3File` instances with `fetch()`, `Response`, and other web APIs that accept `Blob` instances just works.
|
||||
|
||||
### Partial reads with `slice`
|
||||
|
||||
To read a partial range of a file, you can use the `slice` method.
|
||||
|
||||
```ts
|
||||
const partial = s3file.slice(0, 1024);
|
||||
|
||||
// Read the partial range as a Uint8Array
|
||||
const bytes = await partial.bytes();
|
||||
|
||||
// Read the partial range as a string
|
||||
const text = await partial.text();
|
||||
```
|
||||
|
||||
Internally, this works by using the HTTP `Range` header to request only the bytes you want. This `slice` method is the same as [`Blob.prototype.slice`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice).
|
||||
|
||||
### Deleting files from S3
|
||||
|
||||
To delete a file from S3, you can use the `delete` method.
|
||||
|
||||
```ts
|
||||
await s3file.delete();
|
||||
// await s3File.unlink();
|
||||
```
|
||||
|
||||
`delete` is the same as `unlink`.
|
||||
|
||||
## Error codes
|
||||
|
||||
When Bun's S3 API throws an error, it will have a `code` property that matches one of the following values:
|
||||
|
||||
- `ERR_S3_MISSING_CREDENTIALS`
|
||||
- `ERR_S3_INVALID_METHOD`
|
||||
- `ERR_S3_INVALID_PATH`
|
||||
- `ERR_S3_INVALID_ENDPOINT`
|
||||
- `ERR_S3_INVALID_SIGNATURE`
|
||||
- `ERR_S3_INVALID_SESSION_TOKEN`
|
||||
|
||||
When the S3 Object Storage service returns an error (that is, not Bun), it will be an `S3Error` instance (an `Error` instance with the name `"S3Error"`).
|
||||
|
||||
## `S3Client` static methods
|
||||
|
||||
The `S3Client` class provides several static methods for interacting with S3.
|
||||
|
||||
### `S3Client.write` (static)
|
||||
|
||||
To write data directly to a path in the bucket, you can use the `S3Client.write` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
// Write string
|
||||
await S3Client.write("my-file.txt", "Hello World");
|
||||
|
||||
// Write JSON with type
|
||||
await S3Client.write("data.json", JSON.stringify({ hello: "world" }), {
|
||||
...credentials,
|
||||
type: "application/json",
|
||||
});
|
||||
|
||||
// Write from fetch
|
||||
const res = await fetch("https://example.com/data");
|
||||
await S3Client.write("data.bin", res, credentials);
|
||||
|
||||
// Write with ACL
|
||||
await S3Client.write("public.html", html, {
|
||||
...credentials,
|
||||
acl: "public-read",
|
||||
type: "text/html",
|
||||
});
|
||||
```
|
||||
|
||||
This is equivalent to calling `new S3Client(credentials).write("my-file.txt", "Hello World")`.
|
||||
|
||||
### `S3Client.presign` (static)
|
||||
|
||||
To generate a presigned URL for an S3 file, you can use the `S3Client.presign` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
const url = S3Client.presign("my-file.txt", {
|
||||
...credentials,
|
||||
expiresIn: 3600,
|
||||
});
|
||||
```
|
||||
|
||||
This is equivalent to calling `new S3Client(credentials).presign("my-file.txt", { expiresIn: 3600 })`.
|
||||
|
||||
### `S3Client.list` (static)
|
||||
|
||||
To list some or all (up to 1,000) objects in a bucket, you can use the `S3Client.list` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
// List (up to) 1000 objects in the bucket
|
||||
const allObjects = await S3Client.list(null, credentials);
|
||||
|
||||
// List (up to) 500 objects under `uploads/` prefix, with owner field for each object
|
||||
const uploads = await S3Client.list({
|
||||
prefix: 'uploads/',
|
||||
maxKeys: 500,
|
||||
fetchOwner: true,
|
||||
}, credentials);
|
||||
|
||||
// Check if more results are available
|
||||
if (uploads.isTruncated) {
|
||||
// List next batch of objects under `uploads/` prefix
|
||||
const moreUploads = await S3Client.list({
|
||||
prefix: 'uploads/',
|
||||
maxKeys: 500,
|
||||
startAfter: uploads.contents!.at(-1).key
|
||||
fetchOwner: true,
|
||||
}, credentials);
|
||||
}
|
||||
```
|
||||
|
||||
This is equivalent to calling `new S3Client(credentials).list()`.
|
||||
|
||||
### `S3Client.exists` (static)
|
||||
|
||||
To check if an S3 file exists, you can use the `S3Client.exists` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
const exists = await S3Client.exists("my-file.txt", credentials);
|
||||
```
|
||||
|
||||
The same method also works on `S3File` instances.
|
||||
|
||||
```ts
|
||||
import { s3 } from "bun";
|
||||
|
||||
const s3file = s3.file("my-file.txt", {
|
||||
...credentials,
|
||||
});
|
||||
const exists = await s3file.exists();
|
||||
```
|
||||
|
||||
### `S3Client.size` (static)
|
||||
|
||||
To quickly check the size of S3 file without downloading it, you can use the `S3Client.size` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
const bytes = await S3Client.size("my-file.txt", credentials);
|
||||
```
|
||||
|
||||
This is equivalent to calling `new S3Client(credentials).size("my-file.txt")`.
|
||||
|
||||
### `S3Client.stat` (static)
|
||||
|
||||
To get the size, etag, and other metadata of an S3 file, you can use the `S3Client.stat` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
// endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
|
||||
};
|
||||
|
||||
const stat = await S3Client.stat("my-file.txt", credentials);
|
||||
// {
|
||||
// etag: "\"7a30b741503c0b461cc14157e2df4ad8\"",
|
||||
// lastModified: 2025-01-07T00:19:10.000Z,
|
||||
// size: 1024,
|
||||
// type: "text/plain;charset=utf-8",
|
||||
// }
|
||||
```
|
||||
|
||||
### `S3Client.delete` (static)
|
||||
|
||||
To delete an S3 file, you can use the `S3Client.delete` static method.
|
||||
|
||||
```ts
|
||||
import { S3Client } from "bun";
|
||||
|
||||
const credentials = {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
bucket: "my-bucket",
|
||||
// endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
};
|
||||
|
||||
await S3Client.delete("my-file.txt", credentials);
|
||||
// equivalent to
|
||||
// await new S3Client(credentials).delete("my-file.txt");
|
||||
|
||||
// S3Client.unlink is alias of S3Client.delete
|
||||
await S3Client.unlink("my-file.txt", credentials);
|
||||
```
|
||||
|
||||
## `s3://` protocol
|
||||
|
||||
To make it easier to use the same code for local files and S3 files, the `s3://` protocol is supported in `fetch` and `Bun.file()`.
|
||||
|
||||
```ts
|
||||
const response = await fetch("s3://my-bucket/my-file.txt");
|
||||
const file = Bun.file("s3://my-bucket/my-file.txt");
|
||||
```
|
||||
|
||||
You can additionally pass `s3` options to the `fetch` and `Bun.file` functions.
|
||||
|
||||
```ts
|
||||
const response = await fetch("s3://my-bucket/my-file.txt", {
|
||||
s3: {
|
||||
accessKeyId: "your-access-key",
|
||||
secretAccessKey: "your-secret-key",
|
||||
endpoint: "https://s3.us-east-1.amazonaws.com",
|
||||
},
|
||||
headers: {
|
||||
"range": "bytes=0-1023",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### UTF-8, UTF-16, and BOM (byte order mark)
|
||||
|
||||
Like `Response` and `Blob`, `S3File` assumes UTF-8 encoding by default.
|
||||
|
||||
When calling one of the `text()` or `json()` methods on an `S3File`:
|
||||
|
||||
- When a UTF-16 byte order mark (BOM) is detected, it will be treated as UTF-16. JavaScriptCore natively supports UTF-16, so it skips the UTF-8 transcoding process (and strips the BOM). This is mostly good, but it does mean if you have invalid surrogate pairs characters in your UTF-16 string, they will be passed through to JavaScriptCore (same as source code).
|
||||
- When a UTF-8 BOM is detected, it gets stripped before the string is passed to JavaScriptCore and invalid UTF-8 codepoints are replaced with the Unicode replacement character (`\uFFFD`).
|
||||
- UTF-32 is not supported.
|
||||
52
node_modules/bun-types/docs/api/semver.md
generated
vendored
Normal file
52
node_modules/bun-types/docs/api/semver.md
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
Bun implements a semantic versioning API which can be used to compare versions and determine if a version is compatible with another range of versions. The versions and ranges are designed to be compatible with `node-semver`, which is used by npm clients.
|
||||
|
||||
It's about 20x faster than `node-semver`.
|
||||
|
||||

|
||||
|
||||
Currently, this API provides two functions :
|
||||
|
||||
#### `Bun.semver.satisfies(version: string, range: string): boolean`
|
||||
|
||||
Returns `true` if `version` satisfies `range`, otherwise `false`.
|
||||
|
||||
Example:
|
||||
|
||||
```typescript
|
||||
import { semver } from "bun";
|
||||
|
||||
semver.satisfies("1.0.0", "^1.0.0"); // true
|
||||
semver.satisfies("1.0.0", "^1.0.1"); // false
|
||||
semver.satisfies("1.0.0", "~1.0.0"); // true
|
||||
semver.satisfies("1.0.0", "~1.0.1"); // false
|
||||
semver.satisfies("1.0.0", "1.0.0"); // true
|
||||
semver.satisfies("1.0.0", "1.0.1"); // false
|
||||
semver.satisfies("1.0.1", "1.0.0"); // false
|
||||
semver.satisfies("1.0.0", "1.0.x"); // true
|
||||
semver.satisfies("1.0.0", "1.x.x"); // true
|
||||
semver.satisfies("1.0.0", "x.x.x"); // true
|
||||
semver.satisfies("1.0.0", "1.0.0 - 2.0.0"); // true
|
||||
semver.satisfies("1.0.0", "1.0.0 - 1.0.1"); // true
|
||||
```
|
||||
|
||||
If `range` is invalid, it returns false. If `version` is invalid, it returns false.
|
||||
|
||||
#### `Bun.semver.order(versionA: string, versionB: string): 0 | 1 | -1`
|
||||
|
||||
Returns `0` if `versionA` and `versionB` are equal, `1` if `versionA` is greater than `versionB`, and `-1` if `versionA` is less than `versionB`.
|
||||
|
||||
Example:
|
||||
|
||||
```typescript
|
||||
import { semver } from "bun";
|
||||
|
||||
semver.order("1.0.0", "1.0.0"); // 0
|
||||
semver.order("1.0.0", "1.0.1"); // -1
|
||||
semver.order("1.0.1", "1.0.0"); // 1
|
||||
|
||||
const unsorted = ["1.0.0", "1.0.1", "1.0.0-alpha", "1.0.0-beta", "1.0.0-rc"];
|
||||
unsorted.sort(semver.order); // ["1.0.0-alpha", "1.0.0-beta", "1.0.0-rc", "1.0.0", "1.0.1"]
|
||||
console.log(unsorted);
|
||||
```
|
||||
|
||||
If you need other semver functions, feel free to open an issue or pull request.
|
||||
582
node_modules/bun-types/docs/api/spawn.md
generated
vendored
Normal file
582
node_modules/bun-types/docs/api/spawn.md
generated
vendored
Normal file
|
|
@ -0,0 +1,582 @@
|
|||
Spawn child processes with `Bun.spawn` or `Bun.spawnSync`.
|
||||
|
||||
## Spawn a process (`Bun.spawn()`)
|
||||
|
||||
Provide a command as an array of strings. The result of `Bun.spawn()` is a `Bun.Subprocess` object.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
console.log(await proc.exited); // 0
|
||||
```
|
||||
|
||||
The second argument to `Bun.spawn` is a parameters object that can be used to configure the subprocess.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"], {
|
||||
cwd: "./path/to/subdir", // specify a working directory
|
||||
env: { ...process.env, FOO: "bar" }, // specify environment variables
|
||||
onExit(proc, exitCode, signalCode, error) {
|
||||
// exit handler
|
||||
},
|
||||
});
|
||||
|
||||
proc.pid; // process ID of subprocess
|
||||
```
|
||||
|
||||
## Input stream
|
||||
|
||||
By default, the input stream of the subprocess is undefined; it can be configured with the `stdin` parameter.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["cat"], {
|
||||
stdin: await fetch(
|
||||
"https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js",
|
||||
),
|
||||
});
|
||||
|
||||
const text = await proc.stdout.text();
|
||||
console.log(text); // "const input = "hello world".repeat(400); ..."
|
||||
```
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- `null`
|
||||
- **Default.** Provide no input to the subprocess
|
||||
|
||||
---
|
||||
|
||||
- `"pipe"`
|
||||
- Return a `FileSink` for fast incremental writing
|
||||
|
||||
---
|
||||
|
||||
- `"inherit"`
|
||||
- Inherit the `stdin` of the parent process
|
||||
|
||||
---
|
||||
|
||||
- `Bun.file()`
|
||||
- Read from the specified file.
|
||||
|
||||
---
|
||||
|
||||
- `TypedArray | DataView`
|
||||
- Use a binary buffer as input.
|
||||
|
||||
---
|
||||
|
||||
- `Response`
|
||||
- Use the response `body` as input.
|
||||
|
||||
---
|
||||
|
||||
- `Request`
|
||||
- Use the request `body` as input.
|
||||
|
||||
---
|
||||
|
||||
- `ReadableStream`
|
||||
- Use a readable stream as input.
|
||||
|
||||
---
|
||||
|
||||
- `Blob`
|
||||
- Use a blob as input.
|
||||
|
||||
---
|
||||
|
||||
- `number`
|
||||
- Read from the file with a given file descriptor.
|
||||
|
||||
{% /table %}
|
||||
|
||||
The `"pipe"` option lets incrementally write to the subprocess's input stream from the parent process.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["cat"], {
|
||||
stdin: "pipe", // return a FileSink for writing
|
||||
});
|
||||
|
||||
// enqueue string data
|
||||
proc.stdin.write("hello");
|
||||
|
||||
// enqueue binary data
|
||||
const enc = new TextEncoder();
|
||||
proc.stdin.write(enc.encode(" world!"));
|
||||
|
||||
// send buffered data
|
||||
proc.stdin.flush();
|
||||
|
||||
// close the input stream
|
||||
proc.stdin.end();
|
||||
```
|
||||
|
||||
Passing a `ReadableStream` to `stdin` lets you pipe data from a JavaScript `ReadableStream` directly to the subprocess's input:
|
||||
|
||||
```ts
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("Hello from ");
|
||||
controller.enqueue("ReadableStream!");
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
|
||||
const proc = Bun.spawn(["cat"], {
|
||||
stdin: stream,
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const output = await new Response(proc.stdout).text();
|
||||
console.log(output); // "Hello from ReadableStream!"
|
||||
```
|
||||
|
||||
## Output streams
|
||||
|
||||
You can read results from the subprocess via the `stdout` and `stderr` properties. By default these are instances of `ReadableStream`.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
const text = await proc.stdout.text();
|
||||
console.log(text); // => "1.2.19\n"
|
||||
```
|
||||
|
||||
Configure the output stream by passing one of the following values to `stdout/stderr`:
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- `"pipe"`
|
||||
- **Default for `stdout`.** Pipe the output to a `ReadableStream` on the returned `Subprocess` object.
|
||||
|
||||
---
|
||||
|
||||
- `"inherit"`
|
||||
- **Default for `stderr`.** Inherit from the parent process.
|
||||
|
||||
---
|
||||
|
||||
- `"ignore"`
|
||||
- Discard the output.
|
||||
|
||||
---
|
||||
|
||||
- `Bun.file()`
|
||||
- Write to the specified file.
|
||||
|
||||
---
|
||||
|
||||
- `number`
|
||||
- Write to the file with the given file descriptor.
|
||||
|
||||
{% /table %}
|
||||
|
||||
## Exit handling
|
||||
|
||||
Use the `onExit` callback to listen for the process exiting or being killed.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"], {
|
||||
onExit(proc, exitCode, signalCode, error) {
|
||||
// exit handler
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
For convenience, the `exited` property is a `Promise` that resolves when the process exits.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
|
||||
await proc.exited; // resolves when process exit
|
||||
proc.killed; // boolean — was the process killed?
|
||||
proc.exitCode; // null | number
|
||||
proc.signalCode; // null | "SIGABRT" | "SIGALRM" | ...
|
||||
```
|
||||
|
||||
To kill a process:
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
proc.kill();
|
||||
proc.killed; // true
|
||||
|
||||
proc.kill(15); // specify a signal code
|
||||
proc.kill("SIGTERM"); // specify a signal name
|
||||
```
|
||||
|
||||
The parent `bun` process will not terminate until all child processes have exited. Use `proc.unref()` to detach the child process from the parent.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
proc.unref();
|
||||
```
|
||||
|
||||
## Resource usage
|
||||
|
||||
You can get information about the process's resource usage after it has exited:
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["bun", "--version"]);
|
||||
await proc.exited;
|
||||
|
||||
const usage = proc.resourceUsage();
|
||||
console.log(`Max memory used: ${usage.maxRSS} bytes`);
|
||||
console.log(`CPU time (user): ${usage.cpuTime.user} µs`);
|
||||
console.log(`CPU time (system): ${usage.cpuTime.system} µs`);
|
||||
```
|
||||
|
||||
## Using AbortSignal
|
||||
|
||||
You can abort a subprocess using an `AbortSignal`:
|
||||
|
||||
```ts
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
|
||||
const proc = Bun.spawn({
|
||||
cmd: ["sleep", "100"],
|
||||
signal,
|
||||
});
|
||||
|
||||
// Later, to abort the process:
|
||||
controller.abort();
|
||||
```
|
||||
|
||||
## Using timeout and killSignal
|
||||
|
||||
You can set a timeout for a subprocess to automatically terminate after a specific duration:
|
||||
|
||||
```ts
|
||||
// Kill the process after 5 seconds
|
||||
const proc = Bun.spawn({
|
||||
cmd: ["sleep", "10"],
|
||||
timeout: 5000, // 5 seconds in milliseconds
|
||||
});
|
||||
|
||||
await proc.exited; // Will resolve after 5 seconds
|
||||
```
|
||||
|
||||
By default, timed-out processes are killed with the `SIGTERM` signal. You can specify a different signal with the `killSignal` option:
|
||||
|
||||
```ts
|
||||
// Kill the process with SIGKILL after 5 seconds
|
||||
const proc = Bun.spawn({
|
||||
cmd: ["sleep", "10"],
|
||||
timeout: 5000,
|
||||
killSignal: "SIGKILL", // Can be string name or signal number
|
||||
});
|
||||
```
|
||||
|
||||
The `killSignal` option also controls which signal is sent when an AbortSignal is aborted.
|
||||
|
||||
## Using maxBuffer
|
||||
|
||||
For spawnSync, you can limit the maximum number of bytes of output before the process is killed:
|
||||
|
||||
```ts
|
||||
// KIll 'yes' after it emits over 100 bytes of output
|
||||
const result = Bun.spawnSync({
|
||||
cmd: ["yes"], // or ["bun", "exec", "yes"] on windows
|
||||
maxBuffer: 100,
|
||||
});
|
||||
// process exits
|
||||
```
|
||||
|
||||
## Inter-process communication (IPC)
|
||||
|
||||
Bun supports direct inter-process communication channel between two `bun` processes. To receive messages from a spawned Bun subprocess, specify an `ipc` handler.
|
||||
|
||||
```ts#parent.ts
|
||||
const child = Bun.spawn(["bun", "child.ts"], {
|
||||
ipc(message) {
|
||||
/**
|
||||
* The message received from the sub process
|
||||
**/
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The parent process can send messages to the subprocess using the `.send()` method on the returned `Subprocess` instance. A reference to the sending subprocess is also available as the second argument in the `ipc` handler.
|
||||
|
||||
```ts#parent.ts
|
||||
const childProc = Bun.spawn(["bun", "child.ts"], {
|
||||
ipc(message, childProc) {
|
||||
/**
|
||||
* The message received from the sub process
|
||||
**/
|
||||
childProc.send("Respond to child")
|
||||
},
|
||||
});
|
||||
|
||||
childProc.send("I am your father"); // The parent can send messages to the child as well
|
||||
```
|
||||
|
||||
Meanwhile the child process can send messages to its parent using with `process.send()` and receive messages with `process.on("message")`. This is the same API used for `child_process.fork()` in Node.js.
|
||||
|
||||
```ts#child.ts
|
||||
process.send("Hello from child as string");
|
||||
process.send({ message: "Hello from child as object" });
|
||||
|
||||
process.on("message", (message) => {
|
||||
// print message from parent
|
||||
console.log(message);
|
||||
});
|
||||
```
|
||||
|
||||
```ts#child.ts
|
||||
// send a string
|
||||
process.send("Hello from child as string");
|
||||
|
||||
// send an object
|
||||
process.send({ message: "Hello from child as object" });
|
||||
```
|
||||
|
||||
The `serialization` option controls the underlying communication format between the two processes:
|
||||
|
||||
- `advanced`: (default) Messages are serialized using the JSC `serialize` API, which supports cloning [everything `structuredClone` supports](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). This does not support transferring ownership of objects.
|
||||
- `json`: Messages are serialized using `JSON.stringify` and `JSON.parse`, which does not support as many object types as `advanced` does.
|
||||
|
||||
To disconnect the IPC channel from the parent process, call:
|
||||
|
||||
```ts
|
||||
childProc.disconnect();
|
||||
```
|
||||
|
||||
### IPC between Bun & Node.js
|
||||
|
||||
To use IPC between a `bun` process and a Node.js process, set `serialization: "json"` in `Bun.spawn`. This is because Node.js and Bun use different JavaScript engines with different object serialization formats.
|
||||
|
||||
```js#bun-node-ipc.js
|
||||
if (typeof Bun !== "undefined") {
|
||||
const prefix = `[bun ${process.versions.bun} 🐇]`;
|
||||
const node = Bun.spawn({
|
||||
cmd: ["node", __filename],
|
||||
ipc({ message }) {
|
||||
console.log(message);
|
||||
node.send({ message: `${prefix} 👋 hey node` });
|
||||
node.kill();
|
||||
},
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
serialization: "json",
|
||||
});
|
||||
|
||||
node.send({ message: `${prefix} 👋 hey node` });
|
||||
} else {
|
||||
const prefix = `[node ${process.version}]`;
|
||||
process.on("message", ({ message }) => {
|
||||
console.log(message);
|
||||
process.send({ message: `${prefix} 👋 hey bun` });
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Blocking API (`Bun.spawnSync()`)
|
||||
|
||||
Bun provides a synchronous equivalent of `Bun.spawn` called `Bun.spawnSync`. This is a blocking API that supports the same inputs and parameters as `Bun.spawn`. It returns a `SyncSubprocess` object, which differs from `Subprocess` in a few ways.
|
||||
|
||||
1. It contains a `success` property that indicates whether the process exited with a zero exit code.
|
||||
2. The `stdout` and `stderr` properties are instances of `Buffer` instead of `ReadableStream`.
|
||||
3. There is no `stdin` property. Use `Bun.spawn` to incrementally write to the subprocess's input stream.
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawnSync(["echo", "hello"]);
|
||||
|
||||
console.log(proc.stdout.toString());
|
||||
// => "hello\n"
|
||||
```
|
||||
|
||||
As a rule of thumb, the asynchronous `Bun.spawn` API is better for HTTP servers and apps, and `Bun.spawnSync` is better for building command-line tools.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
{%callout%}
|
||||
⚡️ Under the hood, `Bun.spawn` and `Bun.spawnSync` use [`posix_spawn(3)`](https://man7.org/linux/man-pages/man3/posix_spawn.3.html).
|
||||
{%/callout%}
|
||||
|
||||
Bun's `spawnSync` spawns processes 60% faster than the Node.js `child_process` module.
|
||||
|
||||
```bash
|
||||
$ bun spawn.mjs
|
||||
cpu: Apple M1 Max
|
||||
runtime: bun 1.x (arm64-darwin)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
--------------------------------------------------------- -----------------------------
|
||||
spawnSync echo hi 888.14 µs/iter (821.83 µs … 1.2 ms) 905.92 µs 1 ms 1.03 ms
|
||||
$ node spawn.node.mjs
|
||||
cpu: Apple M1 Max
|
||||
runtime: node v18.9.1 (arm64-darwin)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
--------------------------------------------------------- -----------------------------
|
||||
spawnSync echo hi 1.47 ms/iter (1.14 ms … 2.64 ms) 1.57 ms 2.37 ms 2.52 ms
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
A reference of the Spawn API and types are shown below. The real types have complex generics to strongly type the `Subprocess` streams with the options passed to `Bun.spawn` and `Bun.spawnSync`. For full details, find these types as defined [bun.d.ts](https://github.com/oven-sh/bun/blob/main/packages/bun-types/bun.d.ts).
|
||||
|
||||
```ts
|
||||
interface Bun {
|
||||
spawn(command: string[], options?: SpawnOptions.OptionsObject): Subprocess;
|
||||
spawnSync(
|
||||
command: string[],
|
||||
options?: SpawnOptions.OptionsObject,
|
||||
): SyncSubprocess;
|
||||
|
||||
spawn(options: { cmd: string[] } & SpawnOptions.OptionsObject): Subprocess;
|
||||
spawnSync(
|
||||
options: { cmd: string[] } & SpawnOptions.OptionsObject,
|
||||
): SyncSubprocess;
|
||||
}
|
||||
|
||||
namespace SpawnOptions {
|
||||
interface OptionsObject {
|
||||
cwd?: string;
|
||||
env?: Record<string, string | undefined>;
|
||||
stdio?: [Writable, Readable, Readable];
|
||||
stdin?: Writable;
|
||||
stdout?: Readable;
|
||||
stderr?: Readable;
|
||||
onExit?(
|
||||
subprocess: Subprocess,
|
||||
exitCode: number | null,
|
||||
signalCode: number | null,
|
||||
error?: ErrorLike,
|
||||
): void | Promise<void>;
|
||||
ipc?(message: any, subprocess: Subprocess): void;
|
||||
serialization?: "json" | "advanced";
|
||||
windowsHide?: boolean;
|
||||
windowsVerbatimArguments?: boolean;
|
||||
argv0?: string;
|
||||
signal?: AbortSignal;
|
||||
timeout?: number;
|
||||
killSignal?: string | number;
|
||||
maxBuffer?: number;
|
||||
}
|
||||
|
||||
type Readable =
|
||||
| "pipe"
|
||||
| "inherit"
|
||||
| "ignore"
|
||||
| null // equivalent to "ignore"
|
||||
| undefined // to use default
|
||||
| BunFile
|
||||
| ArrayBufferView
|
||||
| number;
|
||||
|
||||
type Writable =
|
||||
| "pipe"
|
||||
| "inherit"
|
||||
| "ignore"
|
||||
| null // equivalent to "ignore"
|
||||
| undefined // to use default
|
||||
| BunFile
|
||||
| ArrayBufferView
|
||||
| number
|
||||
| ReadableStream
|
||||
| Blob
|
||||
| Response
|
||||
| Request;
|
||||
}
|
||||
|
||||
interface Subprocess extends AsyncDisposable {
|
||||
readonly stdin: FileSink | number | undefined;
|
||||
readonly stdout: ReadableStream<Uint8Array> | number | undefined;
|
||||
readonly stderr: ReadableStream<Uint8Array> | number | undefined;
|
||||
readonly readable: ReadableStream<Uint8Array> | number | undefined;
|
||||
readonly pid: number;
|
||||
readonly exited: Promise<number>;
|
||||
readonly exitCode: number | null;
|
||||
readonly signalCode: NodeJS.Signals | null;
|
||||
readonly killed: boolean;
|
||||
|
||||
kill(exitCode?: number | NodeJS.Signals): void;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
|
||||
send(message: any): void;
|
||||
disconnect(): void;
|
||||
resourceUsage(): ResourceUsage | undefined;
|
||||
}
|
||||
|
||||
interface SyncSubprocess {
|
||||
stdout: Buffer | undefined;
|
||||
stderr: Buffer | undefined;
|
||||
exitCode: number;
|
||||
success: boolean;
|
||||
resourceUsage: ResourceUsage;
|
||||
signalCode?: string;
|
||||
exitedDueToTimeout?: true;
|
||||
pid: number;
|
||||
}
|
||||
|
||||
interface ResourceUsage {
|
||||
contextSwitches: {
|
||||
voluntary: number;
|
||||
involuntary: number;
|
||||
};
|
||||
|
||||
cpuTime: {
|
||||
user: number;
|
||||
system: number;
|
||||
total: number;
|
||||
};
|
||||
maxRSS: number;
|
||||
|
||||
messages: {
|
||||
sent: number;
|
||||
received: number;
|
||||
};
|
||||
ops: {
|
||||
in: number;
|
||||
out: number;
|
||||
};
|
||||
shmSize: number;
|
||||
signalCount: number;
|
||||
swapCount: number;
|
||||
}
|
||||
|
||||
type Signal =
|
||||
| "SIGABRT"
|
||||
| "SIGALRM"
|
||||
| "SIGBUS"
|
||||
| "SIGCHLD"
|
||||
| "SIGCONT"
|
||||
| "SIGFPE"
|
||||
| "SIGHUP"
|
||||
| "SIGILL"
|
||||
| "SIGINT"
|
||||
| "SIGIO"
|
||||
| "SIGIOT"
|
||||
| "SIGKILL"
|
||||
| "SIGPIPE"
|
||||
| "SIGPOLL"
|
||||
| "SIGPROF"
|
||||
| "SIGPWR"
|
||||
| "SIGQUIT"
|
||||
| "SIGSEGV"
|
||||
| "SIGSTKFLT"
|
||||
| "SIGSTOP"
|
||||
| "SIGSYS"
|
||||
| "SIGTERM"
|
||||
| "SIGTRAP"
|
||||
| "SIGTSTP"
|
||||
| "SIGTTIN"
|
||||
| "SIGTTOU"
|
||||
| "SIGUNUSED"
|
||||
| "SIGURG"
|
||||
| "SIGUSR1"
|
||||
| "SIGUSR2"
|
||||
| "SIGVTALRM"
|
||||
| "SIGWINCH"
|
||||
| "SIGXCPU"
|
||||
| "SIGXFSZ"
|
||||
| "SIGBREAK"
|
||||
| "SIGLOST"
|
||||
| "SIGINFO";
|
||||
```
|
||||
691
node_modules/bun-types/docs/api/sql.md
generated
vendored
Normal file
691
node_modules/bun-types/docs/api/sql.md
generated
vendored
Normal file
|
|
@ -0,0 +1,691 @@
|
|||
Bun provides native bindings for working with PostgreSQL databases with a modern, Promise-based API. The interface is designed to be simple and performant, using tagged template literals for queries and offering features like connection pooling, transactions, and prepared statements.
|
||||
|
||||
```ts
|
||||
import { sql } from "bun";
|
||||
|
||||
const users = await sql`
|
||||
SELECT * FROM users
|
||||
WHERE active = ${true}
|
||||
LIMIT ${10}
|
||||
`;
|
||||
|
||||
// Select with multiple conditions
|
||||
const activeUsers = await sql`
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE active = ${true}
|
||||
AND age >= ${18}
|
||||
`;
|
||||
```
|
||||
|
||||
{% features title="Features" %}
|
||||
|
||||
{% icon size=20 name="Shield" /%} Tagged template literals to protect against SQL injection
|
||||
|
||||
{% icon size=20 name="GitMerge" /%} Transactions
|
||||
|
||||
{% icon size=20 name="Variable" /%} Named & positional parameters
|
||||
|
||||
{% icon size=20 name="Network" /%} Connection pooling
|
||||
|
||||
{% icon size=20 name="Binary" /%} `BigInt` support
|
||||
|
||||
{% icon size=20 name="Key" /%} SASL Auth support (SCRAM-SHA-256), MD5, and Clear Text
|
||||
|
||||
{% icon size=20 name="Timer" /%} Connection timeouts
|
||||
|
||||
{% icon size=20 name="Database" /%} Returning rows as data objects, arrays of arrays, or `Buffer`
|
||||
|
||||
{% icon size=20 name="Code" /%} Binary protocol support makes it faster
|
||||
|
||||
{% icon size=20 name="Lock" /%} TLS support (and auth mode)
|
||||
|
||||
{% icon size=20 name="Settings" /%} Automatic configuration with environment variable
|
||||
|
||||
{% /features %}
|
||||
|
||||
### Inserting data
|
||||
|
||||
You can pass JavaScript values directly to the SQL template literal and escaping will be handled for you.
|
||||
|
||||
```ts
|
||||
import { sql } from "bun";
|
||||
|
||||
// Basic insert with direct values
|
||||
const [user] = await sql`
|
||||
INSERT INTO users (name, email)
|
||||
VALUES (${name}, ${email})
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
// Using object helper for cleaner syntax
|
||||
const userData = {
|
||||
name: "Alice",
|
||||
email: "alice@example.com",
|
||||
};
|
||||
|
||||
const [newUser] = await sql`
|
||||
INSERT INTO users ${sql(userData)}
|
||||
RETURNING *
|
||||
`;
|
||||
// Expands to: INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')
|
||||
```
|
||||
|
||||
### Bulk Insert
|
||||
|
||||
You can also pass arrays of objects to the SQL template literal and it will be expanded to a `INSERT INTO ... VALUES ...` statement.
|
||||
|
||||
```ts
|
||||
const users = [
|
||||
{ name: "Alice", email: "alice@example.com" },
|
||||
{ name: "Bob", email: "bob@example.com" },
|
||||
{ name: "Charlie", email: "charlie@example.com" },
|
||||
];
|
||||
|
||||
await sql`INSERT INTO users ${sql(users)}`;
|
||||
```
|
||||
|
||||
### Picking columns to insert
|
||||
|
||||
You can use `sql(object, ...string)` to pick which columns to insert. Each of the columns must be defined on the object.
|
||||
|
||||
```ts
|
||||
const user = {
|
||||
name: "Alice",
|
||||
email: "alice@example.com",
|
||||
age: 25,
|
||||
};
|
||||
|
||||
await sql`INSERT INTO users ${sql(user, "name", "email")}`;
|
||||
// Only inserts name and email columns, ignoring other fields
|
||||
```
|
||||
|
||||
## Query Results
|
||||
|
||||
By default, Bun's SQL client returns query results as arrays of objects, where each object represents a row with column names as keys. However, there are cases where you might want the data in a different format. The client provides two additional methods for this purpose.
|
||||
|
||||
### `sql``.values()` format
|
||||
|
||||
The `sql``.values()` method returns rows as arrays of values rather than objects. Each row becomes an array where the values are in the same order as the columns in your query.
|
||||
|
||||
```ts
|
||||
const rows = await sql`SELECT * FROM users`.values();
|
||||
console.log(rows);
|
||||
```
|
||||
|
||||
This returns something like:
|
||||
|
||||
```ts
|
||||
[
|
||||
["Alice", "alice@example.com"],
|
||||
["Bob", "bob@example.com"],
|
||||
];
|
||||
```
|
||||
|
||||
`sql``.values()` is especially useful if duplicate column names are returned in the query results. When using objects (the default), the last column name is used as the key in the object, which means duplicate column names overwrite each other — but when using `sql``.values()`, each column is present in the array so you can access the values of duplicate columns by index.
|
||||
|
||||
### `sql``.raw()` format
|
||||
|
||||
The `.raw()` method returns rows as arrays of `Buffer` objects. This can be useful for working with binary data or for performance reasons.
|
||||
|
||||
```ts
|
||||
const rows = await sql`SELECT * FROM users`.raw();
|
||||
console.log(rows); // [[Buffer, Buffer], [Buffer, Buffer], [Buffer, Buffer]]
|
||||
```
|
||||
|
||||
## SQL Fragments
|
||||
|
||||
A common need in database applications is the ability to construct queries dynamically based on runtime conditions. Bun provides safe ways to do this without risking SQL injection.
|
||||
|
||||
### Dynamic Table Names
|
||||
|
||||
When you need to reference tables or schemas dynamically, use the `sql()` helper to ensure proper escaping:
|
||||
|
||||
```ts
|
||||
// Safely reference tables dynamically
|
||||
await sql`SELECT * FROM ${sql("users")}`;
|
||||
|
||||
// With schema qualification
|
||||
await sql`SELECT * FROM ${sql("public.users")}`;
|
||||
```
|
||||
|
||||
### Conditional Queries
|
||||
|
||||
You can use the `sql()` helper to build queries with conditional clauses. This allows you to create flexible queries that adapt to your application's needs:
|
||||
|
||||
```ts
|
||||
// Optional WHERE clauses
|
||||
const filterAge = true;
|
||||
const minAge = 21;
|
||||
const ageFilter = sql`AND age > ${minAge}`;
|
||||
await sql`
|
||||
SELECT * FROM users
|
||||
WHERE active = ${true}
|
||||
${filterAge ? ageFilter : sql``}
|
||||
`;
|
||||
```
|
||||
|
||||
### Dynamic columns in updates
|
||||
|
||||
You can use `sql(object, ...string)` to pick which columns to update. Each of the columns must be defined on the object. If the columns are not informed all keys will be used to update the row.
|
||||
|
||||
```ts
|
||||
await sql`UPDATE users SET ${sql(user, "name", "email")} WHERE id = ${user.id}`;
|
||||
// uses all keys from the object to update the row
|
||||
await sql`UPDATE users SET ${sql(user)} WHERE id = ${user.id}`;
|
||||
```
|
||||
|
||||
### Dynamic values and `where in`
|
||||
|
||||
Value lists can also be created dynamically, making where in queries simple too. Optionally you can pass a array of objects and inform what key to use to create the list.
|
||||
|
||||
```ts
|
||||
await sql`SELECT * FROM users WHERE id IN ${sql([1, 2, 3])}`;
|
||||
|
||||
const users = [
|
||||
{ id: 1, name: "Alice" },
|
||||
{ id: 2, name: "Bob" },
|
||||
{ id: 3, name: "Charlie" },
|
||||
];
|
||||
await sql`SELECT * FROM users WHERE id IN ${sql(users, "id")}`;
|
||||
```
|
||||
|
||||
## `sql``.simple()`
|
||||
|
||||
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.
|
||||
|
||||
To run multiple statements in a single query, use `sql``.simple()`:
|
||||
|
||||
```ts
|
||||
// Multiple statements in one query
|
||||
await sql`
|
||||
SELECT 1;
|
||||
SELECT 2;
|
||||
`.simple();
|
||||
```
|
||||
|
||||
Simple queries are often useful for database migrations and setup scripts.
|
||||
|
||||
Note that simple queries cannot use parameters (`${value}`). If you need parameters, you must split your query into separate statements.
|
||||
|
||||
### Queries in files
|
||||
|
||||
You can use the `sql.file` method to read a query from a file and execute it, if the file includes $1, $2, etc you can pass parameters to the query. If no parameters are used it can execute multiple commands per file.
|
||||
|
||||
```ts
|
||||
const result = await sql.file("query.sql", [1, 2, 3]);
|
||||
```
|
||||
|
||||
### Unsafe Queries
|
||||
|
||||
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.
|
||||
|
||||
```ts
|
||||
// Multiple commands without parameters
|
||||
const result = await sql.unsafe(`
|
||||
SELECT ${userColumns} FROM users;
|
||||
SELECT ${accountColumns} FROM accounts;
|
||||
`);
|
||||
|
||||
// Using parameters (only one command is allowed)
|
||||
const result = await sql.unsafe(
|
||||
"SELECT " + dangerous + " FROM users WHERE id = $1",
|
||||
[id],
|
||||
);
|
||||
```
|
||||
|
||||
#### What is SQL Injection?
|
||||
|
||||
{% image href="https://xkcd.com/327/" src="https://imgs.xkcd.com/comics/exploits_of_a_mom.png" /%}
|
||||
|
||||
### Execute and Cancelling Queries
|
||||
|
||||
Bun's SQL is lazy, which means it will only start executing when awaited or executed with `.execute()`.
|
||||
You can cancel a query that is currently executing by calling the `cancel()` method on the query object.
|
||||
|
||||
```ts
|
||||
const query = await sql`SELECT * FROM users`.execute();
|
||||
setTimeout(() => query.cancel(), 100);
|
||||
await query;
|
||||
```
|
||||
|
||||
## Database Environment Variables
|
||||
|
||||
`sql` connection parameters can be configured using environment variables. The client checks these variables in a specific order of precedence.
|
||||
|
||||
The following environment variables can be used to define the connection URL:
|
||||
|
||||
| Environment Variable | Description |
|
||||
| --------------------------- | ------------------------------------------ |
|
||||
| `POSTGRES_URL` | Primary connection URL for PostgreSQL |
|
||||
| `DATABASE_URL` | Alternative connection URL |
|
||||
| `PGURL` | Alternative connection URL |
|
||||
| `PG_URL` | Alternative connection URL |
|
||||
| `TLS_POSTGRES_DATABASE_URL` | SSL/TLS-enabled connection URL |
|
||||
| `TLS_DATABASE_URL` | Alternative SSL/TLS-enabled connection URL |
|
||||
|
||||
If no connection URL is provided, the system checks for the following individual parameters:
|
||||
|
||||
| Environment Variable | Fallback Variables | Default Value | Description |
|
||||
| -------------------- | ---------------------------- | ------------- | ----------------- |
|
||||
| `PGHOST` | - | `localhost` | Database host |
|
||||
| `PGPORT` | - | `5432` | Database port |
|
||||
| `PGUSERNAME` | `PGUSER`, `USER`, `USERNAME` | `postgres` | Database user |
|
||||
| `PGPASSWORD` | - | (empty) | Database password |
|
||||
| `PGDATABASE` | - | username | Database name |
|
||||
|
||||
## Runtime Preconnection
|
||||
|
||||
Bun can preconnect to PostgreSQL at startup to improve performance by establishing database connections before your application code runs. This is useful for reducing connection latency on the first database query.
|
||||
|
||||
```bash
|
||||
# Enable PostgreSQL preconnection
|
||||
bun --sql-preconnect index.js
|
||||
|
||||
# Works with DATABASE_URL environment variable
|
||||
DATABASE_URL=postgres://user:pass@localhost:5432/db bun --sql-preconnect index.js
|
||||
|
||||
# Can be combined with other runtime flags
|
||||
bun --sql-preconnect --hot index.js
|
||||
```
|
||||
|
||||
The `--sql-preconnect` flag will automatically establish a PostgreSQL connection using your configured environment variables at startup. If the connection fails, it won't crash your application - the error will be handled gracefully.
|
||||
|
||||
## Connection Options
|
||||
|
||||
You can configure your database connection manually by passing options to the SQL constructor:
|
||||
|
||||
```ts
|
||||
import { SQL } from "bun";
|
||||
|
||||
const db = new SQL({
|
||||
// Required
|
||||
url: "postgres://user:pass@localhost:5432/dbname",
|
||||
|
||||
// Optional configuration
|
||||
hostname: "localhost",
|
||||
port: 5432,
|
||||
database: "myapp",
|
||||
username: "dbuser",
|
||||
password: "secretpass",
|
||||
|
||||
// Connection pool settings
|
||||
max: 20, // Maximum connections in pool
|
||||
idleTimeout: 30, // Close idle connections after 30s
|
||||
maxLifetime: 0, // Connection lifetime in seconds (0 = forever)
|
||||
connectionTimeout: 30, // Timeout when establishing new connections
|
||||
|
||||
// SSL/TLS options
|
||||
tls: true,
|
||||
// tls: {
|
||||
// rejectUnauthorized: true,
|
||||
// requestCert: true,
|
||||
// ca: "path/to/ca.pem",
|
||||
// key: "path/to/key.pem",
|
||||
// cert: "path/to/cert.pem",
|
||||
// checkServerIdentity(hostname, cert) {
|
||||
// ...
|
||||
// },
|
||||
// },
|
||||
|
||||
// Callbacks
|
||||
onconnect: client => {
|
||||
console.log("Connected to database");
|
||||
},
|
||||
onclose: client => {
|
||||
console.log("Connection closed");
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Dynamic passwords
|
||||
|
||||
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating passwords, provide either a synchronous or asynchronous function that will resolve the dynamic password value at connection time.
|
||||
|
||||
```ts
|
||||
import { SQL } from "bun";
|
||||
|
||||
const sql = new SQL(url, {
|
||||
// Other connection config
|
||||
...
|
||||
// Password function for the database user
|
||||
password: async () => await signer.getAuthToken(),
|
||||
});
|
||||
```
|
||||
|
||||
## Transactions
|
||||
|
||||
To start a new transaction, use `sql.begin`. This method reserves a dedicated connection for the duration of the transaction and provides a scoped `sql` instance to use within the callback function. Once the callback completes, `sql.begin` resolves with the return value of the callback.
|
||||
|
||||
The `BEGIN` command is sent automatically, including any optional configurations you specify. If an error occurs during the transaction, a `ROLLBACK` is triggered to release the reserved connection and ensure the process continues smoothly.
|
||||
|
||||
### Basic Transactions
|
||||
|
||||
```ts
|
||||
await sql.begin(async tx => {
|
||||
// All queries in this function run in a transaction
|
||||
await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
await tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = 1`;
|
||||
|
||||
// Transaction automatically commits if no errors are thrown
|
||||
// Rolls back if any error occurs
|
||||
});
|
||||
```
|
||||
|
||||
It's also possible to pipeline the requests in a transaction if needed by returning an array with queries from the callback function like this:
|
||||
|
||||
```ts
|
||||
await sql.begin(async tx => {
|
||||
return [
|
||||
tx`INSERT INTO users (name) VALUES (${"Alice"})`,
|
||||
tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = 1`,
|
||||
];
|
||||
});
|
||||
```
|
||||
|
||||
### Savepoints
|
||||
|
||||
Savepoints in SQL create intermediate checkpoints within a transaction, enabling partial rollbacks without affecting the entire operation. They are useful in complex transactions, allowing error recovery and maintaining consistent results.
|
||||
|
||||
```ts
|
||||
await sql.begin(async tx => {
|
||||
await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
|
||||
await tx.savepoint(async sp => {
|
||||
// This part can be rolled back separately
|
||||
await sp`UPDATE users SET status = 'active'`;
|
||||
if (someCondition) {
|
||||
throw new Error("Rollback to savepoint");
|
||||
}
|
||||
});
|
||||
|
||||
// Continue with transaction even if savepoint rolled back
|
||||
await tx`INSERT INTO audit_log (action) VALUES ('user_created')`;
|
||||
});
|
||||
```
|
||||
|
||||
### Distributed Transactions
|
||||
|
||||
Two-Phase Commit (2PC) is a distributed transaction protocol where Phase 1 has the coordinator preparing nodes by ensuring data is written and ready to commit, while Phase 2 finalizes with nodes either committing or rolling back based on the coordinator's decision. This process ensures data durability and proper lock management.
|
||||
|
||||
In PostgreSQL and MySQL, distributed transactions persist beyond their original session, allowing privileged users or coordinators to commit or rollback them later. This supports robust distributed transactions, recovery processes, and administrative operations.
|
||||
|
||||
Each database system implements distributed transactions differently:
|
||||
|
||||
PostgreSQL natively supports them through prepared transactions, while MySQL uses XA Transactions.
|
||||
|
||||
If any exceptions occur during the distributed transaction and aren't caught, the system will automatically rollback all changes. When everything proceeds normally, you maintain the flexibility to either commit or rollback the transaction later.
|
||||
|
||||
```ts
|
||||
// Begin a distributed transaction
|
||||
await sql.beginDistributed("tx1", async tx => {
|
||||
await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
});
|
||||
|
||||
// Later, commit or rollback
|
||||
await sql.commitDistributed("tx1");
|
||||
// or
|
||||
await sql.rollbackDistributed("tx1");
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
Bun supports SCRAM-SHA-256 (SASL), MD5, and Clear Text authentication. SASL is recommended for better security. Check [Postgres SASL Authentication](https://www.postgresql.org/docs/current/sasl-authentication.html) for more information.
|
||||
|
||||
### SSL Modes Overview
|
||||
|
||||
PostgreSQL supports different SSL/TLS modes to control how secure connections are established. These modes determine the behavior when connecting and the level of certificate verification performed.
|
||||
|
||||
```ts
|
||||
const sql = new SQL({
|
||||
hostname: "localhost",
|
||||
username: "user",
|
||||
password: "password",
|
||||
ssl: "disable", // | "prefer" | "require" | "verify-ca" | "verify-full"
|
||||
});
|
||||
```
|
||||
|
||||
| SSL Mode | Description |
|
||||
| ------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `disable` | No SSL/TLS used. Connections fail if server requires SSL. |
|
||||
| `prefer` | Tries SSL first, falls back to non-SSL if SSL fails. Default mode if none specified. |
|
||||
| `require` | Requires SSL without certificate verification. Fails if SSL cannot be established. |
|
||||
| `verify-ca` | Verifies server certificate is signed by trusted CA. Fails if verification fails. |
|
||||
| `verify-full` | Most secure mode. Verifies certificate and hostname match. Protects against untrusted certificates and MITM attacks. |
|
||||
|
||||
### Using With Connection Strings
|
||||
|
||||
The SSL mode can also be specified in connection strings:
|
||||
|
||||
```ts
|
||||
// Using prefer mode
|
||||
const sql = new SQL("postgres://user:password@localhost/mydb?sslmode=prefer");
|
||||
|
||||
// Using verify-full mode
|
||||
const sql = new SQL(
|
||||
"postgres://user:password@localhost/mydb?sslmode=verify-full",
|
||||
);
|
||||
```
|
||||
|
||||
## Connection Pooling
|
||||
|
||||
Bun's SQL client automatically manages a connection pool, which is a pool of database connections that are reused for multiple queries. This helps to reduce the overhead of establishing and closing connections for each query, and it also helps to manage the number of concurrent connections to the database.
|
||||
|
||||
```ts
|
||||
const db = new SQL({
|
||||
// Pool configuration
|
||||
max: 20, // Maximum 20 concurrent connections
|
||||
idleTimeout: 30, // Close idle connections after 30s
|
||||
maxLifetime: 3600, // Max connection lifetime 1 hour
|
||||
connectionTimeout: 10, // Connection timeout 10s
|
||||
});
|
||||
```
|
||||
|
||||
No connection will be made until a query is made.
|
||||
|
||||
```ts
|
||||
const sql = Bun.sql(); // no connection are created
|
||||
|
||||
await sql`...`; // pool is started until max is reached (if possible), first available connection is used
|
||||
await sql`...`; // previous connection is reused
|
||||
|
||||
// two connections are used now at the same time
|
||||
await Promise.all([
|
||||
sql`INSERT INTO users ${sql({ name: "Alice" })}`,
|
||||
sql`UPDATE users SET name = ${user.name} WHERE id = ${user.id}`,
|
||||
]);
|
||||
|
||||
await sql.close(); // await all queries to finish and close all connections from the pool
|
||||
await sql.close({ timeout: 5 }); // wait 5 seconds and close all connections from the pool
|
||||
await sql.close({ timeout: 0 }); // close all connections from the pool immediately
|
||||
```
|
||||
|
||||
## Reserved Connections
|
||||
|
||||
Bun enables you to reserve a connection from the pool, and returns a client that wraps the single connection. This can be used for running queries on an isolated connection.
|
||||
|
||||
```ts
|
||||
// Get exclusive connection from pool
|
||||
const reserved = await sql.reserve();
|
||||
|
||||
try {
|
||||
await reserved`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
} finally {
|
||||
// Important: Release connection back to pool
|
||||
reserved.release();
|
||||
}
|
||||
|
||||
// Or using Symbol.dispose
|
||||
{
|
||||
using reserved = await sql.reserve();
|
||||
await reserved`SELECT 1`;
|
||||
} // Automatically released
|
||||
```
|
||||
|
||||
## Prepared Statements
|
||||
|
||||
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:
|
||||
|
||||
```ts
|
||||
const sql = new SQL({
|
||||
// ... other options ...
|
||||
prepare: false, // Disable persisting named prepared statements on the server
|
||||
});
|
||||
```
|
||||
|
||||
When `prepare: false` is set:
|
||||
|
||||
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.
|
||||
|
||||
- Parameter binding is still safe against SQL injection
|
||||
- Each query is parsed and planned from scratch by the server
|
||||
- Queries will not be [pipelined](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-PIPELINING)
|
||||
|
||||
You might want to use `prepare: false` when:
|
||||
|
||||
- Using PGBouncer in transaction mode (though since PGBouncer 1.21.0, protocol-level named prepared statements are supported when configured properly)
|
||||
- Debugging query execution plans
|
||||
- Working with dynamic SQL where query plans need to be regenerated frequently
|
||||
- More than one command per query will not be supported (unless you use `sql``.simple()`)
|
||||
|
||||
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.
|
||||
|
||||
## Error Handling
|
||||
|
||||
The client provides typed errors for different failure scenarios:
|
||||
|
||||
### Connection Errors
|
||||
|
||||
| Connection Errors | Description |
|
||||
| --------------------------------- | ---------------------------------------------------- |
|
||||
| `ERR_POSTGRES_CONNECTION_CLOSED` | Connection was terminated or never established |
|
||||
| `ERR_POSTGRES_CONNECTION_TIMEOUT` | Failed to establish connection within timeout period |
|
||||
| `ERR_POSTGRES_IDLE_TIMEOUT` | Connection closed due to inactivity |
|
||||
| `ERR_POSTGRES_LIFETIME_TIMEOUT` | Connection exceeded maximum lifetime |
|
||||
| `ERR_POSTGRES_TLS_NOT_AVAILABLE` | SSL/TLS connection not available |
|
||||
| `ERR_POSTGRES_TLS_UPGRADE_FAILED` | Failed to upgrade connection to SSL/TLS |
|
||||
|
||||
### Authentication Errors
|
||||
|
||||
| Authentication Errors | Description |
|
||||
| ------------------------------------------------ | ---------------------------------------- |
|
||||
| `ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2` | Password authentication failed |
|
||||
| `ERR_POSTGRES_UNKNOWN_AUTHENTICATION_METHOD` | Server requested unknown auth method |
|
||||
| `ERR_POSTGRES_UNSUPPORTED_AUTHENTICATION_METHOD` | Server requested unsupported auth method |
|
||||
| `ERR_POSTGRES_INVALID_SERVER_KEY` | Invalid server key during authentication |
|
||||
| `ERR_POSTGRES_INVALID_SERVER_SIGNATURE` | Invalid server signature |
|
||||
| `ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64` | Invalid SASL signature encoding |
|
||||
| `ERR_POSTGRES_SASL_SIGNATURE_MISMATCH` | SASL signature verification failed |
|
||||
|
||||
### Query Errors
|
||||
|
||||
| Query Errors | Description |
|
||||
| ------------------------------------ | ------------------------------------------ |
|
||||
| `ERR_POSTGRES_SYNTAX_ERROR` | Invalid SQL syntax (extends `SyntaxError`) |
|
||||
| `ERR_POSTGRES_SERVER_ERROR` | General error from PostgreSQL server |
|
||||
| `ERR_POSTGRES_INVALID_QUERY_BINDING` | Invalid parameter binding |
|
||||
| `ERR_POSTGRES_QUERY_CANCELLED` | Query was cancelled |
|
||||
| `ERR_POSTGRES_NOT_TAGGED_CALL` | Query was called without a tagged call |
|
||||
|
||||
### Data Type Errors
|
||||
|
||||
| Data Type Errors | Description |
|
||||
| ------------------------------------------------------- | ------------------------------------- |
|
||||
| `ERR_POSTGRES_INVALID_BINARY_DATA` | Invalid binary data format |
|
||||
| `ERR_POSTGRES_INVALID_BYTE_SEQUENCE` | Invalid byte sequence |
|
||||
| `ERR_POSTGRES_INVALID_BYTE_SEQUENCE_FOR_ENCODING` | Encoding error |
|
||||
| `ERR_POSTGRES_INVALID_CHARACTER` | Invalid character in data |
|
||||
| `ERR_POSTGRES_OVERFLOW` | Numeric overflow |
|
||||
| `ERR_POSTGRES_UNSUPPORTED_BYTEA_FORMAT` | Unsupported binary format |
|
||||
| `ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE` | Integer size not supported |
|
||||
| `ERR_POSTGRES_MULTIDIMENSIONAL_ARRAY_NOT_SUPPORTED_YET` | Multidimensional arrays not supported |
|
||||
| `ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET` | NULL values in arrays not supported |
|
||||
|
||||
### Protocol Errors
|
||||
|
||||
| Protocol Errors | Description |
|
||||
| --------------------------------------- | --------------------------- |
|
||||
| `ERR_POSTGRES_EXPECTED_REQUEST` | Expected client request |
|
||||
| `ERR_POSTGRES_EXPECTED_STATEMENT` | Expected prepared statement |
|
||||
| `ERR_POSTGRES_INVALID_BACKEND_KEY_DATA` | Invalid backend key data |
|
||||
| `ERR_POSTGRES_INVALID_MESSAGE` | Invalid protocol message |
|
||||
| `ERR_POSTGRES_INVALID_MESSAGE_LENGTH` | Invalid message length |
|
||||
| `ERR_POSTGRES_UNEXPECTED_MESSAGE` | Unexpected message type |
|
||||
|
||||
### Transaction Errors
|
||||
|
||||
| Transaction Errors | Description |
|
||||
| ---------------------------------------- | ------------------------------------- |
|
||||
| `ERR_POSTGRES_UNSAFE_TRANSACTION` | Unsafe transaction operation detected |
|
||||
| `ERR_POSTGRES_INVALID_TRANSACTION_STATE` | Invalid transaction state |
|
||||
|
||||
## Numbers and BigInt
|
||||
|
||||
Bun's SQL client includes special handling for large numbers that exceed the range of a 53-bit integer. Here's how it works:
|
||||
|
||||
```ts
|
||||
import { sql } from "bun";
|
||||
|
||||
const [{ x, y }] = await sql`SELECT 9223372036854777 as x, 12345 as y`;
|
||||
|
||||
console.log(typeof x, x); // "string" "9223372036854777"
|
||||
console.log(typeof y, y); // "number" 12345
|
||||
```
|
||||
|
||||
## BigInt Instead of Strings
|
||||
|
||||
If you need large numbers as BigInt instead of strings, you can enable this by setting the `bigint` option to `true` when initializing the SQL client:
|
||||
|
||||
```ts
|
||||
const sql = new SQL({
|
||||
bigint: true,
|
||||
});
|
||||
|
||||
const [{ x }] = await sql`SELECT 9223372036854777 as x`;
|
||||
|
||||
console.log(typeof x, x); // "bigint" 9223372036854777n
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
There's still some things we haven't finished yet.
|
||||
|
||||
- Connection preloading via `--db-preconnect` Bun CLI flag
|
||||
- MySQL support: [we're working on it](https://github.com/oven-sh/bun/pull/15274)
|
||||
- SQLite support: planned, but not started. Ideally, we implement it natively instead of wrapping `bun:sqlite`.
|
||||
- Column name transforms (e.g. `snake_case` to `camelCase`). This is mostly blocked on a unicode-aware implementation of changing the case in C++ using WebKit's `WTF::String`.
|
||||
- Column type transforms
|
||||
|
||||
### Postgres-specific features
|
||||
|
||||
We haven't implemented these yet:
|
||||
|
||||
- `COPY` support
|
||||
- `LISTEN` support
|
||||
- `NOTIFY` support
|
||||
|
||||
We also haven't implemented some of the more uncommon features like:
|
||||
|
||||
- GSSAPI authentication
|
||||
- `SCRAM-SHA-256-PLUS` support
|
||||
- Point & PostGIS types
|
||||
- All the multi-dimensional integer array types (only a couple of the types are supported)
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
> Why is this `Bun.sql` and not `Bun.postgres`?
|
||||
|
||||
The plan is to add more database drivers in the future.
|
||||
|
||||
> Why not just use an existing library?
|
||||
|
||||
npm packages like postgres.js, pg, and node-postgres can be used in Bun too. They're great options.
|
||||
|
||||
Two reasons why:
|
||||
|
||||
1. We think it's simpler for developers to have a database driver built into Bun. The time you spend library shopping is time you could be building your app.
|
||||
2. We leverage some JavaScriptCore engine internals to make it faster to create objects that would be difficult to implement in a library
|
||||
|
||||
## Credits
|
||||
|
||||
Huge thanks to [@porsager](https://github.com/porsager)'s [postgres.js](https://github.com/porsager/postgres) for the inspiration for the API interface.
|
||||
692
node_modules/bun-types/docs/api/sqlite.md
generated
vendored
Normal file
692
node_modules/bun-types/docs/api/sqlite.md
generated
vendored
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
Bun natively implements a high-performance [SQLite3](https://www.sqlite.org/) driver. To use it import from the built-in `bun:sqlite` module.
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database(":memory:");
|
||||
const query = db.query("select 'Hello world' as message;");
|
||||
query.get(); // => { message: "Hello world" }
|
||||
```
|
||||
|
||||
The API is simple, synchronous, and fast. Credit to [better-sqlite3](https://github.com/JoshuaWise/better-sqlite3) and its contributors for inspiring the API of `bun:sqlite`.
|
||||
|
||||
Features include:
|
||||
|
||||
- Transactions
|
||||
- Parameters (named & positional)
|
||||
- Prepared statements
|
||||
- Datatype conversions (`BLOB` becomes `Uint8Array`)
|
||||
- Map query results to classes without an ORM - `query.as(MyClass)`
|
||||
- The fastest performance of any SQLite driver for JavaScript
|
||||
- `bigint` support
|
||||
- Multi-query statements (e.g. `SELECT 1; SELECT 2;`) in a single call to database.run(query)
|
||||
|
||||
The `bun:sqlite` module is roughly 3-6x faster than `better-sqlite3` and 8-9x faster than `deno.land/x/sqlite` for read queries. Each driver was benchmarked against the [Northwind Traders](https://github.com/jpwhite3/northwind-SQLite3/blob/46d5f8a64f396f87cd374d1600dbf521523980e8/Northwind_large.sqlite.zip) dataset. View and run the [benchmark source](https://github.com/oven-sh/bun/tree/main/bench/sqlite).
|
||||
|
||||
{% image width="738" alt="SQLite benchmarks for Bun, better-sqlite3, and deno.land/x/sqlite" src="https://user-images.githubusercontent.com/709451/168459263-8cd51ca3-a924-41e9-908d-cf3478a3b7f3.png" caption="Benchmarked on an M1 MacBook Pro (64GB) running macOS 12.3.1" /%}
|
||||
|
||||
## Database
|
||||
|
||||
To open or create a SQLite3 database:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database("mydb.sqlite");
|
||||
```
|
||||
|
||||
To open an in-memory database:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
// all of these do the same thing
|
||||
const db = new Database(":memory:");
|
||||
const db = new Database();
|
||||
const db = new Database("");
|
||||
```
|
||||
|
||||
To open in `readonly` mode:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
const db = new Database("mydb.sqlite", { readonly: true });
|
||||
```
|
||||
|
||||
To create the database if the file doesn't exist:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
const db = new Database("mydb.sqlite", { create: true });
|
||||
```
|
||||
|
||||
### Strict mode
|
||||
|
||||
{% callout %}
|
||||
Added in Bun v1.1.14
|
||||
{% /callout %}
|
||||
|
||||
By default, `bun:sqlite` requires binding parameters to include the `$`, `:`, or `@` prefix, and does not throw an error if a parameter is missing.
|
||||
|
||||
To instead throw an error when a parameter is missing and allow binding without a prefix, set `strict: true` on the `Database` constructor:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const strict = new Database(
|
||||
":memory:",
|
||||
{ strict: true }
|
||||
);
|
||||
|
||||
// throws error because of the typo:
|
||||
const query = strict
|
||||
.query("SELECT $message;")
|
||||
.all({ message: "Hello world" });
|
||||
|
||||
const notStrict = new Database(
|
||||
":memory:"
|
||||
);
|
||||
// does not throw error:
|
||||
notStrict
|
||||
.query("SELECT $message;")
|
||||
.all({ message: "Hello world" });
|
||||
```
|
||||
|
||||
### Load via ES module import
|
||||
|
||||
You can also use an import attribute to load a database.
|
||||
|
||||
```ts
|
||||
import db from "./mydb.sqlite" with { "type": "sqlite" };
|
||||
|
||||
console.log(db.query("select * from users LIMIT 1").get());
|
||||
```
|
||||
|
||||
This is equivalent to the following:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
const db = new Database("./mydb.sqlite");
|
||||
```
|
||||
|
||||
### `.close(throwOnError: boolean = false)`
|
||||
|
||||
To close a database connection, but allow existing queries to finish, call `.close(false)`:
|
||||
|
||||
```ts
|
||||
const db = new Database();
|
||||
// ... do stuff
|
||||
db.close(false);
|
||||
```
|
||||
|
||||
To close the database and throw an error if there are any pending queries, call `.close(true)`:
|
||||
|
||||
```ts
|
||||
const db = new Database();
|
||||
// ... do stuff
|
||||
db.close(true);
|
||||
```
|
||||
|
||||
Note: `close(false)` is called automatically when the database is garbage collected. It is safe to call multiple times but has no effect after the first.
|
||||
|
||||
### `using` statement
|
||||
|
||||
You can use the `using` statement to ensure that a database connection is closed when the `using` block is exited.
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
{
|
||||
using db = new Database("mydb.sqlite");
|
||||
using query = db.query("select 'Hello world' as message;");
|
||||
console.log(query.get()); // => { message: "Hello world" }
|
||||
}
|
||||
```
|
||||
|
||||
### `.serialize()`
|
||||
|
||||
`bun:sqlite` supports SQLite's built-in mechanism for [serializing](https://www.sqlite.org/c3ref/serialize.html) and [deserializing](https://www.sqlite.org/c3ref/deserialize.html) databases to and from memory.
|
||||
|
||||
```ts
|
||||
const olddb = new Database("mydb.sqlite");
|
||||
const contents = olddb.serialize(); // => Uint8Array
|
||||
const newdb = Database.deserialize(contents);
|
||||
```
|
||||
|
||||
Internally, `.serialize()` calls [`sqlite3_serialize`](https://www.sqlite.org/c3ref/serialize.html).
|
||||
|
||||
### `.query()`
|
||||
|
||||
Use the `db.query()` method on your `Database` instance to [prepare](https://www.sqlite.org/c3ref/prepare.html) a SQL query. The result is a `Statement` instance that will be cached on the `Database` instance. _The query will not be executed._
|
||||
|
||||
```ts
|
||||
const query = db.query(`select "Hello world" as message`);
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — Use the `.prepare()` method to prepare a query _without_ caching it on the `Database` instance.
|
||||
|
||||
```ts
|
||||
// compile the prepared statement
|
||||
const query = db.prepare("SELECT * FROM foo WHERE bar = ?");
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## WAL mode
|
||||
|
||||
SQLite supports [write-ahead log mode](https://www.sqlite.org/wal.html) (WAL) which dramatically improves performance, especially in situations with many concurrent readers and a single writer. It's broadly recommended to enable WAL mode for most typical applications.
|
||||
|
||||
To enable WAL mode, run this pragma query at the beginning of your application:
|
||||
|
||||
```ts
|
||||
db.exec("PRAGMA journal_mode = WAL;");
|
||||
```
|
||||
|
||||
{% details summary="What is WAL mode" %}
|
||||
In WAL mode, writes to the database are written directly to a separate file called the "WAL file" (write-ahead log). This file will be later integrated into the main database file. Think of it as a buffer for pending writes. Refer to the [SQLite docs](https://www.sqlite.org/wal.html) for a more detailed overview.
|
||||
|
||||
On macOS, WAL files may be persistent by default. This is not a bug, it is how macOS configured the system version of SQLite.
|
||||
{% /details %}
|
||||
|
||||
## Statements
|
||||
|
||||
A `Statement` is a _prepared query_, which means it's been parsed and compiled into an efficient binary form. It can be executed multiple times in a performant way.
|
||||
|
||||
Create a statement with the `.query` method on your `Database` instance.
|
||||
|
||||
```ts
|
||||
const query = db.query(`select "Hello world" as message`);
|
||||
```
|
||||
|
||||
Queries can contain parameters. These can be numerical (`?1`) or named (`$param` or `:param` or `@param`).
|
||||
|
||||
```ts
|
||||
const query = db.query(`SELECT ?1, ?2;`);
|
||||
const query = db.query(`SELECT $param1, $param2;`);
|
||||
```
|
||||
|
||||
Values are bound to these parameters when the query is executed. A `Statement` can be executed with several different methods, each returning the results in a different form.
|
||||
|
||||
### Binding values
|
||||
|
||||
To bind values to a statement, pass an object to the `.all()`, `.get()`, `.run()`, or `.values()` method.
|
||||
|
||||
```ts
|
||||
const query = db.query(`select $message;`);
|
||||
query.all({ $message: "Hello world" });
|
||||
```
|
||||
|
||||
You can bind using positional parameters too:
|
||||
|
||||
```ts
|
||||
const query = db.query(`select ?1;`);
|
||||
query.all("Hello world");
|
||||
```
|
||||
|
||||
#### `strict: true` lets you bind values without prefixes
|
||||
|
||||
{% callout %}
|
||||
Added in Bun v1.1.14
|
||||
{% /callout %}
|
||||
|
||||
By default, the `$`, `:`, and `@` prefixes are **included** when binding values to named parameters. To bind without these prefixes, use the `strict` option in the `Database` constructor.
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database(":memory:", {
|
||||
// bind values without prefixes
|
||||
strict: true,
|
||||
});
|
||||
|
||||
const query = db.query(`select $message;`);
|
||||
|
||||
// strict: true
|
||||
query.all({ message: "Hello world" });
|
||||
|
||||
// strict: false
|
||||
// query.all({ $message: "Hello world" });
|
||||
```
|
||||
|
||||
### `.all()`
|
||||
|
||||
Use `.all()` to run a query and get back the results as an array of objects.
|
||||
|
||||
```ts
|
||||
const query = db.query(`select $message;`);
|
||||
query.all({ $message: "Hello world" });
|
||||
// => [{ message: "Hello world" }]
|
||||
```
|
||||
|
||||
Internally, this calls [`sqlite3_reset`](https://www.sqlite.org/capi3ref.html#sqlite3_reset) and repeatedly calls [`sqlite3_step`](https://www.sqlite.org/capi3ref.html#sqlite3_step) until it returns `SQLITE_DONE`.
|
||||
|
||||
### `.get()`
|
||||
|
||||
Use `.get()` to run a query and get back the first result as an object.
|
||||
|
||||
```ts
|
||||
const query = db.query(`select $message;`);
|
||||
query.get({ $message: "Hello world" });
|
||||
// => { $message: "Hello world" }
|
||||
```
|
||||
|
||||
Internally, this calls [`sqlite3_reset`](https://www.sqlite.org/capi3ref.html#sqlite3_reset) followed by [`sqlite3_step`](https://www.sqlite.org/capi3ref.html#sqlite3_step) until it no longer returns `SQLITE_ROW`. If the query returns no rows, `undefined` is returned.
|
||||
|
||||
### `.run()`
|
||||
|
||||
Use `.run()` to run a query and get back `undefined`. This is useful for schema-modifying queries (e.g. `CREATE TABLE`) or bulk write operations.
|
||||
|
||||
```ts
|
||||
const query = db.query(`create table foo;`);
|
||||
query.run();
|
||||
// {
|
||||
// lastInsertRowid: 0,
|
||||
// changes: 0,
|
||||
// }
|
||||
```
|
||||
|
||||
Internally, this calls [`sqlite3_reset`](https://www.sqlite.org/capi3ref.html#sqlite3_reset) and calls [`sqlite3_step`](https://www.sqlite.org/capi3ref.html#sqlite3_step) once. Stepping through all the rows is not necessary when you don't care about the results.
|
||||
|
||||
{% callout %}
|
||||
Since Bun v1.1.14, `.run()` returns an object with two properties: `lastInsertRowid` and `changes`.
|
||||
{% /callout %}
|
||||
|
||||
The `lastInsertRowid` property returns the ID of the last row inserted into the database. The `changes` property is the number of rows affected by the query.
|
||||
|
||||
### `.as(Class)` - Map query results to a class
|
||||
|
||||
{% callout %}
|
||||
Added in Bun v1.1.14
|
||||
{% /callout %}
|
||||
|
||||
Use `.as(Class)` to run a query and get back the results as instances of a class. This lets you attach methods & getters/setters to results.
|
||||
|
||||
```ts
|
||||
class Movie {
|
||||
title: string;
|
||||
year: number;
|
||||
|
||||
get isMarvel() {
|
||||
return this.title.includes("Marvel");
|
||||
}
|
||||
}
|
||||
|
||||
const query = db.query("SELECT title, year FROM movies").as(Movie);
|
||||
const movies = query.all();
|
||||
const first = query.get();
|
||||
console.log(movies[0].isMarvel); // => true
|
||||
console.log(first.isMarvel); // => true
|
||||
```
|
||||
|
||||
As a performance optimization, the class constructor is not called, default initializers are not run, and private fields are not accessible. This is more like using `Object.create` than `new`. The class's prototype is assigned to the object, methods are attached, and getters/setters are set up, but the constructor is not called.
|
||||
|
||||
The database columns are set as properties on the class instance.
|
||||
|
||||
### `.iterate()` (`@@iterator`)
|
||||
|
||||
Use `.iterate()` to run a query and incrementally return results. This is useful for large result sets that you want to process one row at a time without loading all the results into memory.
|
||||
|
||||
```ts
|
||||
const query = db.query("SELECT * FROM foo");
|
||||
for (const row of query.iterate()) {
|
||||
console.log(row);
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the `@@iterator` protocol:
|
||||
|
||||
```ts
|
||||
const query = db.query("SELECT * FROM foo");
|
||||
for (const row of query) {
|
||||
console.log(row);
|
||||
}
|
||||
```
|
||||
|
||||
This feature was added in Bun v1.1.31.
|
||||
|
||||
### `.values()`
|
||||
|
||||
Use `values()` to run a query and get back all results as an array of arrays.
|
||||
|
||||
```ts
|
||||
const query = db.query(`select $message;`);
|
||||
query.values({ $message: "Hello world" });
|
||||
|
||||
query.values(2);
|
||||
// [
|
||||
// [ "Iron Man", 2008 ],
|
||||
// [ "The Avengers", 2012 ],
|
||||
// [ "Ant-Man: Quantumania", 2023 ],
|
||||
// ]
|
||||
```
|
||||
|
||||
Internally, this calls [`sqlite3_reset`](https://www.sqlite.org/capi3ref.html#sqlite3_reset) and repeatedly calls [`sqlite3_step`](https://www.sqlite.org/capi3ref.html#sqlite3_step) until it returns `SQLITE_DONE`.
|
||||
|
||||
### `.finalize()`
|
||||
|
||||
Use `.finalize()` to destroy a `Statement` and free any resources associated with it. Once finalized, a `Statement` cannot be executed again. Typically, the garbage collector will do this for you, but explicit finalization may be useful in performance-sensitive applications.
|
||||
|
||||
```ts
|
||||
const query = db.query("SELECT title, year FROM movies");
|
||||
const movies = query.all();
|
||||
query.finalize();
|
||||
```
|
||||
|
||||
### `.toString()`
|
||||
|
||||
Calling `toString()` on a `Statement` instance prints the expanded SQL query. This is useful for debugging.
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
// setup
|
||||
const query = db.query("SELECT $param;");
|
||||
|
||||
console.log(query.toString()); // => "SELECT NULL"
|
||||
|
||||
query.run(42);
|
||||
console.log(query.toString()); // => "SELECT 42"
|
||||
|
||||
query.run(365);
|
||||
console.log(query.toString()); // => "SELECT 365"
|
||||
```
|
||||
|
||||
Internally, this calls [`sqlite3_expanded_sql`](https://www.sqlite.org/capi3ref.html#sqlite3_expanded_sql). The parameters are expanded using the most recently bound values.
|
||||
|
||||
## Parameters
|
||||
|
||||
Queries can contain parameters. These can be numerical (`?1`) or named (`$param` or `:param` or `@param`). Bind values to these parameters when executing the query:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#Query
|
||||
const query = db.query("SELECT * FROM foo WHERE bar = $bar");
|
||||
const results = query.all({
|
||||
$bar: "bar",
|
||||
});
|
||||
```
|
||||
|
||||
```json#Results
|
||||
[
|
||||
{ "$bar": "bar" }
|
||||
]
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
Numbered (positional) parameters work too:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#Query
|
||||
const query = db.query("SELECT ?1, ?2");
|
||||
const results = query.all("hello", "goodbye");
|
||||
```
|
||||
|
||||
```ts#Results
|
||||
[
|
||||
{
|
||||
"?1": "hello",
|
||||
"?2": "goodbye"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## Integers
|
||||
|
||||
sqlite supports signed 64 bit integers, but JavaScript only supports signed 52 bit integers or arbitrary precision integers with `bigint`.
|
||||
|
||||
`bigint` input is supported everywhere, but by default `bun:sqlite` returns integers as `number` types. If you need to handle integers larger than 2^53, set `safeIntegers` option to `true` when creating a `Database` instance. This also validates that `bigint` passed to `bun:sqlite` do not exceed 64 bits.
|
||||
|
||||
By default, `bun:sqlite` returns integers as `number` types. If you need to handle integers larger than 2^53, you can use the `bigint` type.
|
||||
|
||||
### `safeIntegers: true`
|
||||
|
||||
{% callout %}
|
||||
Added in Bun v1.1.14
|
||||
{% /callout %}
|
||||
|
||||
When `safeIntegers` is `true`, `bun:sqlite` will return integers as `bigint` types:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database(":memory:", { safeIntegers: true });
|
||||
const query = db.query(
|
||||
`SELECT ${BigInt(Number.MAX_SAFE_INTEGER) + 102n} as max_int`,
|
||||
);
|
||||
const result = query.get();
|
||||
console.log(result.max_int); // => 9007199254741093n
|
||||
```
|
||||
|
||||
When `safeIntegers` is `true`, `bun:sqlite` will throw an error if a `bigint` value in a bound parameter exceeds 64 bits:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database(":memory:", { safeIntegers: true });
|
||||
db.run("CREATE TABLE test (id INTEGER PRIMARY KEY, value INTEGER)");
|
||||
|
||||
const query = db.query("INSERT INTO test (value) VALUES ($value)");
|
||||
|
||||
try {
|
||||
query.run({ $value: BigInt(Number.MAX_SAFE_INTEGER) ** 2n });
|
||||
} catch (e) {
|
||||
console.log(e.message); // => BigInt value '81129638414606663681390495662081' is out of range
|
||||
}
|
||||
```
|
||||
|
||||
### `safeIntegers: false` (default)
|
||||
|
||||
When `safeIntegers` is `false`, `bun:sqlite` will return integers as `number` types and truncate any bits beyond 53:
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database(":memory:", { safeIntegers: false });
|
||||
const query = db.query(
|
||||
`SELECT ${BigInt(Number.MAX_SAFE_INTEGER) + 102n} as max_int`,
|
||||
);
|
||||
const result = query.get();
|
||||
console.log(result.max_int); // => 9007199254741092
|
||||
```
|
||||
|
||||
## Transactions
|
||||
|
||||
Transactions are a mechanism for executing multiple queries in an _atomic_ way; that is, either all of the queries succeed or none of them do. Create a transaction with the `db.transaction()` method:
|
||||
|
||||
```ts
|
||||
const insertCat = db.prepare("INSERT INTO cats (name) VALUES ($name)");
|
||||
const insertCats = db.transaction(cats => {
|
||||
for (const cat of cats) insertCat.run(cat);
|
||||
});
|
||||
```
|
||||
|
||||
At this stage, we haven't inserted any cats! The call to `db.transaction()` returns a new function (`insertCats`) that _wraps_ the function that executes the queries.
|
||||
|
||||
To execute the transaction, call this function. All arguments will be passed through to the wrapped function; the return value of the wrapped function will be returned by the transaction function. The wrapped function also has access to the `this` context as defined where the transaction is executed.
|
||||
|
||||
```ts
|
||||
const insert = db.prepare("INSERT INTO cats (name) VALUES ($name)");
|
||||
const insertCats = db.transaction(cats => {
|
||||
for (const cat of cats) insert.run(cat);
|
||||
return cats.length;
|
||||
});
|
||||
|
||||
const count = insertCats([
|
||||
{ $name: "Keanu" },
|
||||
{ $name: "Salem" },
|
||||
{ $name: "Crookshanks" },
|
||||
]);
|
||||
|
||||
console.log(`Inserted ${count} cats`);
|
||||
```
|
||||
|
||||
The driver will automatically [`begin`](https://www.sqlite.org/lang_transaction.html) a transaction when `insertCats` is called and `commit` it when the wrapped function returns. If an exception is thrown, the transaction will be rolled back. The exception will propagate as usual; it is not caught.
|
||||
|
||||
{% callout %}
|
||||
**Nested transactions** — Transaction functions can be called from inside other transaction functions. When doing so, the inner transaction becomes a [savepoint](https://www.sqlite.org/lang_savepoint.html).
|
||||
|
||||
{% details summary="View nested transaction example" %}
|
||||
|
||||
```ts
|
||||
// setup
|
||||
import { Database } from "bun:sqlite";
|
||||
const db = Database.open(":memory:");
|
||||
db.run(
|
||||
"CREATE TABLE expenses (id INTEGER PRIMARY KEY AUTOINCREMENT, note TEXT, dollars INTEGER);",
|
||||
);
|
||||
db.run(
|
||||
"CREATE TABLE cats (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER)",
|
||||
);
|
||||
const insertExpense = db.prepare(
|
||||
"INSERT INTO expenses (note, dollars) VALUES (?, ?)",
|
||||
);
|
||||
const insert = db.prepare("INSERT INTO cats (name, age) VALUES ($name, $age)");
|
||||
const insertCats = db.transaction(cats => {
|
||||
for (const cat of cats) insert.run(cat);
|
||||
});
|
||||
|
||||
const adopt = db.transaction(cats => {
|
||||
insertExpense.run("adoption fees", 20);
|
||||
insertCats(cats); // nested transaction
|
||||
});
|
||||
|
||||
adopt([
|
||||
{ $name: "Joey", $age: 2 },
|
||||
{ $name: "Sally", $age: 4 },
|
||||
{ $name: "Junior", $age: 1 },
|
||||
]);
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
{% /callout %}
|
||||
|
||||
Transactions also come with `deferred`, `immediate`, and `exclusive` versions.
|
||||
|
||||
```ts
|
||||
insertCats(cats); // uses "BEGIN"
|
||||
insertCats.deferred(cats); // uses "BEGIN DEFERRED"
|
||||
insertCats.immediate(cats); // uses "BEGIN IMMEDIATE"
|
||||
insertCats.exclusive(cats); // uses "BEGIN EXCLUSIVE"
|
||||
```
|
||||
|
||||
### `.loadExtension()`
|
||||
|
||||
To load a [SQLite extension](https://www.sqlite.org/loadext.html), call `.loadExtension(name)` on your `Database` instance
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database();
|
||||
db.loadExtension("myext");
|
||||
```
|
||||
|
||||
{% details summary="For macOS users" %}
|
||||
**MacOS users** By default, macOS ships with Apple's proprietary build of SQLite, which doesn't support extensions. To use extensions, you'll need to install a vanilla build of SQLite.
|
||||
|
||||
```bash
|
||||
$ brew install sqlite
|
||||
$ which sqlite # get path to binary
|
||||
```
|
||||
|
||||
To point `bun:sqlite` to the new build, call `Database.setCustomSQLite(path)` before creating any `Database` instances. (On other operating systems, this is a no-op.) Pass a path to the SQLite `.dylib` file, _not_ the executable. With recent versions of Homebrew this is something like `/opt/homebrew/Cellar/sqlite/<version>/libsqlite3.dylib`.
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
Database.setCustomSQLite("/path/to/libsqlite.dylib");
|
||||
|
||||
const db = new Database();
|
||||
db.loadExtension("myext");
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
### .fileControl(cmd: number, value: any)
|
||||
|
||||
To use the advanced `sqlite3_file_control` API, call `.fileControl(cmd, value)` on your `Database` instance.
|
||||
|
||||
```ts
|
||||
import { Database, constants } from "bun:sqlite";
|
||||
|
||||
const db = new Database();
|
||||
// Ensure WAL mode is NOT persistent
|
||||
// this prevents wal files from lingering after the database is closed
|
||||
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
|
||||
```
|
||||
|
||||
`value` can be:
|
||||
|
||||
- `number`
|
||||
- `TypedArray`
|
||||
- `undefined` or `null`
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
class Database {
|
||||
constructor(
|
||||
filename: string,
|
||||
options?:
|
||||
| number
|
||||
| {
|
||||
readonly?: boolean;
|
||||
create?: boolean;
|
||||
readwrite?: boolean;
|
||||
},
|
||||
);
|
||||
|
||||
query<Params, ReturnType>(sql: string): Statement<Params, ReturnType>;
|
||||
run(
|
||||
sql: string,
|
||||
params?: SQLQueryBindings,
|
||||
): { lastInsertRowid: number; changes: number };
|
||||
exec = this.run;
|
||||
}
|
||||
|
||||
class Statement<Params, ReturnType> {
|
||||
all(params: Params): ReturnType[];
|
||||
get(params: Params): ReturnType | undefined;
|
||||
run(params: Params): {
|
||||
lastInsertRowid: number;
|
||||
changes: number;
|
||||
};
|
||||
values(params: Params): unknown[][];
|
||||
|
||||
finalize(): void; // destroy statement and clean up resources
|
||||
toString(): string; // serialize to SQL
|
||||
|
||||
columnNames: string[]; // the column names of the result set
|
||||
paramsCount: number; // the number of parameters expected by the statement
|
||||
native: any; // the native object representing the statement
|
||||
|
||||
as(Class: new () => ReturnType): this;
|
||||
}
|
||||
|
||||
type SQLQueryBindings =
|
||||
| string
|
||||
| bigint
|
||||
| TypedArray
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| Record<string, string | bigint | TypedArray | number | boolean | null>;
|
||||
```
|
||||
|
||||
### Datatypes
|
||||
|
||||
| JavaScript type | SQLite type |
|
||||
| --------------- | ---------------------- |
|
||||
| `string` | `TEXT` |
|
||||
| `number` | `INTEGER` or `DECIMAL` |
|
||||
| `boolean` | `INTEGER` (1 or 0) |
|
||||
| `Uint8Array` | `BLOB` |
|
||||
| `Buffer` | `BLOB` |
|
||||
| `bigint` | `INTEGER` |
|
||||
| `null` | `NULL` |
|
||||
216
node_modules/bun-types/docs/api/streams.md
generated
vendored
Normal file
216
node_modules/bun-types/docs/api/streams.md
generated
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
Streams are an important abstraction for working with binary data without loading it all into memory at once. They are commonly used for reading and writing files, sending and receiving network requests, and processing large amounts of data.
|
||||
|
||||
Bun implements the Web APIs [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) and [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream).
|
||||
|
||||
{% callout %}
|
||||
Bun also implements the `node:stream` module, including [`Readable`](https://nodejs.org/api/stream.html#stream_readable_streams), [`Writable`](https://nodejs.org/api/stream.html#stream_writable_streams), and [`Duplex`](https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams). For complete documentation, refer to the [Node.js docs](https://nodejs.org/api/stream.html).
|
||||
{% /callout %}
|
||||
|
||||
To create a simple `ReadableStream`:
|
||||
|
||||
```ts
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("hello");
|
||||
controller.enqueue("world");
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The contents of a `ReadableStream` can be read chunk-by-chunk with `for await` syntax.
|
||||
|
||||
```ts
|
||||
for await (const chunk of stream) {
|
||||
console.log(chunk);
|
||||
// => "hello"
|
||||
// => "world"
|
||||
}
|
||||
```
|
||||
|
||||
## Direct `ReadableStream`
|
||||
|
||||
Bun implements an optimized version of `ReadableStream` that avoid unnecessary data copying & queue management logic. With a traditional `ReadableStream`, chunks of data are _enqueued_. Each chunk is copied into a queue, where it sits until the stream is ready to send more data.
|
||||
|
||||
```ts
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("hello");
|
||||
controller.enqueue("world");
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
With a direct `ReadableStream`, chunks of data are written directly to the stream. No queueing happens, and there's no need to clone the chunk data into memory. The `controller` API is updated to reflect this; instead of `.enqueue()` you call `.write`.
|
||||
|
||||
```ts
|
||||
const stream = new ReadableStream({
|
||||
type: "direct",
|
||||
pull(controller) {
|
||||
controller.write("hello");
|
||||
controller.write("world");
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
When using a direct `ReadableStream`, all chunk queueing is handled by the destination. The consumer of the stream receives exactly what is passed to `controller.write()`, without any encoding or modification.
|
||||
|
||||
## Async generator streams
|
||||
|
||||
Bun also supports async generator functions as a source for `Response` and `Request`. This is an easy way to create a `ReadableStream` that fetches data from an asynchronous source.
|
||||
|
||||
```ts
|
||||
const response = new Response(
|
||||
(async function* () {
|
||||
yield "hello";
|
||||
yield "world";
|
||||
})(),
|
||||
);
|
||||
|
||||
await response.text(); // "helloworld"
|
||||
```
|
||||
|
||||
You can also use `[Symbol.asyncIterator]` directly.
|
||||
|
||||
```ts
|
||||
const response = new Response({
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
yield "hello";
|
||||
yield "world";
|
||||
},
|
||||
});
|
||||
|
||||
await response.text(); // "helloworld"
|
||||
```
|
||||
|
||||
If you need more granular control over the stream, `yield` will return the direct ReadableStream controller.
|
||||
|
||||
```ts
|
||||
const response = new Response({
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
const controller = yield "hello";
|
||||
await controller.end();
|
||||
},
|
||||
});
|
||||
|
||||
await response.text(); // "hello"
|
||||
```
|
||||
|
||||
## `Bun.ArrayBufferSink`
|
||||
|
||||
The `Bun.ArrayBufferSink` class is a fast incremental writer for constructing an `ArrayBuffer` of unknown size.
|
||||
|
||||
```ts
|
||||
const sink = new Bun.ArrayBufferSink();
|
||||
|
||||
sink.write("h");
|
||||
sink.write("e");
|
||||
sink.write("l");
|
||||
sink.write("l");
|
||||
sink.write("o");
|
||||
|
||||
sink.end();
|
||||
// ArrayBuffer(5) [ 104, 101, 108, 108, 111 ]
|
||||
```
|
||||
|
||||
To instead retrieve the data as a `Uint8Array`, pass the `asUint8Array` option to the `start` method.
|
||||
|
||||
```ts-diff
|
||||
const sink = new Bun.ArrayBufferSink();
|
||||
sink.start({
|
||||
+ asUint8Array: true
|
||||
});
|
||||
|
||||
sink.write("h");
|
||||
sink.write("e");
|
||||
sink.write("l");
|
||||
sink.write("l");
|
||||
sink.write("o");
|
||||
|
||||
sink.end();
|
||||
// Uint8Array(5) [ 104, 101, 108, 108, 111 ]
|
||||
```
|
||||
|
||||
The `.write()` method supports strings, typed arrays, `ArrayBuffer`, and `SharedArrayBuffer`.
|
||||
|
||||
```ts
|
||||
sink.write("h");
|
||||
sink.write(new Uint8Array([101, 108]));
|
||||
sink.write(Buffer.from("lo").buffer);
|
||||
|
||||
sink.end();
|
||||
```
|
||||
|
||||
Once `.end()` is called, no more data can be written to the `ArrayBufferSink`. However, in the context of buffering a stream, it's useful to continuously write data and periodically `.flush()` the contents (say, into a `WriteableStream`). To support this, pass `stream: true` to the constructor.
|
||||
|
||||
```ts
|
||||
const sink = new Bun.ArrayBufferSink();
|
||||
sink.start({
|
||||
stream: true,
|
||||
});
|
||||
|
||||
sink.write("h");
|
||||
sink.write("e");
|
||||
sink.write("l");
|
||||
sink.flush();
|
||||
// ArrayBuffer(5) [ 104, 101, 108 ]
|
||||
|
||||
sink.write("l");
|
||||
sink.write("o");
|
||||
sink.flush();
|
||||
// ArrayBuffer(5) [ 108, 111 ]
|
||||
```
|
||||
|
||||
The `.flush()` method returns the buffered data as an `ArrayBuffer` (or `Uint8Array` if `asUint8Array: true`) and clears internal buffer.
|
||||
|
||||
To manually set the size of the internal buffer in bytes, pass a value for `highWaterMark`:
|
||||
|
||||
```ts
|
||||
const sink = new Bun.ArrayBufferSink();
|
||||
sink.start({
|
||||
highWaterMark: 1024 * 1024, // 1 MB
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="Reference" %}
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Fast incremental writer that becomes an `ArrayBuffer` on end().
|
||||
*/
|
||||
export class ArrayBufferSink {
|
||||
constructor();
|
||||
|
||||
start(options?: {
|
||||
asUint8Array?: boolean;
|
||||
/**
|
||||
* Preallocate an internal buffer of this size
|
||||
* This can significantly improve performance when the chunk size is small
|
||||
*/
|
||||
highWaterMark?: number;
|
||||
/**
|
||||
* On {@link ArrayBufferSink.flush}, return the written data as a `Uint8Array`.
|
||||
* Writes will restart from the beginning of the buffer.
|
||||
*/
|
||||
stream?: boolean;
|
||||
}): void;
|
||||
|
||||
write(
|
||||
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
|
||||
): number;
|
||||
/**
|
||||
* Flush the internal buffer
|
||||
*
|
||||
* If {@link ArrayBufferSink.start} was passed a `stream` option, this will return a `ArrayBuffer`
|
||||
* If {@link ArrayBufferSink.start} was passed a `stream` option and `asUint8Array`, this will return a `Uint8Array`
|
||||
* Otherwise, this will return the number of bytes written since the last flush
|
||||
*
|
||||
* This API might change later to separate Uint8ArraySink and ArrayBufferSink
|
||||
*/
|
||||
flush(): number | Uint8Array | ArrayBuffer;
|
||||
end(): ArrayBuffer | Uint8Array;
|
||||
}
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
221
node_modules/bun-types/docs/api/tcp.md
generated
vendored
Normal file
221
node_modules/bun-types/docs/api/tcp.md
generated
vendored
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
Use Bun's native TCP API to implement performance sensitive systems like database clients, game servers, or anything that needs to communicate over TCP (instead of HTTP). This is a low-level API intended for library authors and for advanced use cases.
|
||||
|
||||
## Start a server (`Bun.listen()`)
|
||||
|
||||
To start a TCP server with `Bun.listen`:
|
||||
|
||||
```ts
|
||||
Bun.listen({
|
||||
hostname: "localhost",
|
||||
port: 8080,
|
||||
socket: {
|
||||
data(socket, data) {}, // message received from client
|
||||
open(socket) {}, // socket opened
|
||||
close(socket, error) {}, // socket closed
|
||||
drain(socket) {}, // socket ready for more data
|
||||
error(socket, error) {}, // error handler
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="An API designed for speed" %}
|
||||
|
||||
In Bun, a set of handlers are declared once per server instead of assigning callbacks to each socket, as with Node.js `EventEmitters` or the web-standard `WebSocket` API.
|
||||
|
||||
```ts
|
||||
Bun.listen({
|
||||
hostname: "localhost",
|
||||
port: 8080,
|
||||
socket: {
|
||||
open(socket) {},
|
||||
data(socket, data) {},
|
||||
drain(socket) {},
|
||||
close(socket, error) {},
|
||||
error(socket, error) {},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
For performance-sensitive servers, assigning listeners to each socket can cause significant garbage collector pressure and increase memory usage. By contrast, Bun only allocates one handler function for each event and shares it among all sockets. This is a small optimization, but it adds up.
|
||||
|
||||
{% /details %}
|
||||
|
||||
Contextual data can be attached to a socket in the `open` handler.
|
||||
|
||||
```ts
|
||||
type SocketData = { sessionId: string };
|
||||
|
||||
Bun.listen<SocketData>({
|
||||
hostname: "localhost",
|
||||
port: 8080,
|
||||
socket: {
|
||||
data(socket, data) {
|
||||
socket.write(`${socket.data.sessionId}: ack`);
|
||||
},
|
||||
open(socket) {
|
||||
socket.data = { sessionId: "abcd" };
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To enable TLS, pass a `tls` object containing `key` and `cert` fields.
|
||||
|
||||
```ts
|
||||
Bun.listen({
|
||||
hostname: "localhost",
|
||||
port: 8080,
|
||||
socket: {
|
||||
data(socket, data) {},
|
||||
},
|
||||
tls: {
|
||||
// can be string, BunFile, TypedArray, Buffer, or array thereof
|
||||
key: Bun.file("./key.pem"),
|
||||
cert: Bun.file("./cert.pem"),
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The `key` and `cert` fields expect the _contents_ of your TLS key and certificate. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
|
||||
|
||||
```ts
|
||||
Bun.listen({
|
||||
// ...
|
||||
tls: {
|
||||
// BunFile
|
||||
key: Bun.file("./key.pem"),
|
||||
// Buffer
|
||||
key: fs.readFileSync("./key.pem"),
|
||||
// string
|
||||
key: fs.readFileSync("./key.pem", "utf8"),
|
||||
// array of above
|
||||
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The result of `Bun.listen` is a server that conforms to the `TCPSocket` interface.
|
||||
|
||||
```ts
|
||||
const server = Bun.listen({
|
||||
/* config*/
|
||||
});
|
||||
|
||||
// stop listening
|
||||
// parameter determines whether active connections are closed
|
||||
server.stop(true);
|
||||
|
||||
// let Bun process exit even if server is still listening
|
||||
server.unref();
|
||||
```
|
||||
|
||||
## Create a connection (`Bun.connect()`)
|
||||
|
||||
Use `Bun.connect` to connect to a TCP server. Specify the server to connect to with `hostname` and `port`. TCP clients can define the same set of handlers as `Bun.listen`, plus a couple client-specific handlers.
|
||||
|
||||
```ts
|
||||
// The client
|
||||
const socket = await Bun.connect({
|
||||
hostname: "localhost",
|
||||
port: 8080,
|
||||
|
||||
socket: {
|
||||
data(socket, data) {},
|
||||
open(socket) {},
|
||||
close(socket, error) {},
|
||||
drain(socket) {},
|
||||
error(socket, error) {},
|
||||
|
||||
// client-specific handlers
|
||||
connectError(socket, error) {}, // connection failed
|
||||
end(socket) {}, // connection closed by server
|
||||
timeout(socket) {}, // connection timed out
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To require TLS, specify `tls: true`.
|
||||
|
||||
```ts
|
||||
// The client
|
||||
const socket = await Bun.connect({
|
||||
// ... config
|
||||
tls: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Hot reloading
|
||||
|
||||
Both TCP servers and sockets can be hot reloaded with new handlers.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#Server
|
||||
const server = Bun.listen({ /* config */ })
|
||||
|
||||
// reloads handlers for all active server-side sockets
|
||||
server.reload({
|
||||
socket: {
|
||||
data(){
|
||||
// new 'data' handler
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```ts#Client
|
||||
const socket = await Bun.connect({ /* config */ })
|
||||
socket.reload({
|
||||
data(){
|
||||
// new 'data' handler
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## Buffering
|
||||
|
||||
Currently, TCP sockets in Bun do not buffer data. For performance-sensitive code, it's important to consider buffering carefully. For example, this:
|
||||
|
||||
```ts
|
||||
socket.write("h");
|
||||
socket.write("e");
|
||||
socket.write("l");
|
||||
socket.write("l");
|
||||
socket.write("o");
|
||||
```
|
||||
|
||||
...performs significantly worse than this:
|
||||
|
||||
```ts
|
||||
socket.write("hello");
|
||||
```
|
||||
|
||||
To simplify this for now, consider using Bun's `ArrayBufferSink` with the `{stream: true}` option:
|
||||
|
||||
```ts
|
||||
import { ArrayBufferSink } from "bun";
|
||||
|
||||
const sink = new ArrayBufferSink();
|
||||
sink.start({ stream: true, highWaterMark: 1024 });
|
||||
|
||||
sink.write("h");
|
||||
sink.write("e");
|
||||
sink.write("l");
|
||||
sink.write("l");
|
||||
sink.write("o");
|
||||
|
||||
queueMicrotask(() => {
|
||||
const data = sink.flush();
|
||||
const wrote = socket.write(data);
|
||||
if (wrote < data.byteLength) {
|
||||
// put it back in the sink if the socket is full
|
||||
sink.write(data.subarray(wrote));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Corking** — Support for corking is planned, but in the meantime backpressure must be managed manually with the `drain` handler.
|
||||
{% /callout %}
|
||||
276
node_modules/bun-types/docs/api/transpiler.md
generated
vendored
Normal file
276
node_modules/bun-types/docs/api/transpiler.md
generated
vendored
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
Bun exposes its internal transpiler via the `Bun.Transpiler` class. To create an instance of Bun's transpiler:
|
||||
|
||||
```ts
|
||||
const transpiler = new Bun.Transpiler({
|
||||
loader: "tsx", // "js | "jsx" | "ts" | "tsx"
|
||||
});
|
||||
```
|
||||
|
||||
## `.transformSync()`
|
||||
|
||||
Transpile code synchronously with the `.transformSync()` method. Modules are not resolved and the code is not executed. The result is a string of vanilla JavaScript code.
|
||||
|
||||
<!-- It is synchronous and runs in the same thread as other JavaScript code. -->
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```js#Example
|
||||
const transpiler = new Bun.Transpiler({
|
||||
loader: 'tsx',
|
||||
});
|
||||
|
||||
const code = `
|
||||
import * as whatever from "./whatever.ts"
|
||||
export function Home(props: {title: string}){
|
||||
return <p>{props.title}</p>;
|
||||
}`;
|
||||
|
||||
const result = transpiler.transformSync(code);
|
||||
```
|
||||
|
||||
```js#Result
|
||||
import { __require as require } from "bun:wrap";
|
||||
import * as JSX from "react/jsx-dev-runtime";
|
||||
var jsx = require(JSX).jsxDEV;
|
||||
|
||||
export default jsx(
|
||||
"div",
|
||||
{
|
||||
children: "hi!",
|
||||
},
|
||||
undefined,
|
||||
false,
|
||||
undefined,
|
||||
this,
|
||||
);
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
To override the default loader specified in the `new Bun.Transpiler()` constructor, pass a second argument to `.transformSync()`.
|
||||
|
||||
```ts
|
||||
transpiler.transformSync("<div>hi!</div>", "tsx");
|
||||
```
|
||||
|
||||
{% details summary="Nitty gritty" %}
|
||||
When `.transformSync` is called, the transpiler is run in the same thread as the currently executed code.
|
||||
|
||||
If a macro is used, it will be run in the same thread as the transpiler, but in a separate event loop from the rest of your application. Currently, globals between macros and regular code are shared, which means it is possible (but not recommended) to share states between macros and regular code. Attempting to use AST nodes outside of a macro is undefined behavior.
|
||||
{% /details %}
|
||||
|
||||
## `.transform()`
|
||||
|
||||
The `transform()` method is an async version of `.transformSync()` that returns a `Promise<string>`.
|
||||
|
||||
```js
|
||||
const transpiler = new Bun.Transpiler({ loader: "jsx" });
|
||||
const result = await transpiler.transform("<div>hi!</div>");
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
Unless you're transpiling _many_ large files, you should probably use `Bun.Transpiler.transformSync`. The cost of the threadpool will often take longer than actually transpiling code.
|
||||
|
||||
```ts
|
||||
await transpiler.transform("<div>hi!</div>", "tsx");
|
||||
```
|
||||
|
||||
{% details summary="Nitty gritty" %}
|
||||
The `.transform()` method runs the transpiler in Bun's worker threadpool, so if you run it 100 times, it will run it across `Math.floor($cpu_count * 0.8)` threads, without blocking the main JavaScript thread.
|
||||
|
||||
If your code uses a macro, it will potentially spawn a new copy of Bun's JavaScript runtime environment in that new thread.
|
||||
{% /details %}
|
||||
|
||||
## `.scan()`
|
||||
|
||||
The `Transpiler` instance can also scan some source code and return a list of its imports and exports, plus additional metadata about each one. [Type-only](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export) imports and exports are ignored.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#Example
|
||||
const transpiler = new Bun.Transpiler({
|
||||
loader: 'tsx',
|
||||
});
|
||||
|
||||
const code = `
|
||||
import React from 'react';
|
||||
import type {ReactNode} from 'react';
|
||||
const val = require('./cjs.js')
|
||||
import('./loader');
|
||||
|
||||
export const name = "hello";
|
||||
`;
|
||||
|
||||
const result = transpiler.scan(code);
|
||||
```
|
||||
|
||||
```json#Output
|
||||
{
|
||||
"exports": [
|
||||
"name"
|
||||
],
|
||||
"imports": [
|
||||
{
|
||||
"kind": "import-statement",
|
||||
"path": "react"
|
||||
},
|
||||
{
|
||||
"kind": "import-statement",
|
||||
"path": "remix"
|
||||
},
|
||||
{
|
||||
"kind": "dynamic-import",
|
||||
"path": "./loader"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
Each import in the `imports` array has a `path` and `kind`. Bun categories imports into the following kinds:
|
||||
|
||||
- `import-statement`: `import React from 'react'`
|
||||
- `require-call`: `const val = require('./cjs.js')`
|
||||
- `require-resolve`: `require.resolve('./cjs.js')`
|
||||
- `dynamic-import`: `import('./loader')`
|
||||
- `import-rule`: `@import 'foo.css'`
|
||||
- `url-token`: `url('./foo.png')`
|
||||
<!-- - `internal`: `import {foo} from 'bun:internal'`
|
||||
- `entry-point-build`: `import {foo} from 'bun:entry'`
|
||||
- `entry-point-run`: `bun ./mymodule` -->
|
||||
|
||||
## `.scanImports()`
|
||||
|
||||
For performance-sensitive code, you can use the `.scanImports()` method to get a list of imports. It's faster than `.scan()` (especially for large files) but marginally less accurate due to some performance optimizations.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#Example
|
||||
const transpiler = new Bun.Transpiler({
|
||||
loader: 'tsx',
|
||||
});
|
||||
|
||||
const code = `
|
||||
import React from 'react';
|
||||
import type {ReactNode} from 'react';
|
||||
const val = require('./cjs.js')
|
||||
import('./loader');
|
||||
|
||||
export const name = "hello";
|
||||
`;
|
||||
|
||||
const result = transpiler.scanImports(code);
|
||||
```
|
||||
|
||||
```json#Results
|
||||
[
|
||||
{
|
||||
kind: "import-statement",
|
||||
path: "react"
|
||||
}, {
|
||||
kind: "require-call",
|
||||
path: "./cjs.js"
|
||||
}, {
|
||||
kind: "dynamic-import",
|
||||
path: "./loader"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
type Loader = "jsx" | "js" | "ts" | "tsx";
|
||||
|
||||
interface TranspilerOptions {
|
||||
// Replace key with value. Value must be a JSON string.
|
||||
// { "process.env.NODE_ENV": "\"production\"" }
|
||||
define?: Record<string, string>,
|
||||
|
||||
// Default loader for this transpiler
|
||||
loader?: Loader,
|
||||
|
||||
// Default platform to target
|
||||
// This affects how import and/or require is used
|
||||
target?: "browser" | "bun" | "node",
|
||||
|
||||
// Specify a tsconfig.json file as stringified JSON or an object
|
||||
// Use this to set a custom JSX factory, fragment, or import source
|
||||
// For example, if you want to use Preact instead of React. Or if you want to use Emotion.
|
||||
tsconfig?: string | TSConfig,
|
||||
|
||||
// Replace imports with macros
|
||||
macro?: MacroMap,
|
||||
|
||||
// Specify a set of exports to eliminate
|
||||
// Or rename certain exports
|
||||
exports?: {
|
||||
eliminate?: string[];
|
||||
replace?: Record<string, string>;
|
||||
},
|
||||
|
||||
// Whether to remove unused imports from transpiled file
|
||||
// Default: false
|
||||
trimUnusedImports?: boolean,
|
||||
|
||||
// Whether to enable a set of JSX optimizations
|
||||
// jsxOptimizationInline ...,
|
||||
|
||||
// Experimental whitespace minification
|
||||
minifyWhitespace?: boolean,
|
||||
|
||||
// Whether to inline constant values
|
||||
// Typically improves performance and decreases bundle size
|
||||
// Default: true
|
||||
inline?: boolean,
|
||||
}
|
||||
|
||||
// Map import paths to macros
|
||||
interface MacroMap {
|
||||
// {
|
||||
// "react-relay": {
|
||||
// "graphql": "bun-macro-relay/bun-macro-relay.tsx"
|
||||
// }
|
||||
// }
|
||||
[packagePath: string]: {
|
||||
[importItemName: string]: string,
|
||||
},
|
||||
}
|
||||
|
||||
class Bun.Transpiler {
|
||||
constructor(options: TranspilerOptions)
|
||||
|
||||
transform(code: string, loader?: Loader): Promise<string>
|
||||
transformSync(code: string, loader?: Loader): string
|
||||
|
||||
scan(code: string): {exports: string[], imports: Import}
|
||||
scanImports(code: string): Import[]
|
||||
}
|
||||
|
||||
type Import = {
|
||||
path: string,
|
||||
kind:
|
||||
// import foo from 'bar'; in JavaScript
|
||||
| "import-statement"
|
||||
// require("foo") in JavaScript
|
||||
| "require-call"
|
||||
// require.resolve("foo") in JavaScript
|
||||
| "require-resolve"
|
||||
// Dynamic import() in JavaScript
|
||||
| "dynamic-import"
|
||||
// @import() in CSS
|
||||
| "import-rule"
|
||||
// url() in CSS
|
||||
| "url-token"
|
||||
// The import was injected by Bun
|
||||
| "internal"
|
||||
// Entry point (not common)
|
||||
| "entry-point-build"
|
||||
| "entry-point-run"
|
||||
}
|
||||
|
||||
const transpiler = new Bun.Transpiler({ loader: "jsx" });
|
||||
```
|
||||
123
node_modules/bun-types/docs/api/udp.md
generated
vendored
Normal file
123
node_modules/bun-types/docs/api/udp.md
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
Use Bun's UDP API to implement services with advanced real-time requirements, such as voice chat.
|
||||
|
||||
## Bind a UDP socket (`Bun.udpSocket()`)
|
||||
|
||||
To create a new (bound) UDP socket:
|
||||
|
||||
```ts
|
||||
const socket = await Bun.udpSocket({});
|
||||
console.log(socket.port); // assigned by the operating system
|
||||
```
|
||||
|
||||
Specify a port:
|
||||
|
||||
```ts
|
||||
const socket = await Bun.udpSocket({
|
||||
port: 41234,
|
||||
});
|
||||
console.log(socket.port); // 41234
|
||||
```
|
||||
|
||||
### Send a datagram
|
||||
|
||||
Specify the data to send, as well as the destination port and address.
|
||||
|
||||
```ts
|
||||
socket.send("Hello, world!", 41234, "127.0.0.1");
|
||||
```
|
||||
|
||||
Note that the address must be a valid IP address - `send` does not perform
|
||||
DNS resolution, as it is intended for low-latency operations.
|
||||
|
||||
### Receive datagrams
|
||||
|
||||
When creating your socket, add a callback to specify what should be done when packets are received:
|
||||
|
||||
```ts
|
||||
const server = await Bun.udpSocket({
|
||||
socket: {
|
||||
data(socket, buf, port, addr) {
|
||||
console.log(`message from ${addr}:${port}:`);
|
||||
console.log(buf.toString());
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const client = await Bun.udpSocket({});
|
||||
client.send("Hello!", server.port, "127.0.0.1");
|
||||
```
|
||||
|
||||
### Connections
|
||||
|
||||
While UDP does not have a concept of a connection, many UDP communications (especially as a client) involve only one peer.
|
||||
In such cases it can be beneficial to connect the socket to that peer, which specifies to which address all packets are sent
|
||||
and restricts incoming packets to that peer only.
|
||||
|
||||
```ts
|
||||
const server = await Bun.udpSocket({
|
||||
socket: {
|
||||
data(socket, buf, port, addr) {
|
||||
console.log(`message from ${addr}:${port}:`);
|
||||
console.log(buf.toString());
|
||||
},
|
||||
},
|
||||
});
|
||||
const client = await Bun.udpSocket({
|
||||
connect: {
|
||||
port: server.port,
|
||||
hostname: "127.0.0.1",
|
||||
},
|
||||
});
|
||||
|
||||
client.send("Hello");
|
||||
```
|
||||
|
||||
Because connections are implemented on the operating system level, you can potentially observe performance benefits, too.
|
||||
|
||||
### Send many packets at once using `sendMany()`
|
||||
|
||||
If you want to send a large volume of packets at once, it can make sense to batch them all together to avoid the overhead
|
||||
of making a system call for each. This is made possible by the `sendMany()` API:
|
||||
|
||||
For an unconnected socket, `sendMany` takes an array as its only argument. Each set of three array elements describes a packet:
|
||||
The first item is the data to be sent, the second is the target port, and the last is the target address.
|
||||
|
||||
```ts
|
||||
const socket = await Bun.udpSocket({});
|
||||
// sends 'Hello' to 127.0.0.1:41234, and 'foo' to 1.1.1.1:53 in a single operation
|
||||
socket.sendMany(["Hello", 41234, "127.0.0.1", "foo", 53, "1.1.1.1"]);
|
||||
```
|
||||
|
||||
With a connected socket, `sendMany` simply takes an array, where each element represents the data to be sent to the peer.
|
||||
|
||||
```ts
|
||||
const socket = await Bun.udpSocket({
|
||||
connect: {
|
||||
port: 41234,
|
||||
hostname: "localhost",
|
||||
},
|
||||
});
|
||||
socket.sendMany(["foo", "bar", "baz"]);
|
||||
```
|
||||
|
||||
`sendMany` returns the number of packets that were successfully sent. As with `send`, `sendMany` only takes valid IP addresses
|
||||
as destinations, as it does not perform DNS resolution.
|
||||
|
||||
### Handle backpressure
|
||||
|
||||
It may happen that a packet that you're sending does not fit into the operating system's packet buffer. You can detect that this
|
||||
has happened when:
|
||||
|
||||
- `send` returns `false`
|
||||
- `sendMany` returns a number smaller than the number of packets you specified
|
||||
In this case, the `drain` socket handler will be called once the socket becomes writable again:
|
||||
|
||||
```ts
|
||||
const socket = await Bun.udpSocket({
|
||||
socket: {
|
||||
drain(socket) {
|
||||
// continue sending data
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
798
node_modules/bun-types/docs/api/utils.md
generated
vendored
Normal file
798
node_modules/bun-types/docs/api/utils.md
generated
vendored
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
## `Bun.version`
|
||||
|
||||
A `string` containing the version of the `bun` CLI that is currently running.
|
||||
|
||||
```ts
|
||||
Bun.version;
|
||||
// => "0.6.4"
|
||||
```
|
||||
|
||||
## `Bun.revision`
|
||||
|
||||
The git commit of [Bun](https://github.com/oven-sh/bun) that was compiled to create the current `bun` CLI.
|
||||
|
||||
```ts
|
||||
Bun.revision;
|
||||
// => "f02561530fda1ee9396f51c8bc99b38716e38296"
|
||||
```
|
||||
|
||||
## `Bun.env`
|
||||
|
||||
An alias for `process.env`.
|
||||
|
||||
## `Bun.main`
|
||||
|
||||
An absolute path to the entrypoint of the current program (the file that was executed with `bun run`).
|
||||
|
||||
```ts#script.ts
|
||||
Bun.main;
|
||||
// /path/to/script.ts
|
||||
```
|
||||
|
||||
This is particular useful for determining whether a script is being directly executed, as opposed to being imported by another script.
|
||||
|
||||
```ts
|
||||
if (import.meta.path === Bun.main) {
|
||||
// this script is being directly executed
|
||||
} else {
|
||||
// this file is being imported from another script
|
||||
}
|
||||
```
|
||||
|
||||
This is analogous to the [`require.main = module` trick](https://stackoverflow.com/questions/6398196/detect-if-called-through-require-or-directly-by-command-line) in Node.js.
|
||||
|
||||
## `Bun.sleep()`
|
||||
|
||||
`Bun.sleep(ms: number)`
|
||||
|
||||
Returns a `Promise` that resolves after the given number of milliseconds.
|
||||
|
||||
```ts
|
||||
console.log("hello");
|
||||
await Bun.sleep(1000);
|
||||
console.log("hello one second later!");
|
||||
```
|
||||
|
||||
Alternatively, pass a `Date` object to receive a `Promise` that resolves at that point in time.
|
||||
|
||||
```ts
|
||||
const oneSecondInFuture = new Date(Date.now() + 1000);
|
||||
|
||||
console.log("hello");
|
||||
await Bun.sleep(oneSecondInFuture);
|
||||
console.log("hello one second later!");
|
||||
```
|
||||
|
||||
## `Bun.sleepSync()`
|
||||
|
||||
`Bun.sleepSync(ms: number)`
|
||||
|
||||
A blocking synchronous version of `Bun.sleep`.
|
||||
|
||||
```ts
|
||||
console.log("hello");
|
||||
Bun.sleepSync(1000); // blocks thread for one second
|
||||
console.log("hello one second later!");
|
||||
```
|
||||
|
||||
## `Bun.which()`
|
||||
|
||||
`Bun.which(bin: string)`
|
||||
|
||||
Returns the path to an executable, similar to typing `which` in your terminal.
|
||||
|
||||
```ts
|
||||
const ls = Bun.which("ls");
|
||||
console.log(ls); // "/usr/bin/ls"
|
||||
```
|
||||
|
||||
By default Bun looks at the current `PATH` environment variable to determine the path. To configure `PATH`:
|
||||
|
||||
```ts
|
||||
const ls = Bun.which("ls", {
|
||||
PATH: "/usr/local/bin:/usr/bin:/bin",
|
||||
});
|
||||
console.log(ls); // "/usr/bin/ls"
|
||||
```
|
||||
|
||||
Pass a `cwd` option to resolve for executable from within a specific directory.
|
||||
|
||||
```ts
|
||||
const ls = Bun.which("ls", {
|
||||
cwd: "/tmp",
|
||||
PATH: "",
|
||||
});
|
||||
|
||||
console.log(ls); // null
|
||||
```
|
||||
|
||||
You can think of this as a builtin alternative to the [`which`](https://www.npmjs.com/package/which) npm package.
|
||||
|
||||
## `Bun.randomUUIDv7()`
|
||||
|
||||
`Bun.randomUUIDv7()` returns a [UUID v7](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-01.html#name-uuidv7-layout-and-bit-order), which is monotonic and suitable for sorting and databases.
|
||||
|
||||
```ts
|
||||
import { randomUUIDv7 } from "bun";
|
||||
|
||||
const id = randomUUIDv7();
|
||||
// => "0192ce11-26d5-7dc3-9305-1426de888c5a"
|
||||
```
|
||||
|
||||
A UUID v7 is a 128-bit value that encodes the current timestamp, a random value, and a counter. The timestamp is encoded using the lowest 48 bits, and the random value and counter are encoded using the remaining bits.
|
||||
|
||||
The `timestamp` parameter defaults to the current time in milliseconds. When the timestamp changes, the counter is reset to a pseudo-random integer wrapped to 4096. This counter is atomic and threadsafe, meaning that using `Bun.randomUUIDv7()` in many Workers within the same process running at the same timestamp will not have colliding counter values.
|
||||
|
||||
The final 8 bytes of the UUID are a cryptographically secure random value. It uses the same random number generator used by `crypto.randomUUID()` (which comes from BoringSSL, which in turn comes from the platform-specific system random number generator usually provided by the underlying hardware).
|
||||
|
||||
```ts
|
||||
namespace Bun {
|
||||
function randomUUIDv7(
|
||||
encoding?: "hex" | "base64" | "base64url" = "hex",
|
||||
timestamp?: number = Date.now(),
|
||||
): string;
|
||||
/**
|
||||
* If you pass "buffer", you get a 16-byte buffer instead of a string.
|
||||
*/
|
||||
function randomUUIDv7(
|
||||
encoding: "buffer",
|
||||
timestamp?: number = Date.now(),
|
||||
): Buffer;
|
||||
|
||||
// If you only pass a timestamp, you get a hex string
|
||||
function randomUUIDv7(timestamp?: number = Date.now()): string;
|
||||
}
|
||||
```
|
||||
|
||||
You can optionally set encoding to `"buffer"` to get a 16-byte buffer instead of a string. This can sometimes avoid string conversion overhead.
|
||||
|
||||
```ts#buffer.ts
|
||||
const buffer = Bun.randomUUIDv7("buffer");
|
||||
```
|
||||
|
||||
`base64` and `base64url` encodings are also supported when you want a slightly shorter string.
|
||||
|
||||
```ts#base64.ts
|
||||
const base64 = Bun.randomUUIDv7("base64");
|
||||
const base64url = Bun.randomUUIDv7("base64url");
|
||||
```
|
||||
|
||||
## `Bun.peek()`
|
||||
|
||||
`Bun.peek(prom: Promise)`
|
||||
|
||||
Reads a promise's result without `await` or `.then`, but only if the promise has already fulfilled or rejected.
|
||||
|
||||
```ts
|
||||
import { peek } from "bun";
|
||||
|
||||
const promise = Promise.resolve("hi");
|
||||
|
||||
// no await!
|
||||
const result = peek(promise);
|
||||
console.log(result); // "hi"
|
||||
```
|
||||
|
||||
This is important when attempting to reduce number of extraneous microticks in performance-sensitive code. It's an advanced API and you probably shouldn't use it unless you know what you're doing.
|
||||
|
||||
```ts
|
||||
import { peek } from "bun";
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
test("peek", () => {
|
||||
const promise = Promise.resolve(true);
|
||||
|
||||
// no await necessary!
|
||||
expect(peek(promise)).toBe(true);
|
||||
|
||||
// if we peek again, it returns the same value
|
||||
const again = peek(promise);
|
||||
expect(again).toBe(true);
|
||||
|
||||
// if we peek a non-promise, it returns the value
|
||||
const value = peek(42);
|
||||
expect(value).toBe(42);
|
||||
|
||||
// if we peek a pending promise, it returns the promise again
|
||||
const pending = new Promise(() => {});
|
||||
expect(peek(pending)).toBe(pending);
|
||||
|
||||
// If we peek a rejected promise, it:
|
||||
// - returns the error
|
||||
// - does not mark the promise as handled
|
||||
const rejected = Promise.reject(
|
||||
new Error("Successfully tested promise rejection"),
|
||||
);
|
||||
expect(peek(rejected).message).toBe("Successfully tested promise rejection");
|
||||
});
|
||||
```
|
||||
|
||||
The `peek.status` function lets you read the status of a promise without resolving it.
|
||||
|
||||
```ts
|
||||
import { peek } from "bun";
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
test("peek.status", () => {
|
||||
const promise = Promise.resolve(true);
|
||||
expect(peek.status(promise)).toBe("fulfilled");
|
||||
|
||||
const pending = new Promise(() => {});
|
||||
expect(peek.status(pending)).toBe("pending");
|
||||
|
||||
const rejected = Promise.reject(new Error("oh nooo"));
|
||||
expect(peek.status(rejected)).toBe("rejected");
|
||||
});
|
||||
```
|
||||
|
||||
## `Bun.openInEditor()`
|
||||
|
||||
Opens a file in your default editor. Bun auto-detects your editor via the `$VISUAL` or `$EDITOR` environment variables.
|
||||
|
||||
```ts
|
||||
const currentFile = import.meta.url;
|
||||
Bun.openInEditor(currentFile);
|
||||
```
|
||||
|
||||
You can override this via the `debug.editor` setting in your [`bunfig.toml`](https://bun.com/docs/runtime/bunfig).
|
||||
|
||||
```toml-diff#bunfig.toml
|
||||
+ [debug]
|
||||
+ editor = "code"
|
||||
```
|
||||
|
||||
Or specify an editor with the `editor` param. You can also specify a line and column number.
|
||||
|
||||
```ts
|
||||
Bun.openInEditor(import.meta.url, {
|
||||
editor: "vscode", // or "subl"
|
||||
line: 10,
|
||||
column: 5,
|
||||
});
|
||||
```
|
||||
|
||||
## `Bun.deepEquals()`
|
||||
|
||||
Recursively checks if two objects are equivalent. This is used internally by `expect().toEqual()` in `bun:test`.
|
||||
|
||||
```ts
|
||||
const foo = { a: 1, b: 2, c: { d: 3 } };
|
||||
|
||||
// true
|
||||
Bun.deepEquals(foo, { a: 1, b: 2, c: { d: 3 } });
|
||||
|
||||
// false
|
||||
Bun.deepEquals(foo, { a: 1, b: 2, c: { d: 4 } });
|
||||
```
|
||||
|
||||
A third boolean parameter can be used to enable "strict" mode. This is used by `expect().toStrictEqual()` in the test runner.
|
||||
|
||||
```ts
|
||||
const a = { entries: [1, 2] };
|
||||
const b = { entries: [1, 2], extra: undefined };
|
||||
|
||||
Bun.deepEquals(a, b); // => true
|
||||
Bun.deepEquals(a, b, true); // => false
|
||||
```
|
||||
|
||||
In strict mode, the following are considered unequal:
|
||||
|
||||
```ts
|
||||
// undefined values
|
||||
Bun.deepEquals({}, { a: undefined }, true); // false
|
||||
|
||||
// undefined in arrays
|
||||
Bun.deepEquals(["asdf"], ["asdf", undefined], true); // false
|
||||
|
||||
// sparse arrays
|
||||
Bun.deepEquals([, 1], [undefined, 1], true); // false
|
||||
|
||||
// object literals vs instances w/ same properties
|
||||
class Foo {
|
||||
a = 1;
|
||||
}
|
||||
Bun.deepEquals(new Foo(), { a: 1 }, true); // false
|
||||
```
|
||||
|
||||
## `Bun.escapeHTML()`
|
||||
|
||||
`Bun.escapeHTML(value: string | object | number | boolean): string`
|
||||
|
||||
Escapes the following characters from an input string:
|
||||
|
||||
- `"` becomes `"`
|
||||
- `&` becomes `&`
|
||||
- `'` becomes `'`
|
||||
- `<` becomes `<`
|
||||
- `>` becomes `>`
|
||||
|
||||
This function is optimized for large input. On an M1X, it processes 480 MB/s -
|
||||
20 GB/s, depending on how much data is being escaped and whether there is non-ascii
|
||||
text. Non-string types will be converted to a string before escaping.
|
||||
|
||||
## `Bun.stringWidth()` ~6,756x faster `string-width` alternative
|
||||
|
||||
Get the column count of a string as it would be displayed in a terminal.
|
||||
Supports ANSI escape codes, emoji, and wide characters.
|
||||
|
||||
Example usage:
|
||||
|
||||
```ts
|
||||
Bun.stringWidth("hello"); // => 5
|
||||
Bun.stringWidth("\u001b[31mhello\u001b[0m"); // => 5
|
||||
Bun.stringWidth("\u001b[31mhello\u001b[0m", { countAnsiEscapeCodes: true }); // => 12
|
||||
```
|
||||
|
||||
This is useful for:
|
||||
|
||||
- Aligning text in a terminal
|
||||
- Quickly checking if a string contains ANSI escape codes
|
||||
- Measuring the width of a string in a terminal
|
||||
|
||||
This API is designed to match the popular "string-width" package, so that
|
||||
existing code can be easily ported to Bun and vice versa.
|
||||
|
||||
[In this benchmark](https://github.com/oven-sh/bun/blob/5147c0ba7379d85d4d1ed0714b84d6544af917eb/bench/snippets/string-width.mjs#L13), `Bun.stringWidth` is a ~6,756x faster than the `string-width` npm package for input larger than about 500 characters. Big thanks to [sindresorhus](https://github.com/sindresorhus) for their work on `string-width`!
|
||||
|
||||
```ts
|
||||
❯ bun string-width.mjs
|
||||
cpu: 13th Gen Intel(R) Core(TM) i9-13900
|
||||
runtime: bun 1.0.29 (x64-linux)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
------------------------------------------------------------------------------------- -----------------------------
|
||||
Bun.stringWidth 500 chars ascii 37.09 ns/iter (36.77 ns … 41.11 ns) 37.07 ns 38.84 ns 38.99 ns
|
||||
|
||||
❯ node string-width.mjs
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
------------------------------------------------------------------------------------- -----------------------------
|
||||
npm/string-width 500 chars ascii 249,710 ns/iter (239,970 ns … 293,180 ns) 250,930 ns 276,700 ns 281,450 ns
|
||||
```
|
||||
|
||||
To make `Bun.stringWidth` fast, we've implemented it in Zig using optimized SIMD instructions, accounting for Latin1, UTF-16, and UTF-8 encodings. It passes `string-width`'s tests.
|
||||
|
||||
{% details summary="View full benchmark" %}
|
||||
|
||||
As a reminder, 1 nanosecond (ns) is 1 billionth of a second. Here's a quick reference for converting between units:
|
||||
|
||||
| Unit | 1 Millisecond |
|
||||
| ---- | ------------- |
|
||||
| ns | 1,000,000 |
|
||||
| µs | 1,000 |
|
||||
| ms | 1 |
|
||||
|
||||
```js
|
||||
❯ bun string-width.mjs
|
||||
cpu: 13th Gen Intel(R) Core(TM) i9-13900
|
||||
runtime: bun 1.0.29 (x64-linux)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
------------------------------------------------------------------------------------- -----------------------------
|
||||
Bun.stringWidth 5 chars ascii 16.45 ns/iter (16.27 ns … 19.71 ns) 16.48 ns 16.93 ns 17.21 ns
|
||||
Bun.stringWidth 50 chars ascii 19.42 ns/iter (18.61 ns … 27.85 ns) 19.35 ns 21.7 ns 22.31 ns
|
||||
Bun.stringWidth 500 chars ascii 37.09 ns/iter (36.77 ns … 41.11 ns) 37.07 ns 38.84 ns 38.99 ns
|
||||
Bun.stringWidth 5,000 chars ascii 216.9 ns/iter (215.8 ns … 228.54 ns) 216.23 ns 228.52 ns 228.53 ns
|
||||
Bun.stringWidth 25,000 chars ascii 1.01 µs/iter (1.01 µs … 1.01 µs) 1.01 µs 1.01 µs 1.01 µs
|
||||
Bun.stringWidth 7 chars ascii+emoji 54.2 ns/iter (53.36 ns … 58.19 ns) 54.23 ns 57.55 ns 57.94 ns
|
||||
Bun.stringWidth 70 chars ascii+emoji 354.26 ns/iter (350.51 ns … 363.96 ns) 355.93 ns 363.11 ns 363.96 ns
|
||||
Bun.stringWidth 700 chars ascii+emoji 3.3 µs/iter (3.27 µs … 3.4 µs) 3.3 µs 3.4 µs 3.4 µs
|
||||
Bun.stringWidth 7,000 chars ascii+emoji 32.69 µs/iter (32.22 µs … 45.27 µs) 32.7 µs 34.57 µs 34.68 µs
|
||||
Bun.stringWidth 35,000 chars ascii+emoji 163.35 µs/iter (161.17 µs … 170.79 µs) 163.82 µs 169.66 µs 169.93 µs
|
||||
Bun.stringWidth 8 chars ansi+emoji 66.15 ns/iter (65.17 ns … 69.97 ns) 66.12 ns 69.8 ns 69.87 ns
|
||||
Bun.stringWidth 80 chars ansi+emoji 492.95 ns/iter (488.05 ns … 499.5 ns) 494.8 ns 498.58 ns 499.5 ns
|
||||
Bun.stringWidth 800 chars ansi+emoji 4.73 µs/iter (4.71 µs … 4.88 µs) 4.72 µs 4.88 µs 4.88 µs
|
||||
Bun.stringWidth 8,000 chars ansi+emoji 47.02 µs/iter (46.37 µs … 67.44 µs) 46.96 µs 49.57 µs 49.63 µs
|
||||
Bun.stringWidth 40,000 chars ansi+emoji 234.45 µs/iter (231.78 µs … 240.98 µs) 234.92 µs 236.34 µs 236.62 µs
|
||||
Bun.stringWidth 19 chars ansi+emoji+ascii 135.46 ns/iter (133.67 ns … 143.26 ns) 135.32 ns 142.55 ns 142.77 ns
|
||||
Bun.stringWidth 190 chars ansi+emoji+ascii 1.17 µs/iter (1.16 µs … 1.17 µs) 1.17 µs 1.17 µs 1.17 µs
|
||||
Bun.stringWidth 1,900 chars ansi+emoji+ascii 11.45 µs/iter (11.26 µs … 20.41 µs) 11.45 µs 12.08 µs 12.11 µs
|
||||
Bun.stringWidth 19,000 chars ansi+emoji+ascii 114.06 µs/iter (112.86 µs … 120.06 µs) 114.25 µs 115.86 µs 116.15 µs
|
||||
Bun.stringWidth 95,000 chars ansi+emoji+ascii 572.69 µs/iter (565.52 µs … 607.22 µs) 572.45 µs 604.86 µs 605.21 µs
|
||||
```
|
||||
|
||||
```ts
|
||||
❯ node string-width.mjs
|
||||
cpu: 13th Gen Intel(R) Core(TM) i9-13900
|
||||
runtime: node v21.4.0 (x64-linux)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
-------------------------------------------------------------------------------------- -----------------------------
|
||||
npm/string-width 5 chars ascii 3.19 µs/iter (3.13 µs … 3.48 µs) 3.25 µs 3.48 µs 3.48 µs
|
||||
npm/string-width 50 chars ascii 20.09 µs/iter (18.93 µs … 435.06 µs) 19.49 µs 21.89 µs 22.59 µs
|
||||
npm/string-width 500 chars ascii 249.71 µs/iter (239.97 µs … 293.18 µs) 250.93 µs 276.7 µs 281.45 µs
|
||||
npm/string-width 5,000 chars ascii 6.69 ms/iter (6.58 ms … 6.76 ms) 6.72 ms 6.76 ms 6.76 ms
|
||||
npm/string-width 25,000 chars ascii 139.57 ms/iter (137.17 ms … 143.28 ms) 140.49 ms 143.28 ms 143.28 ms
|
||||
npm/string-width 7 chars ascii+emoji 3.7 µs/iter (3.62 µs … 3.94 µs) 3.73 µs 3.94 µs 3.94 µs
|
||||
npm/string-width 70 chars ascii+emoji 23.93 µs/iter (22.44 µs … 331.2 µs) 23.15 µs 25.98 µs 30.2 µs
|
||||
npm/string-width 700 chars ascii+emoji 251.65 µs/iter (237.78 µs … 444.69 µs) 252.92 µs 325.89 µs 354.08 µs
|
||||
npm/string-width 7,000 chars ascii+emoji 4.95 ms/iter (4.82 ms … 5.19 ms) 5 ms 5.04 ms 5.19 ms
|
||||
npm/string-width 35,000 chars ascii+emoji 96.93 ms/iter (94.39 ms … 102.58 ms) 97.68 ms 102.58 ms 102.58 ms
|
||||
npm/string-width 8 chars ansi+emoji 3.92 µs/iter (3.45 µs … 4.57 µs) 4.09 µs 4.57 µs 4.57 µs
|
||||
npm/string-width 80 chars ansi+emoji 24.46 µs/iter (22.87 µs … 4.2 ms) 23.54 µs 25.89 µs 27.41 µs
|
||||
npm/string-width 800 chars ansi+emoji 259.62 µs/iter (246.76 µs … 480.12 µs) 258.65 µs 349.84 µs 372.55 µs
|
||||
npm/string-width 8,000 chars ansi+emoji 5.46 ms/iter (5.41 ms … 5.57 ms) 5.48 ms 5.55 ms 5.57 ms
|
||||
npm/string-width 40,000 chars ansi+emoji 108.91 ms/iter (107.55 ms … 109.5 ms) 109.25 ms 109.5 ms 109.5 ms
|
||||
npm/string-width 19 chars ansi+emoji+ascii 6.53 µs/iter (6.35 µs … 6.75 µs) 6.54 µs 6.75 µs 6.75 µs
|
||||
npm/string-width 190 chars ansi+emoji+ascii 55.52 µs/iter (52.59 µs … 352.73 µs) 54.19 µs 80.77 µs 167.21 µs
|
||||
npm/string-width 1,900 chars ansi+emoji+ascii 701.71 µs/iter (653.94 µs … 893.78 µs) 715.3 µs 855.37 µs 872.9 µs
|
||||
npm/string-width 19,000 chars ansi+emoji+ascii 27.19 ms/iter (26.89 ms … 27.41 ms) 27.28 ms 27.41 ms 27.41 ms
|
||||
npm/string-width 95,000 chars ansi+emoji+ascii 3.68 s/iter (3.66 s … 3.7 s) 3.69 s 3.7 s 3.7 s
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
TypeScript definition:
|
||||
|
||||
```ts
|
||||
namespace Bun {
|
||||
export function stringWidth(
|
||||
/**
|
||||
* The string to measure
|
||||
*/
|
||||
input: string,
|
||||
options?: {
|
||||
/**
|
||||
* If `true`, count ANSI escape codes as part of the string width. If `false`, ANSI escape codes are ignored when calculating the string width.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
countAnsiEscapeCodes?: boolean;
|
||||
/**
|
||||
* When it's ambiugous and `true`, count emoji as 1 characters wide. If `false`, emoji are counted as 2 character wide.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
ambiguousIsNarrow?: boolean;
|
||||
},
|
||||
): number;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- ## `Bun.enableANSIColors()` -->
|
||||
|
||||
## `Bun.fileURLToPath()`
|
||||
|
||||
Converts a `file://` URL to an absolute path.
|
||||
|
||||
```ts
|
||||
const path = Bun.fileURLToPath(new URL("file:///foo/bar.txt"));
|
||||
console.log(path); // "/foo/bar.txt"
|
||||
```
|
||||
|
||||
## `Bun.pathToFileURL()`
|
||||
|
||||
Converts an absolute path to a `file://` URL.
|
||||
|
||||
```ts
|
||||
const url = Bun.pathToFileURL("/foo/bar.txt");
|
||||
console.log(url); // "file:///foo/bar.txt"
|
||||
```
|
||||
|
||||
<!-- Bun.hash; -->
|
||||
|
||||
## `Bun.gzipSync()`
|
||||
|
||||
Compresses a `Uint8Array` using zlib's GZIP algorithm.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello".repeat(100)); // Buffer extends Uint8Array
|
||||
const compressed = Bun.gzipSync(buf);
|
||||
|
||||
buf; // => Uint8Array(500)
|
||||
compressed; // => Uint8Array(30)
|
||||
```
|
||||
|
||||
Optionally, pass a parameters object as the second argument:
|
||||
|
||||
{% details summary="zlib compression options"%}
|
||||
|
||||
```ts
|
||||
export type ZlibCompressionOptions = {
|
||||
/**
|
||||
* The compression level to use. Must be between `-1` and `9`.
|
||||
* - A value of `-1` uses the default compression level (Currently `6`)
|
||||
* - A value of `0` gives no compression
|
||||
* - A value of `1` gives least compression, fastest speed
|
||||
* - A value of `9` gives best compression, slowest speed
|
||||
*/
|
||||
level?: -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
||||
/**
|
||||
* How much memory should be allocated for the internal compression state.
|
||||
*
|
||||
* A value of `1` uses minimum memory but is slow and reduces compression ratio.
|
||||
*
|
||||
* A value of `9` uses maximum memory for optimal speed. The default is `8`.
|
||||
*/
|
||||
memLevel?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
||||
/**
|
||||
* The base 2 logarithm of the window size (the size of the history buffer).
|
||||
*
|
||||
* Larger values of this parameter result in better compression at the expense of memory usage.
|
||||
*
|
||||
* The following value ranges are supported:
|
||||
* - `9..15`: The output will have a zlib header and footer (Deflate)
|
||||
* - `-9..-15`: The output will **not** have a zlib header or footer (Raw Deflate)
|
||||
* - `25..31` (16+`9..15`): The output will have a gzip header and footer (gzip)
|
||||
*
|
||||
* The gzip header will have no file name, no extra data, no comment, no modification time (set to zero) and no header CRC.
|
||||
*/
|
||||
windowBits?:
|
||||
| -9
|
||||
| -10
|
||||
| -11
|
||||
| -12
|
||||
| -13
|
||||
| -14
|
||||
| -15
|
||||
| 9
|
||||
| 10
|
||||
| 11
|
||||
| 12
|
||||
| 13
|
||||
| 14
|
||||
| 15
|
||||
| 25
|
||||
| 26
|
||||
| 27
|
||||
| 28
|
||||
| 29
|
||||
| 30
|
||||
| 31;
|
||||
/**
|
||||
* Tunes the compression algorithm.
|
||||
*
|
||||
* - `Z_DEFAULT_STRATEGY`: For normal data **(Default)**
|
||||
* - `Z_FILTERED`: For data produced by a filter or predictor
|
||||
* - `Z_HUFFMAN_ONLY`: Force Huffman encoding only (no string match)
|
||||
* - `Z_RLE`: Limit match distances to one (run-length encoding)
|
||||
* - `Z_FIXED` prevents the use of dynamic Huffman codes
|
||||
*
|
||||
* `Z_RLE` is designed to be almost as fast as `Z_HUFFMAN_ONLY`, but give better compression for PNG image data.
|
||||
*
|
||||
* `Z_FILTERED` forces more Huffman coding and less string matching, it is
|
||||
* somewhat intermediate between `Z_DEFAULT_STRATEGY` and `Z_HUFFMAN_ONLY`.
|
||||
* Filtered data consists mostly of small values with a somewhat random distribution.
|
||||
*/
|
||||
strategy?: number;
|
||||
};
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
## `Bun.gunzipSync()`
|
||||
|
||||
Decompresses a `Uint8Array` using zlib's GUNZIP algorithm.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello".repeat(100)); // Buffer extends Uint8Array
|
||||
const compressed = Bun.gzipSync(buf);
|
||||
|
||||
const dec = new TextDecoder();
|
||||
const uncompressed = Bun.gunzipSync(compressed);
|
||||
dec.decode(uncompressed);
|
||||
// => "hellohellohello..."
|
||||
```
|
||||
|
||||
## `Bun.deflateSync()`
|
||||
|
||||
Compresses a `Uint8Array` using zlib's DEFLATE algorithm.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello".repeat(100));
|
||||
const compressed = Bun.deflateSync(buf);
|
||||
|
||||
buf; // => Buffer(500)
|
||||
compressed; // => Uint8Array(12)
|
||||
```
|
||||
|
||||
The second argument supports the same set of configuration options as [`Bun.gzipSync`](#bun-gzipsync).
|
||||
|
||||
## `Bun.inflateSync()`
|
||||
|
||||
Decompresses a `Uint8Array` using zlib's INFLATE algorithm.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello".repeat(100));
|
||||
const compressed = Bun.deflateSync(buf);
|
||||
|
||||
const dec = new TextDecoder();
|
||||
const decompressed = Bun.inflateSync(compressed);
|
||||
dec.decode(decompressed);
|
||||
// => "hellohellohello..."
|
||||
```
|
||||
|
||||
## `Bun.inspect()`
|
||||
|
||||
Serializes an object to a `string` exactly as it would be printed by `console.log`.
|
||||
|
||||
```ts
|
||||
const obj = { foo: "bar" };
|
||||
const str = Bun.inspect(obj);
|
||||
// => '{\nfoo: "bar" \n}'
|
||||
|
||||
const arr = new Uint8Array([1, 2, 3]);
|
||||
const str = Bun.inspect(arr);
|
||||
// => "Uint8Array(3) [ 1, 2, 3 ]"
|
||||
```
|
||||
|
||||
## `Bun.inspect.custom`
|
||||
|
||||
This is the symbol that Bun uses to implement `Bun.inspect`. You can override this to customize how your objects are printed. It is identical to `util.inspect.custom` in Node.js.
|
||||
|
||||
```ts
|
||||
class Foo {
|
||||
[Bun.inspect.custom]() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
console.log(foo); // => "foo"
|
||||
```
|
||||
|
||||
## `Bun.inspect.table(tabularData, properties, options)`
|
||||
|
||||
Format tabular data into a string. Like [`console.table`](https://developer.mozilla.org/en-US/docs/Web/API/console/table_static), except it returns a string rather than printing to the console.
|
||||
|
||||
```ts
|
||||
console.log(
|
||||
Bun.inspect.table([
|
||||
{ a: 1, b: 2, c: 3 },
|
||||
{ a: 4, b: 5, c: 6 },
|
||||
{ a: 7, b: 8, c: 9 },
|
||||
]),
|
||||
);
|
||||
//
|
||||
// ┌───┬───┬───┬───┐
|
||||
// │ │ a │ b │ c │
|
||||
// ├───┼───┼───┼───┤
|
||||
// │ 0 │ 1 │ 2 │ 3 │
|
||||
// │ 1 │ 4 │ 5 │ 6 │
|
||||
// │ 2 │ 7 │ 8 │ 9 │
|
||||
// └───┴───┴───┴───┘
|
||||
```
|
||||
|
||||
Additionally, you can pass an array of property names to display only a subset of properties.
|
||||
|
||||
```ts
|
||||
console.log(
|
||||
Bun.inspect.table(
|
||||
[
|
||||
{ a: 1, b: 2, c: 3 },
|
||||
{ a: 4, b: 5, c: 6 },
|
||||
],
|
||||
["a", "c"],
|
||||
),
|
||||
);
|
||||
//
|
||||
// ┌───┬───┬───┐
|
||||
// │ │ a │ c │
|
||||
// ├───┼───┼───┤
|
||||
// │ 0 │ 1 │ 3 │
|
||||
// │ 1 │ 4 │ 6 │
|
||||
// └───┴───┴───┘
|
||||
```
|
||||
|
||||
You can also conditionally enable ANSI colors by passing `{ colors: true }`.
|
||||
|
||||
```ts
|
||||
console.log(
|
||||
Bun.inspect.table(
|
||||
[
|
||||
{ a: 1, b: 2, c: 3 },
|
||||
{ a: 4, b: 5, c: 6 },
|
||||
],
|
||||
{
|
||||
colors: true,
|
||||
},
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
## `Bun.nanoseconds()`
|
||||
|
||||
Returns the number of nanoseconds since the current `bun` process started, as a `number`. Useful for high-precision timing and benchmarking.
|
||||
|
||||
```ts
|
||||
Bun.nanoseconds();
|
||||
// => 7288958
|
||||
```
|
||||
|
||||
## `Bun.readableStreamTo*()`
|
||||
|
||||
Bun implements a set of convenience functions for asynchronously consuming the body of a `ReadableStream` and converting it to various binary formats.
|
||||
|
||||
```ts
|
||||
const stream = (await fetch("https://bun.com")).body;
|
||||
stream; // => ReadableStream
|
||||
|
||||
await Bun.readableStreamToArrayBuffer(stream);
|
||||
// => ArrayBuffer
|
||||
|
||||
await Bun.readableStreamToBytes(stream);
|
||||
// => Uint8Array
|
||||
|
||||
await Bun.readableStreamToBlob(stream);
|
||||
// => Blob
|
||||
|
||||
await Bun.readableStreamToJSON(stream);
|
||||
// => object
|
||||
|
||||
await Bun.readableStreamToText(stream);
|
||||
// => string
|
||||
|
||||
// returns all chunks as an array
|
||||
await Bun.readableStreamToArray(stream);
|
||||
// => unknown[]
|
||||
|
||||
// returns all chunks as a FormData object (encoded as x-www-form-urlencoded)
|
||||
await Bun.readableStreamToFormData(stream);
|
||||
|
||||
// returns all chunks as a FormData object (encoded as multipart/form-data)
|
||||
await Bun.readableStreamToFormData(stream, multipartFormBoundary);
|
||||
```
|
||||
|
||||
## `Bun.resolveSync()`
|
||||
|
||||
Resolves a file path or module specifier using Bun's internal module resolution algorithm. The first argument is the path to resolve, and the second argument is the "root". If no match is found, an `Error` is thrown.
|
||||
|
||||
```ts
|
||||
Bun.resolveSync("./foo.ts", "/path/to/project");
|
||||
// => "/path/to/project/foo.ts"
|
||||
|
||||
Bun.resolveSync("zod", "/path/to/project");
|
||||
// => "/path/to/project/node_modules/zod/index.ts"
|
||||
```
|
||||
|
||||
To resolve relative to the current working directory, pass `process.cwd()` or `"."` as the root.
|
||||
|
||||
```ts
|
||||
Bun.resolveSync("./foo.ts", process.cwd());
|
||||
Bun.resolveSync("./foo.ts", "/path/to/project");
|
||||
```
|
||||
|
||||
To resolve relative to the directory containing the current file, pass `import.meta.dir`.
|
||||
|
||||
```ts
|
||||
Bun.resolveSync("./foo.ts", import.meta.dir);
|
||||
```
|
||||
|
||||
## `serialize` & `deserialize` in `bun:jsc`
|
||||
|
||||
To save a JavaScript value into an ArrayBuffer & back, use `serialize` and `deserialize` from the `"bun:jsc"` module.
|
||||
|
||||
```js
|
||||
import { serialize, deserialize } from "bun:jsc";
|
||||
|
||||
const buf = serialize({ foo: "bar" });
|
||||
const obj = deserialize(buf);
|
||||
console.log(obj); // => { foo: "bar" }
|
||||
```
|
||||
|
||||
Internally, [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) and [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) serialize and deserialize the same way. This exposes the underlying [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) to JavaScript as an ArrayBuffer.
|
||||
|
||||
## `estimateShallowMemoryUsageOf` in `bun:jsc`
|
||||
|
||||
The `estimateShallowMemoryUsageOf` function returns a best-effort estimate of the memory usage of an object in bytes, excluding the memory usage of properties or other objects it references. For accurate per-object memory usage, use `Bun.generateHeapSnapshot`.
|
||||
|
||||
```js
|
||||
import { estimateShallowMemoryUsageOf } from "bun:jsc";
|
||||
|
||||
const obj = { foo: "bar" };
|
||||
const usage = estimateShallowMemoryUsageOf(obj);
|
||||
console.log(usage); // => 16
|
||||
|
||||
const buffer = Buffer.alloc(1024 * 1024);
|
||||
estimateShallowMemoryUsageOf(buffer);
|
||||
// => 1048624
|
||||
|
||||
const req = new Request("https://bun.com");
|
||||
estimateShallowMemoryUsageOf(req);
|
||||
// => 167
|
||||
|
||||
const array = Array(1024).fill({ a: 1 });
|
||||
// Arrays are usually not stored contiguously in memory, so this will not return a useful value (which isn't a bug).
|
||||
estimateShallowMemoryUsageOf(array);
|
||||
// => 16
|
||||
```
|
||||
547
node_modules/bun-types/docs/api/websockets.md
generated
vendored
Normal file
547
node_modules/bun-types/docs/api/websockets.md
generated
vendored
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
`Bun.serve()` supports server-side WebSockets, with on-the-fly compression, TLS support, and a Bun-native publish-subscribe API.
|
||||
|
||||
{% callout %}
|
||||
|
||||
**⚡️ 7x more throughput** — Bun's WebSockets are fast. For a [simple chatroom](https://github.com/oven-sh/bun/tree/main/bench/websocket-server/README.md) on Linux x64, Bun can handle 7x more requests per second than Node.js + [`"ws"`](https://github.com/websockets/ws).
|
||||
|
||||
| Messages sent per second | Runtime | Clients |
|
||||
| ------------------------ | ------------------------------ | ------- |
|
||||
| ~700,000 | (`Bun.serve`) Bun v0.2.1 (x64) | 16 |
|
||||
| ~100,000 | (`ws`) Node v18.10.0 (x64) | 16 |
|
||||
|
||||
Internally Bun's WebSocket implementation is built on [uWebSockets](https://github.com/uNetworking/uWebSockets).
|
||||
{% /callout %}
|
||||
|
||||
## Start a WebSocket server
|
||||
|
||||
Below is a simple WebSocket server built with `Bun.serve`, in which all incoming requests are [upgraded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) to WebSocket connections in the `fetch` handler. The socket handlers are declared in the `websocket` parameter.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {
|
||||
// upgrade the request to a WebSocket
|
||||
if (server.upgrade(req)) {
|
||||
return; // do not return a Response
|
||||
}
|
||||
return new Response("Upgrade failed", { status: 500 });
|
||||
},
|
||||
websocket: {}, // handlers
|
||||
});
|
||||
```
|
||||
|
||||
The following WebSocket event handlers are supported:
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {}, // upgrade logic
|
||||
websocket: {
|
||||
message(ws, message) {}, // a message is received
|
||||
open(ws) {}, // a socket is opened
|
||||
close(ws, code, message) {}, // a socket is closed
|
||||
drain(ws) {}, // the socket is ready to receive more data
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="An API designed for speed" %}
|
||||
|
||||
In Bun, handlers are declared once per server, instead of per socket.
|
||||
|
||||
`ServerWebSocket` expects you to pass a `WebSocketHandler` object to the `Bun.serve()` method which has methods for `open`, `message`, `close`, `drain`, and `error`. This is different than the client-side `WebSocket` class which extends `EventTarget` (onmessage, onopen, onclose),
|
||||
|
||||
Clients tend to not have many socket connections open so an event-based API makes sense.
|
||||
|
||||
But servers tend to have **many** socket connections open, which means:
|
||||
|
||||
- Time spent adding/removing event listeners for each connection adds up
|
||||
- Extra memory spent on storing references to callbacks function for each connection
|
||||
- Usually, people create new functions for each connection, which also means more memory
|
||||
|
||||
So, instead of using an event-based API, `ServerWebSocket` expects you to pass a single object with methods for each event in `Bun.serve()` and it is reused for each connection.
|
||||
|
||||
This leads to less memory usage and less time spent adding/removing event listeners.
|
||||
{% /details %}
|
||||
|
||||
The first argument to each handler is the instance of `ServerWebSocket` handling the event. The `ServerWebSocket` class is a fast, Bun-native implementation of [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) with some additional features.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {}, // upgrade logic
|
||||
websocket: {
|
||||
message(ws, message) {
|
||||
ws.send(message); // echo back the message
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Sending messages
|
||||
|
||||
Each `ServerWebSocket` instance has a `.send()` method for sending messages to the client. It supports a range of input types.
|
||||
|
||||
```ts
|
||||
ws.send("Hello world"); // string
|
||||
ws.send(response.arrayBuffer()); // ArrayBuffer
|
||||
ws.send(new Uint8Array([1, 2, 3])); // TypedArray | DataView
|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
Once the upgrade succeeds, Bun will send a `101 Switching Protocols` response per the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). Additional `headers` can be attached to this `Response` in the call to `server.upgrade()`.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {
|
||||
const sessionId = await generateSessionId();
|
||||
server.upgrade(req, {
|
||||
headers: {
|
||||
"Set-Cookie": `SessionId=${sessionId}`,
|
||||
},
|
||||
});
|
||||
},
|
||||
websocket: {}, // handlers
|
||||
});
|
||||
```
|
||||
|
||||
### Contextual data
|
||||
|
||||
Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. This data is made available on the `ws.data` property inside the WebSocket handlers.
|
||||
|
||||
```ts
|
||||
type WebSocketData = {
|
||||
createdAt: number;
|
||||
channelId: string;
|
||||
authToken: string;
|
||||
};
|
||||
|
||||
// TypeScript: specify the type of `data`
|
||||
Bun.serve<WebSocketData>({
|
||||
fetch(req, server) {
|
||||
const cookies = new Bun.CookieMap(req.headers.get("cookie")!);
|
||||
|
||||
server.upgrade(req, {
|
||||
// this object must conform to WebSocketData
|
||||
data: {
|
||||
createdAt: Date.now(),
|
||||
channelId: new URL(req.url).searchParams.get("channelId"),
|
||||
authToken: cookies.get("X-Token"),
|
||||
},
|
||||
});
|
||||
|
||||
return undefined;
|
||||
},
|
||||
websocket: {
|
||||
// handler called when a message is received
|
||||
async message(ws, message) {
|
||||
const user = getUserFromToken(ws.data.authToken);
|
||||
|
||||
await saveMessageToDatabase({
|
||||
channel: ws.data.channelId,
|
||||
message: String(message),
|
||||
userId: user.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To connect to this server from the browser, create a new `WebSocket`.
|
||||
|
||||
```ts#browser.js
|
||||
const socket = new WebSocket("ws://localhost:3000/chat");
|
||||
|
||||
socket.addEventListener("message", event => {
|
||||
console.log(event.data);
|
||||
})
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Identifying users** — The cookies that are currently set on the page will be sent with the WebSocket upgrade request and available on `req.headers` in the `fetch` handler. Parse these cookies to determine the identity of the connecting user and set the value of `data` accordingly.
|
||||
{% /callout %}
|
||||
|
||||
### Pub/Sub
|
||||
|
||||
Bun's `ServerWebSocket` implementation implements a native publish-subscribe API for topic-based broadcasting. Individual sockets can `.subscribe()` to a topic (specified with a string identifier) and `.publish()` messages to all other subscribers to that topic (excluding itself). This topic-based broadcast API is similar to [MQTT](https://en.wikipedia.org/wiki/MQTT) and [Redis Pub/Sub](https://redis.io/topics/pubsub).
|
||||
|
||||
```ts
|
||||
const server = Bun.serve<{ username: string }>({
|
||||
fetch(req, server) {
|
||||
const url = new URL(req.url);
|
||||
if (url.pathname === "/chat") {
|
||||
console.log(`upgrade!`);
|
||||
const username = getUsernameFromReq(req);
|
||||
const success = server.upgrade(req, { data: { username } });
|
||||
return success
|
||||
? undefined
|
||||
: new Response("WebSocket upgrade error", { status: 400 });
|
||||
}
|
||||
|
||||
return new Response("Hello world");
|
||||
},
|
||||
websocket: {
|
||||
open(ws) {
|
||||
const msg = `${ws.data.username} has entered the chat`;
|
||||
ws.subscribe("the-group-chat");
|
||||
server.publish("the-group-chat", msg);
|
||||
},
|
||||
message(ws, message) {
|
||||
// this is a group chat
|
||||
// so the server re-broadcasts incoming message to everyone
|
||||
server.publish("the-group-chat", `${ws.data.username}: ${message}`);
|
||||
},
|
||||
close(ws) {
|
||||
const msg = `${ws.data.username} has left the chat`;
|
||||
ws.unsubscribe("the-group-chat");
|
||||
server.publish("the-group-chat", msg);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Listening on ${server.hostname}:${server.port}`);
|
||||
```
|
||||
|
||||
Calling `.publish(data)` will send the message to all subscribers of a topic _except_ the socket that called `.publish()`. To send a message to all subscribers of a topic, use the `.publish()` method on the `Server` instance.
|
||||
|
||||
```ts
|
||||
const server = Bun.serve({
|
||||
websocket: {
|
||||
// ...
|
||||
},
|
||||
});
|
||||
|
||||
// listen for some external event
|
||||
server.publish("the-group-chat", "Hello world");
|
||||
```
|
||||
|
||||
### Compression
|
||||
|
||||
Per-message [compression](https://websockets.readthedocs.io/en/stable/topics/compression.html) can be enabled with the `perMessageDeflate` parameter.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {}, // upgrade logic
|
||||
websocket: {
|
||||
// enable compression and decompression
|
||||
perMessageDeflate: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Compression can be enabled for individual messages by passing a `boolean` as the second argument to `.send()`.
|
||||
|
||||
```ts
|
||||
ws.send("Hello world", true);
|
||||
```
|
||||
|
||||
For fine-grained control over compression characteristics, refer to the [Reference](#reference).
|
||||
|
||||
### Backpressure
|
||||
|
||||
The `.send(message)` method of `ServerWebSocket` returns a `number` indicating the result of the operation.
|
||||
|
||||
- `-1` — The message was enqueued but there is backpressure
|
||||
- `0` — The message was dropped due to a connection issue
|
||||
- `1+` — The number of bytes sent
|
||||
|
||||
This gives you better control over backpressure in your server.
|
||||
|
||||
### Timeouts and limits
|
||||
|
||||
By default, Bun will close a WebSocket connection if it is idle for 120 seconds. This can be configured with the `idleTimeout` parameter.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {}, // upgrade logic
|
||||
websocket: {
|
||||
idleTimeout: 60, // 60 seconds
|
||||
|
||||
// ...
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Bun will also close a WebSocket connection if it receives a message that is larger than 16 MB. This can be configured with the `maxPayloadLength` parameter.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req, server) {}, // upgrade logic
|
||||
websocket: {
|
||||
maxPayloadLength: 1024 * 1024, // 1 MB
|
||||
|
||||
// ...
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Connect to a `Websocket` server
|
||||
|
||||
Bun implements the `WebSocket` class. To create a WebSocket client that connects to a `ws://` or `wss://` server, create an instance of `WebSocket`, as you would in the browser.
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000");
|
||||
```
|
||||
|
||||
In browsers, the cookies that are currently set on the page will be sent with the WebSocket upgrade request. This is a standard feature of the `WebSocket` API.
|
||||
|
||||
For convenience, Bun lets you setting custom headers directly in the constructor. This is a Bun-specific extension of the `WebSocket` standard. _This will not work in browsers._
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000", {
|
||||
headers: {
|
||||
// custom headers
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To add event listeners to the socket:
|
||||
|
||||
```ts
|
||||
// message is received
|
||||
socket.addEventListener("message", event => {});
|
||||
|
||||
// socket opened
|
||||
socket.addEventListener("open", event => {});
|
||||
|
||||
// socket closed
|
||||
socket.addEventListener("close", event => {});
|
||||
|
||||
// error handler
|
||||
socket.addEventListener("error", event => {});
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
namespace Bun {
|
||||
export function serve(params: {
|
||||
fetch: (req: Request, server: Server) => Response | Promise<Response>;
|
||||
websocket?: {
|
||||
message: (
|
||||
ws: ServerWebSocket,
|
||||
message: string | ArrayBuffer | Uint8Array,
|
||||
) => void;
|
||||
open?: (ws: ServerWebSocket) => void;
|
||||
close?: (ws: ServerWebSocket, code: number, reason: string) => void;
|
||||
error?: (ws: ServerWebSocket, error: Error) => void;
|
||||
drain?: (ws: ServerWebSocket) => void;
|
||||
|
||||
maxPayloadLength?: number; // default: 16 * 1024 * 1024 = 16 MB
|
||||
idleTimeout?: number; // default: 120 (seconds)
|
||||
backpressureLimit?: number; // default: 1024 * 1024 = 1 MB
|
||||
closeOnBackpressureLimit?: boolean; // default: false
|
||||
sendPings?: boolean; // default: true
|
||||
publishToSelf?: boolean; // default: false
|
||||
|
||||
perMessageDeflate?:
|
||||
| boolean
|
||||
| {
|
||||
compress?: boolean | Compressor;
|
||||
decompress?: boolean | Compressor;
|
||||
};
|
||||
};
|
||||
}): Server;
|
||||
}
|
||||
|
||||
type Compressor =
|
||||
| `"disable"`
|
||||
| `"shared"`
|
||||
| `"dedicated"`
|
||||
| `"3KB"`
|
||||
| `"4KB"`
|
||||
| `"8KB"`
|
||||
| `"16KB"`
|
||||
| `"32KB"`
|
||||
| `"64KB"`
|
||||
| `"128KB"`
|
||||
| `"256KB"`;
|
||||
|
||||
interface Server {
|
||||
pendingWebSockets: number;
|
||||
publish(
|
||||
topic: string,
|
||||
data: string | ArrayBufferView | ArrayBuffer,
|
||||
compress?: boolean,
|
||||
): number;
|
||||
upgrade(
|
||||
req: Request,
|
||||
options?: {
|
||||
headers?: HeadersInit;
|
||||
data?: any;
|
||||
},
|
||||
): boolean;
|
||||
}
|
||||
|
||||
interface ServerWebSocket {
|
||||
readonly data: any;
|
||||
readonly readyState: number;
|
||||
readonly remoteAddress: string;
|
||||
send(message: string | ArrayBuffer | Uint8Array, compress?: boolean): number;
|
||||
close(code?: number, reason?: string): void;
|
||||
subscribe(topic: string): void;
|
||||
unsubscribe(topic: string): void;
|
||||
publish(topic: string, message: string | ArrayBuffer | Uint8Array): void;
|
||||
isSubscribed(topic: string): boolean;
|
||||
cork(cb: (ws: ServerWebSocket) => void): void;
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
### `Bun.serve(params)`
|
||||
|
||||
{% param name="params" %}
|
||||
Configuration object for WebSocket server
|
||||
{% /param %}
|
||||
|
||||
{% param name=" fetch" %}
|
||||
`(req: Request, server: Server) => Response | Promise<Response>`
|
||||
|
||||
Call `server.upgrade(req)` to upgrade the request to a WebSocket connection. This method returns `true` if the upgrade succeeds, or `false` if the upgrade fails.
|
||||
{% /param %}
|
||||
|
||||
{% param name=" websocket" %}
|
||||
Configuration object for WebSocket server
|
||||
{% /param %}
|
||||
|
||||
{% param name=" message" %}
|
||||
`(ws: ServerWebSocket, message: string | ArrayBuffer | Uint8Array) => void`
|
||||
|
||||
This handler is called when a `WebSocket` receives a message.
|
||||
{% /param %}
|
||||
|
||||
{% param name=" open" %}
|
||||
`(ws: ServerWebSocket) => void`
|
||||
|
||||
This handler is called when a `WebSocket` is opened.
|
||||
{% /param %}
|
||||
|
||||
{% param name=" close" %}
|
||||
`(ws: ServerWebSocket, code: number, message: string) => void`
|
||||
|
||||
This handler is called when a `WebSocket` is closed.
|
||||
{% /param %}
|
||||
|
||||
{% param name=" drain" %}
|
||||
`(ws: ServerWebSocket) => void`
|
||||
|
||||
This handler is called when a `WebSocket` is ready to receive more data.
|
||||
{% /param %}
|
||||
|
||||
{% param name=" perMessageDeflate" %}
|
||||
`boolean | {\n compress?: boolean | Compressor;\n decompress?: boolean | Compressor \n}`
|
||||
|
||||
Enable per-message compression and decompression. This is a boolean value or an object with `compress` and `decompress` properties. Each property can be a boolean value or one of the following `Compressor` types:
|
||||
|
||||
- `"disable"`
|
||||
- `"shared"`
|
||||
- `"dedicated"`
|
||||
- `"3KB"`
|
||||
- `"4KB"`
|
||||
- `"8KB"`
|
||||
- `"16KB"`
|
||||
- `"32KB"`
|
||||
- `"64KB"`
|
||||
- `"128KB"`
|
||||
- `"256KB"`
|
||||
|
||||
{% /param %}
|
||||
|
||||
### `ServerWebSocket`
|
||||
|
||||
{% param name="readyState" %}
|
||||
`number`
|
||||
|
||||
The current state of the `WebSocket` connection. This is one of the following values:
|
||||
|
||||
- `0` `CONNECTING`
|
||||
- `1` `OPEN`
|
||||
- `2` `CLOSING`
|
||||
- `3` `CLOSED`
|
||||
|
||||
{% /param %}
|
||||
|
||||
{% param name="remoteAddress" %}
|
||||
|
||||
`string`
|
||||
|
||||
The remote address of the `WebSocket` connection
|
||||
{% /param %}
|
||||
|
||||
{% param name="data" %}
|
||||
The data associated with the `WebSocket` connection. This is set in the `server.upgrade()` call.
|
||||
{% /param %}
|
||||
|
||||
{% param name=".send()" %}
|
||||
`send(message: string | ArrayBuffer | Uint8Array, compress?: boolean): number`
|
||||
|
||||
Send a message to the client. Returns a `number` indicating the result of the operation.
|
||||
|
||||
- `-1`: the message was enqueued but there is backpressure
|
||||
- `0`: the message was dropped due to a connection issue
|
||||
- `1+`: the number of bytes sent
|
||||
|
||||
The `compress` argument will enable compression for this message, even if the `perMessageDeflate` option is disabled.
|
||||
{% /param %}
|
||||
|
||||
{% param name=".subscribe()" %}
|
||||
`subscribe(topic: string): void`
|
||||
|
||||
Subscribe to a topic
|
||||
{% /param %}
|
||||
|
||||
{% param name=".unsubscribe()" %}
|
||||
`unsubscribe(topic: string): void`
|
||||
|
||||
Unsubscribe from a topic
|
||||
{% /param %}
|
||||
|
||||
{% param name=".publish()" %}
|
||||
`publish(topic: string, data: string | ArrayBufferView | ArrayBuffer, compress?: boolean): number;`
|
||||
|
||||
Send a message to all subscribers of a topic
|
||||
{% /param %}
|
||||
|
||||
{% param name=".isSubscribed()" %}
|
||||
`isSubscribed(topic: string): boolean`
|
||||
|
||||
Check if the `WebSocket` is subscribed to a topic
|
||||
{% /param %}
|
||||
{% param name=".cork()" %}
|
||||
`cork(cb: (ws: ServerWebSocket) => void): void;`
|
||||
|
||||
Batch a set of operations on a `WebSocket` connection. The `message`, `open`, and `drain` callbacks are automatically corked, so
|
||||
you only need to call this if you are sending messages outside of those
|
||||
callbacks or in async functions.
|
||||
|
||||
```ts
|
||||
ws.cork((ws) => {
|
||||
ws.send("first");
|
||||
ws.send("second");
|
||||
ws.send("third");
|
||||
});
|
||||
```
|
||||
|
||||
{% /param %}
|
||||
|
||||
{% param name=".close()" %}
|
||||
`close(code?: number, message?: string): void`
|
||||
|
||||
Close the `WebSocket` connection
|
||||
{% /param %}
|
||||
|
||||
### `Server`
|
||||
|
||||
{% param name="pendingWebsockets" %}
|
||||
Number of in-flight `WebSocket` messages
|
||||
{% /param %}
|
||||
|
||||
{% param name=".publish()" %}
|
||||
`publish(topic: string, data: string | ArrayBufferView | ArrayBuffer, compress?: boolean): number;`
|
||||
|
||||
Send a message to all subscribers of a topic
|
||||
{% /param %}
|
||||
|
||||
{% param name=".upgrade()" %}
|
||||
`upgrade(req: Request): boolean`
|
||||
|
||||
Upgrade a request to a `WebSocket` connection. Returns `true` if the upgrade succeeds, or `false` if the upgrade fails.
|
||||
{% /param %} -->
|
||||
244
node_modules/bun-types/docs/api/workers.md
generated
vendored
Normal file
244
node_modules/bun-types/docs/api/workers.md
generated
vendored
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
{% callout %}
|
||||
**🚧** — The `Worker` API is still experimental and should not be considered ready for production.
|
||||
{% /callout %}
|
||||
|
||||
[`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) lets you start and communicate with a new JavaScript instance running on a separate thread while sharing I/O resources with the main thread.
|
||||
|
||||
Bun implements a minimal version of the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) with extensions that make it work better for server-side use cases. Like the rest of Bun, `Worker` in Bun support CommonJS, ES Modules, TypeScript, JSX, TSX and more out of the box. No extra build steps are necessary.
|
||||
|
||||
## Creating a `Worker`
|
||||
|
||||
Like in browsers, [`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) is a global. Use it to create a new worker thread.
|
||||
|
||||
### From the main thread
|
||||
|
||||
```js#Main_thread
|
||||
const worker = new Worker("./worker.ts");
|
||||
|
||||
worker.postMessage("hello");
|
||||
worker.onmessage = event => {
|
||||
console.log(event.data);
|
||||
};
|
||||
```
|
||||
|
||||
### Worker thread
|
||||
|
||||
```ts#worker.ts_(Worker_thread)
|
||||
// prevents TS errors
|
||||
declare var self: Worker;
|
||||
|
||||
self.onmessage = (event: MessageEvent) => {
|
||||
console.log(event.data);
|
||||
postMessage("world");
|
||||
};
|
||||
```
|
||||
|
||||
To prevent TypeScript errors when using `self`, add this line to the top of your worker file.
|
||||
|
||||
```ts
|
||||
declare var self: Worker;
|
||||
```
|
||||
|
||||
You can use `import` and `export` syntax in your worker code. Unlike in browsers, there's no need to specify `{type: "module"}` to use ES Modules.
|
||||
|
||||
To simplify error handling, the initial script to load is resolved at the time `new Worker(url)` is called.
|
||||
|
||||
```js
|
||||
const worker = new Worker("/not-found.js");
|
||||
// throws an error immediately
|
||||
```
|
||||
|
||||
The specifier passed to `Worker` is resolved relative to the project root (like typing `bun ./path/to/file.js`).
|
||||
|
||||
### `preload` - load modules before the worker starts
|
||||
|
||||
You can pass an array of module specifiers to the `preload` option to load modules before the worker starts. This is useful when you want to ensure some code is always loaded before the application starts, like loading OpenTelemetry, Sentry, DataDog, etc.
|
||||
|
||||
```js
|
||||
const worker = new Worker("./worker.ts", {
|
||||
preload: ["./load-sentry.js"],
|
||||
});
|
||||
```
|
||||
|
||||
Like the `--preload` CLI argument, the `preload` option is processed before the worker starts.
|
||||
|
||||
You can also pass a single string to the `preload` option:
|
||||
|
||||
```js
|
||||
const worker = new Worker("./worker.ts", {
|
||||
preload: "./load-sentry.js",
|
||||
});
|
||||
```
|
||||
|
||||
This feature was added in Bun v1.1.35.
|
||||
|
||||
### `blob:` URLs
|
||||
|
||||
As of Bun v1.1.13, you can also pass a `blob:` URL to `Worker`. This is useful for creating workers from strings or other sources.
|
||||
|
||||
```js
|
||||
const blob = new Blob(
|
||||
[
|
||||
`
|
||||
self.onmessage = (event: MessageEvent) => postMessage(event.data)`,
|
||||
],
|
||||
{
|
||||
type: "application/typescript",
|
||||
},
|
||||
);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const worker = new Worker(url);
|
||||
```
|
||||
|
||||
Like the rest of Bun, workers created from `blob:` URLs support TypeScript, JSX, and other file types out of the box. You can communicate it should be loaded via typescript either via `type` or by passing a `filename` to the `File` constructor.
|
||||
|
||||
```js
|
||||
const file = new File(
|
||||
[
|
||||
`
|
||||
self.onmessage = (event: MessageEvent) => postMessage(event.data)`,
|
||||
],
|
||||
"worker.ts",
|
||||
);
|
||||
const url = URL.createObjectURL(file);
|
||||
const worker = new Worker(url);
|
||||
```
|
||||
|
||||
### `"open"`
|
||||
|
||||
The `"open"` event is emitted when a worker is created and ready to receive messages. This can be used to send an initial message to a worker once it's ready. (This event does not exist in browsers.)
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
|
||||
worker.addEventListener("open", () => {
|
||||
console.log("worker is ready");
|
||||
});
|
||||
```
|
||||
|
||||
Messages are automatically enqueued until the worker is ready, so there is no need to wait for the `"open"` event to send messages.
|
||||
|
||||
## Messages with `postMessage`
|
||||
|
||||
To send messages, use [`worker.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) and [`self.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). This leverages the [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
|
||||
|
||||
```js
|
||||
// On the worker thread, `postMessage` is automatically "routed" to the parent thread.
|
||||
postMessage({ hello: "world" });
|
||||
|
||||
// On the main thread
|
||||
worker.postMessage({ hello: "world" });
|
||||
```
|
||||
|
||||
To receive messages, use the [`message` event handler](https://developer.mozilla.org/en-US/docs/Web/API/Worker/message_event) on the worker and main thread.
|
||||
|
||||
```js
|
||||
// Worker thread:
|
||||
self.addEventListener("message", event => {
|
||||
console.log(event.data);
|
||||
});
|
||||
// or use the setter:
|
||||
// self.onmessage = fn
|
||||
|
||||
// if on the main thread
|
||||
worker.addEventListener("message", event => {
|
||||
console.log(event.data);
|
||||
});
|
||||
// or use the setter:
|
||||
// worker.onmessage = fn
|
||||
```
|
||||
|
||||
## Terminating a worker
|
||||
|
||||
A `Worker` instance terminates automatically once it's event loop has no work left to do. Attaching a `"message"` listener on the global or any `MessagePort`s will keep the event loop alive. To forcefully terminate a `Worker`, call `worker.terminate()`.
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
|
||||
// ...some time later
|
||||
worker.terminate();
|
||||
```
|
||||
|
||||
This will cause the worker's to exit as soon as possible.
|
||||
|
||||
### `process.exit()`
|
||||
|
||||
A worker can terminate itself with `process.exit()`. This does not terminate the main process. Like in Node.js, `process.on('beforeExit', callback)` and `process.on('exit', callback)` are emitted on the worker thread (and not on the main thread), and the exit code is passed to the `"close"` event.
|
||||
|
||||
### `"close"`
|
||||
|
||||
The `"close"` event is emitted when a worker has been terminated. It can take some time for the worker to actually terminate, so this event is emitted when the worker has been marked as terminated. The `CloseEvent` will contain the exit code passed to `process.exit()`, or 0 if closed for other reasons.
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
|
||||
worker.addEventListener("close", event => {
|
||||
console.log("worker is being closed");
|
||||
});
|
||||
```
|
||||
|
||||
This event does not exist in browsers.
|
||||
|
||||
## Managing lifetime
|
||||
|
||||
By default, an active `Worker` will keep the main (spawning) process alive, so async tasks like `setTimeout` and promises will keep the process alive. Attaching `message` listeners will also keep the `Worker` alive.
|
||||
|
||||
### `worker.unref()`
|
||||
|
||||
To stop a running worker from keeping the process alive, call `worker.unref()`. This decouples the lifetime of the worker to the lifetime of the main process, and is equivalent to what Node.js' `worker_threads` does.
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
worker.unref();
|
||||
```
|
||||
|
||||
Note: `worker.unref()` is not available in browsers.
|
||||
|
||||
### `worker.ref()`
|
||||
|
||||
To keep the process alive until the `Worker` terminates, call `worker.ref()`. A ref'd worker is the default behavior, and still needs something going on in the event loop (such as a `"message"` listener) for the worker to continue running.
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
worker.unref();
|
||||
// later...
|
||||
worker.ref();
|
||||
```
|
||||
|
||||
Alternatively, you can also pass an `options` object to `Worker`:
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
|
||||
ref: false,
|
||||
});
|
||||
```
|
||||
|
||||
Note: `worker.ref()` is not available in browsers.
|
||||
|
||||
## Memory usage with `smol`
|
||||
|
||||
JavaScript instances can use a lot of memory. Bun's `Worker` supports a `smol` mode that reduces memory usage, at a cost of performance. To enable `smol` mode, pass `smol: true` to the `options` object in the `Worker` constructor.
|
||||
|
||||
```js
|
||||
const worker = new Worker("./i-am-smol.ts", {
|
||||
smol: true,
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="What does `smol` mode actually do?" %}
|
||||
Setting `smol: true` sets `JSC::HeapSize` to be `Small` instead of the default `Large`.
|
||||
{% /details %}
|
||||
|
||||
## `Bun.isMainThread`
|
||||
|
||||
You can check if you're in the main thread by checking `Bun.isMainThread`.
|
||||
|
||||
```ts
|
||||
if (Bun.isMainThread) {
|
||||
console.log("I'm the main thread");
|
||||
} else {
|
||||
console.log("I'm in a worker");
|
||||
}
|
||||
```
|
||||
|
||||
This is useful for conditionally running code based on whether you're in the main thread or not.
|
||||
120
node_modules/bun-types/docs/benchmarks.md
generated
vendored
Normal file
120
node_modules/bun-types/docs/benchmarks.md
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
Bun.js focuses on performance, developer experience, and compatibility with the JavaScript ecosystem.
|
||||
|
||||
## HTTP Requests
|
||||
|
||||
```ts
|
||||
// http.ts
|
||||
export default {
|
||||
port: 3000,
|
||||
fetch(request: Request) {
|
||||
return new Response("Hello World");
|
||||
},
|
||||
};
|
||||
|
||||
// bun ./http.ts
|
||||
```
|
||||
|
||||
| Requests per second | OS | CPU | Bun version |
|
||||
| ---------------------------------------------------------------------- | ----- | ------------------------------ | ----------- |
|
||||
| [260,000](https://twitter.com/jarredsumner/status/1512040623200616449) | macOS | Apple Silicon M1 Max | 0.0.76 |
|
||||
| [160,000](https://twitter.com/jarredsumner/status/1511988933587976192) | Linux | AMD Ryzen 5 3600 6-Core 2.2ghz | 0.0.76 |
|
||||
|
||||
{% details summary="See benchmark details" %}
|
||||
Measured with [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c) by running:
|
||||
|
||||
```bash
|
||||
$ ./http_load_test 20 127.0.0.1 3000
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
## File System
|
||||
|
||||
`cat` clone that runs [2x faster than GNU cat](https://twitter.com/jarredsumner/status/1511707890708586496) for large files on Linux
|
||||
|
||||
```js
|
||||
// cat.js
|
||||
import { resolve } from "path";
|
||||
import { write, stdout, file, argv } from "bun";
|
||||
|
||||
const path = resolve(argv.at(-1));
|
||||
|
||||
await write(
|
||||
// stdout is a Blob
|
||||
stdout,
|
||||
// file(path) returns a Blob - https://developer.mozilla.org/en-US/docs/Web/API/Blob
|
||||
file(path),
|
||||
);
|
||||
```
|
||||
|
||||
Run this with `bun cat.js /path/to/big/file`.
|
||||
|
||||
## Reading from standard input
|
||||
|
||||
```ts
|
||||
for await (const line of console) {
|
||||
// line of text from stdin
|
||||
console.log(line);
|
||||
}
|
||||
```
|
||||
|
||||
## React SSR
|
||||
|
||||
```js
|
||||
import { renderToReadableStream } from "react-dom/server";
|
||||
|
||||
const dt = new Intl.DateTimeFormat();
|
||||
|
||||
export default {
|
||||
port: 3000,
|
||||
async fetch(request: Request) {
|
||||
return new Response(
|
||||
await renderToReadableStream(
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello from React!</h1>
|
||||
<p>The date is {dt.format(new Date())}</p>
|
||||
</body>
|
||||
</html>,
|
||||
),
|
||||
);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Write to stdout with `console.write`:
|
||||
|
||||
```js
|
||||
// no trailing newline
|
||||
// works with strings and typed arrays
|
||||
console.write("Hello World!");
|
||||
```
|
||||
|
||||
There are some more examples in the [examples](./examples) folder.
|
||||
|
||||
PRs adding more examples are very welcome!
|
||||
|
||||
## Fast paths for Web APIs
|
||||
|
||||
Bun.js has fast paths for common use cases that make Web APIs live up to the performance demands of servers and CLIs.
|
||||
|
||||
`Bun.file(path)` returns a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that represents a lazily-loaded file.
|
||||
|
||||
When you pass a file blob to `Bun.write`, Bun automatically uses a faster system call:
|
||||
|
||||
```js
|
||||
const blob = Bun.file("input.txt");
|
||||
await Bun.write("output.txt", blob);
|
||||
```
|
||||
|
||||
On Linux, this uses the [`copy_file_range`](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) syscall and on macOS, this becomes `clonefile` (or [`fcopyfile`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/copyfile.3.html)).
|
||||
|
||||
`Bun.write` also supports [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. It automatically converts to a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
|
||||
|
||||
```js
|
||||
// Eventually, this will stream the response to disk but today it buffers
|
||||
await Bun.write("index.html", await fetch("https://example.com"));
|
||||
```
|
||||
42
node_modules/bun-types/docs/bun-flavored-toml.md
generated
vendored
Normal file
42
node_modules/bun-types/docs/bun-flavored-toml.md
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[TOML](https://toml.io/) is a minimal configuration file format designed to be easy for humans to read.
|
||||
|
||||
Bun implements a TOML parser with a few tweaks designed for better interoperability with INI files and with JavaScript.
|
||||
|
||||
### ; and # are comments
|
||||
|
||||
In Bun-flavored TOML, comments start with `#` or `;`
|
||||
|
||||
```ini
|
||||
# This is a comment
|
||||
; This is also a comment
|
||||
```
|
||||
|
||||
This matches the behavior of INI files.
|
||||
|
||||
In TOML, comments start with `#`
|
||||
|
||||
```toml
|
||||
# This is a comment
|
||||
```
|
||||
|
||||
### String escape characters
|
||||
|
||||
Bun-flavored adds a few more escape sequences to TOML to work better with JavaScript strings.
|
||||
|
||||
```
|
||||
# Bun-flavored TOML extras
|
||||
\x{XX} - ASCII (U+00XX)
|
||||
\u{x+} - unicode (U+0000000X) - (U+XXXXXXXX)
|
||||
\v - vertical tab
|
||||
|
||||
# Regular TOML
|
||||
\b - backspace (U+0008)
|
||||
\t - tab (U+0009)
|
||||
\n - linefeed (U+000A)
|
||||
\f - form feed (U+000C)
|
||||
\r - carriage return (U+000D)
|
||||
\" - quote (U+0022)
|
||||
\\ - backslash (U+005C)
|
||||
\uXXXX - unicode (U+XXXX)
|
||||
\UXXXXXXXX - unicode (U+XXXXXXXX)
|
||||
```
|
||||
1028
node_modules/bun-types/docs/bundler/css.md
generated
vendored
Normal file
1028
node_modules/bun-types/docs/bundler/css.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
145
node_modules/bun-types/docs/bundler/css_modules.md
generated
vendored
Normal file
145
node_modules/bun-types/docs/bundler/css_modules.md
generated
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
# CSS Modules
|
||||
|
||||
Bun's bundler also supports bundling [CSS modules](https://css-tricks.com/css-modules-part-1-need/) in addition to [regular CSS](/docs/bundler/css) with support for the following features:
|
||||
|
||||
- Automatically detecting CSS module files (`.module.css`) with zero configuration
|
||||
- Composition (`composes` property)
|
||||
- Importing CSS modules into JSX/TSX
|
||||
- Warnings/errors for invalid usages of CSS modules
|
||||
|
||||
A CSS module is a CSS file (with the `.module.css` extension) where are all class names and animations are scoped to the file. This helps you avoid class name collisions as CSS declarations are globally scoped by default.
|
||||
|
||||
Under the hood, Bun's bundler transforms locally scoped class names into unique identifiers.
|
||||
|
||||
## Getting started
|
||||
|
||||
Create a CSS file with the `.module.css` extension:
|
||||
|
||||
```css
|
||||
/* styles.module.css */
|
||||
.button {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* other-styles.module.css */
|
||||
.button {
|
||||
color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
You can then import this file, for example into a TSX file:
|
||||
|
||||
```tsx
|
||||
import styles from "./styles.module.css";
|
||||
import otherStyles from "./other-styles.module.css";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<button className={styles.button}>Red button!</button>
|
||||
<button className={otherStyles.button}>Blue button!</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The `styles` object from importing the CSS module file will be an object with all class names as keys and
|
||||
their unique identifiers as values:
|
||||
|
||||
```tsx
|
||||
import styles from "./styles.module.css";
|
||||
import otherStyles from "./other-styles.module.css";
|
||||
|
||||
console.log(styles);
|
||||
console.log(otherStyles);
|
||||
```
|
||||
|
||||
This will output:
|
||||
|
||||
```ts
|
||||
{
|
||||
button: "button_123";
|
||||
}
|
||||
|
||||
{
|
||||
button: "button_456";
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, the class names are unique to each file, avoiding any collisions!
|
||||
|
||||
### Composition
|
||||
|
||||
CSS modules allow you to _compose_ class selectors together. This lets you reuse style rules across multiple classes.
|
||||
|
||||
For example:
|
||||
|
||||
```css
|
||||
/* styles.module.css */
|
||||
.button {
|
||||
composes: background;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
Would be the same as writing:
|
||||
|
||||
```css
|
||||
.button {
|
||||
background-color: blue;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
There are a couple rules to keep in mind when using `composes`:
|
||||
|
||||
- A `composes` property must come before any regular CSS properties or declarations
|
||||
- You can only use `composes` on a **simple selector with a single class name**:
|
||||
|
||||
```css
|
||||
#button {
|
||||
/* Invalid! `#button` is not a class selector */
|
||||
composes: background;
|
||||
}
|
||||
|
||||
.button,
|
||||
.button-secondary {
|
||||
/* Invalid! `.button, .button-secondary` is not a simple selector */
|
||||
composes: background;
|
||||
}
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
### Composing from a separate CSS module file
|
||||
|
||||
You can also compose from a separate CSS module file:
|
||||
|
||||
```css
|
||||
/* background.module.css */
|
||||
.background {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
/* styles.module.css */
|
||||
.button {
|
||||
composes: background from "./background.module.css";
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
When composing classes from separate files, be sure that they do not contain the same properties.
|
||||
|
||||
The CSS module spec says that composing classes from separate files with conflicting properties is
|
||||
undefined behavior, meaning that the output may differ and be unreliable.
|
||||
{% /callout %}
|
||||
481
node_modules/bun-types/docs/bundler/executables.md
generated
vendored
Normal file
481
node_modules/bun-types/docs/bundler/executables.md
generated
vendored
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
Bun's bundler implements a `--compile` flag for generating a standalone binary from a TypeScript or JavaScript file.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```bash
|
||||
$ bun build ./cli.ts --compile --outfile mycli
|
||||
```
|
||||
|
||||
```ts#cli.ts
|
||||
console.log("Hello world!");
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
This bundles `cli.ts` into an executable that can be executed directly:
|
||||
|
||||
```
|
||||
$ ./mycli
|
||||
Hello world!
|
||||
```
|
||||
|
||||
All imported files and packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are supported.
|
||||
|
||||
## Cross-compile to other platforms
|
||||
|
||||
The `--target` flag lets you compile your standalone executable for a different operating system, architecture, or version of Bun than the machine you're running `bun build` on.
|
||||
|
||||
To build for Linux x64 (most servers):
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
|
||||
|
||||
# To support CPUs from before 2013, use the baseline version (nehalem)
|
||||
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp
|
||||
|
||||
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
|
||||
# modern is faster, but baseline is more compatible.
|
||||
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for Linux ARM64 (e.g. Graviton or Raspberry Pi):
|
||||
|
||||
```sh
|
||||
# Note: the default architecture is x64 if no architecture is specified.
|
||||
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for Windows x64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# To support CPUs from before 2013, use the baseline version (nehalem)
|
||||
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
|
||||
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# note: if no .exe extension is provided, Bun will automatically add it for Windows executables
|
||||
```
|
||||
|
||||
To build for macOS arm64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for macOS x64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
#### Supported targets
|
||||
|
||||
The order of the `--target` flag does not matter, as long as they're delimited by a `-`.
|
||||
|
||||
| --target | Operating System | Architecture | Modern | Baseline | Libc |
|
||||
| --------------------- | ---------------- | ------------ | ------ | -------- | ----- |
|
||||
| bun-linux-x64 | Linux | x64 | ✅ | ✅ | glibc |
|
||||
| bun-linux-arm64 | Linux | arm64 | ✅ | N/A | glibc |
|
||||
| bun-windows-x64 | Windows | x64 | ✅ | ✅ | - |
|
||||
| ~~bun-windows-arm64~~ | Windows | arm64 | ❌ | ❌ | - |
|
||||
| bun-darwin-x64 | macOS | x64 | ✅ | ✅ | - |
|
||||
| bun-darwin-arm64 | macOS | arm64 | ✅ | N/A | - |
|
||||
| bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
|
||||
| bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
|
||||
|
||||
On x64 platforms, Bun uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `-baseline` build of Bun is for older CPUs that don't support these optimizations. Normally, when you install Bun we automatically detect which version to use but this can be harder to do when cross-compiling since you might not know the target CPU. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.
|
||||
|
||||
## Build-time constants
|
||||
|
||||
Use the `--define` flag to inject build-time constants into your executable, such as version numbers, build timestamps, or configuration values:
|
||||
|
||||
```bash
|
||||
$ bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli
|
||||
```
|
||||
|
||||
These constants are embedded directly into your compiled binary at build time, providing zero runtime overhead and enabling dead code elimination optimizations.
|
||||
|
||||
{% callout type="info" %}
|
||||
For comprehensive examples and advanced patterns, see the [Build-time constants guide](/guides/runtime/build-time-constants).
|
||||
{% /callout %}
|
||||
|
||||
## Deploying to production
|
||||
|
||||
Compiled executables reduce memory usage and improve Bun's start time.
|
||||
|
||||
Normally, Bun reads and transpiles JavaScript and TypeScript files on `import` and `require`. This is part of what makes so much of Bun "just work", but it's not free. It costs time and memory to read files from disk, resolve file paths, parse, transpile, and print source code.
|
||||
|
||||
With compiled executables, you can move that cost from runtime to build-time.
|
||||
|
||||
When deploying to production, we recommend the following:
|
||||
|
||||
```sh
|
||||
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
### Bytecode compilation
|
||||
|
||||
To improve startup time, enable bytecode compilation:
|
||||
|
||||
```sh
|
||||
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
Using bytecode compilation, `tsc` starts 2x faster:
|
||||
|
||||
{% image src="https://github.com/user-attachments/assets/dc8913db-01d2-48f8-a8ef-ac4e984f9763" width="689" /%}
|
||||
|
||||
Bytecode compilation moves parsing overhead for large input files from runtime to bundle time. Your app starts faster, in exchange for making the `bun build` command a little slower. It doesn't obscure source code.
|
||||
|
||||
**Experimental:** Bytecode compilation is an experimental feature introduced in Bun v1.1.30. Only `cjs` format is supported (which means no top-level-await). Let us know if you run into any issues!
|
||||
|
||||
### What do these flags do?
|
||||
|
||||
The `--minify` argument optimizes the size of the transpiled output code. If you have a large application, this can save megabytes of space. For smaller applications, it might still improve start time a little.
|
||||
|
||||
The `--sourcemap` argument embeds a sourcemap compressed with zstd, so that errors & stacktraces point to their original locations instead of the transpiled location. Bun will automatically decompress & resolve the sourcemap when an error occurs.
|
||||
|
||||
The `--bytecode` argument enables bytecode compilation. Every time you run JavaScript code in Bun, JavaScriptCore (the engine) will compile your source code into bytecode. We can move this parsing work from runtime to bundle time, saving you startup time.
|
||||
|
||||
## Act as the Bun CLI
|
||||
|
||||
{% note %}
|
||||
|
||||
New in Bun v1.2.16
|
||||
|
||||
{% /note %}
|
||||
|
||||
You can run a standalone executable as if it were the `bun` CLI itself by setting the `BUN_BE_BUN=1` environment variable. When this variable is set, the executable will ignore its bundled entrypoint and instead expose all the features of Bun's CLI.
|
||||
|
||||
For example, consider an executable compiled from a simple script:
|
||||
|
||||
```sh
|
||||
$ cat such-bun.js
|
||||
console.log("you shouldn't see this");
|
||||
|
||||
$ bun build --compile ./such-bun.js
|
||||
[3ms] bundle 1 modules
|
||||
[89ms] compile such-bun
|
||||
```
|
||||
|
||||
Normally, running `./such-bun` with arguments would execute the script. However, with the `BUN_BE_BUN=1` environment variable, it acts just like the `bun` binary:
|
||||
|
||||
```sh
|
||||
# Executable runs its own entrypoint by default
|
||||
$ ./such-bun install
|
||||
you shouldn't see this
|
||||
|
||||
# With the env var, the executable acts like the `bun` CLI
|
||||
$ BUN_BE_BUN=1 ./such-bun install
|
||||
bun install v1.2.16-canary.1 (1d1db811)
|
||||
Checked 63 installs across 64 packages (no changes) [5.00ms]
|
||||
```
|
||||
|
||||
This is useful for building CLI tools on top of Bun that may need to install packages, bundle dependencies, run different or local files and more without needing to download a separate binary or install bun.
|
||||
|
||||
## Full-stack executables
|
||||
|
||||
{% note %}
|
||||
|
||||
New in Bun v1.2.17
|
||||
|
||||
{% /note %}
|
||||
|
||||
Bun's `--compile` flag can create standalone executables that contain both server and client code, making it ideal for full-stack applications. When you import an HTML file in your server code, Bun automatically bundles all frontend assets (JavaScript, CSS, etc.) and embeds them into the executable. When Bun sees the HTML import on the server, it kicks off a frontend build process to bundle JavaScript, CSS, and other assets.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#server.ts
|
||||
import { serve } from "bun";
|
||||
import index from "./index.html";
|
||||
|
||||
const server = serve({
|
||||
routes: {
|
||||
"/": index,
|
||||
"/api/hello": { GET: () => Response.json({ message: "Hello from API" }) },
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Server running at http://localhost:${server.port}`);
|
||||
```
|
||||
|
||||
```html#index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>My App</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
<script src="./app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js#app.js
|
||||
console.log("Hello from the client!");
|
||||
```
|
||||
|
||||
```css#styles.css
|
||||
body {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
To build this into a single executable:
|
||||
|
||||
```sh
|
||||
bun build --compile ./server.ts --outfile myapp
|
||||
```
|
||||
|
||||
This creates a self-contained binary that includes:
|
||||
|
||||
- Your server code
|
||||
- The Bun runtime
|
||||
- All frontend assets (HTML, CSS, JavaScript)
|
||||
- Any npm packages used by your server
|
||||
|
||||
The result is a single file that can be deployed anywhere without needing Node.js, Bun, or any dependencies installed. Just run:
|
||||
|
||||
```sh
|
||||
./myapp
|
||||
```
|
||||
|
||||
Bun automatically handles serving the frontend assets with proper MIME types and cache headers. The HTML import is replaced with a manifest object that `Bun.serve` uses to efficiently serve pre-bundled assets.
|
||||
|
||||
For more details on building full-stack applications with Bun, see the [full-stack guide](/docs/bundler/fullstack).
|
||||
|
||||
## Worker
|
||||
|
||||
To use workers in a standalone executable, add the worker's entrypoint to the CLI arguments:
|
||||
|
||||
```sh
|
||||
$ bun build --compile ./index.ts ./my-worker.ts --outfile myapp
|
||||
```
|
||||
|
||||
Then, reference the worker in your code:
|
||||
|
||||
```ts
|
||||
console.log("Hello from Bun!");
|
||||
|
||||
// Any of these will work:
|
||||
new Worker("./my-worker.ts");
|
||||
new Worker(new URL("./my-worker.ts", import.meta.url));
|
||||
new Worker(new URL("./my-worker.ts", import.meta.url).href);
|
||||
```
|
||||
|
||||
As of Bun v1.1.25, when you add multiple entrypoints to a standalone executable, they will be bundled separately into the executable.
|
||||
|
||||
In the future, we may automatically detect usages of statically-known paths in `new Worker(path)` and then bundle those into the executable, but for now, you'll need to add it to the shell command manually like the above example.
|
||||
|
||||
If you use a relative path to a file not included in the standalone executable, it will attempt to load that path from disk relative to the current working directory of the process (and then error if it doesn't exist).
|
||||
|
||||
## SQLite
|
||||
|
||||
You can use `bun:sqlite` imports with `bun build --compile`.
|
||||
|
||||
By default, the database is resolved relative to the current working directory of the process.
|
||||
|
||||
```js
|
||||
import db from "./my.db" with { type: "sqlite" };
|
||||
|
||||
console.log(db.query("select * from users LIMIT 1").get());
|
||||
```
|
||||
|
||||
That means if the executable is located at `/usr/bin/hello`, the user's terminal is located at `/home/me/Desktop`, it will look for `/home/me/Desktop/my.db`.
|
||||
|
||||
```
|
||||
$ cd /home/me/Desktop
|
||||
$ ./hello
|
||||
```
|
||||
|
||||
## Embed assets & files
|
||||
|
||||
Standalone executables support embedding files.
|
||||
|
||||
To embed files into an executable with `bun build --compile`, import the file in your code.
|
||||
|
||||
```ts
|
||||
// this becomes an internal file path
|
||||
import icon from "./icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
// Embedded files can be streamed from Response objects
|
||||
return new Response(file(icon));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Embedded files can be read using `Bun.file`'s functions or the Node.js `fs.readFile` function (in `"node:fs"`).
|
||||
|
||||
For example, to read the contents of the embedded file:
|
||||
|
||||
```js
|
||||
import icon from "./icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
const bytes = await file(icon).arrayBuffer();
|
||||
// await fs.promises.readFile(icon)
|
||||
// fs.readFileSync(icon)
|
||||
```
|
||||
|
||||
### Embed SQLite databases
|
||||
|
||||
If your application wants to embed a SQLite database, set `type: "sqlite"` in the import attribute and the `embed` attribute to `"true"`.
|
||||
|
||||
```js
|
||||
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };
|
||||
|
||||
console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());
|
||||
```
|
||||
|
||||
This database is read-write, but all changes are lost when the executable exits (since it's stored in memory).
|
||||
|
||||
### Embed N-API Addons
|
||||
|
||||
As of Bun v1.0.23, you can embed `.node` files into executables.
|
||||
|
||||
```js
|
||||
const addon = require("./addon.node");
|
||||
|
||||
console.log(addon.hello());
|
||||
```
|
||||
|
||||
Unfortunately, if you're using `@mapbox/node-pre-gyp` or other similar tools, you'll need to make sure the `.node` file is directly required or it won't bundle correctly.
|
||||
|
||||
### Embed directories
|
||||
|
||||
To embed a directory with `bun build --compile`, use a shell glob in your `bun build` command:
|
||||
|
||||
```sh
|
||||
$ bun build --compile ./index.ts ./public/**/*.png
|
||||
```
|
||||
|
||||
Then, you can reference the files in your code:
|
||||
|
||||
```ts
|
||||
import icon from "./public/assets/icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
// Embedded files can be streamed from Response objects
|
||||
return new Response(file(icon));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
This is honestly a workaround, and we expect to improve this in the future with a more direct API.
|
||||
|
||||
### Listing embedded files
|
||||
|
||||
To get a list of all embedded files, use `Bun.embeddedFiles`:
|
||||
|
||||
```js
|
||||
import "./icon.png" with { type: "file" };
|
||||
import { embeddedFiles } from "bun";
|
||||
|
||||
console.log(embeddedFiles[0].name); // `icon-${hash}.png`
|
||||
```
|
||||
|
||||
`Bun.embeddedFiles` returns an array of `Blob` objects which you can use to get the size, contents, and other properties of the files.
|
||||
|
||||
```ts
|
||||
embeddedFiles: Blob[]
|
||||
```
|
||||
|
||||
The list of embedded files excludes bundled source code like `.ts` and `.js` files.
|
||||
|
||||
#### Content hash
|
||||
|
||||
By default, embedded files have a content hash appended to their name. This is useful for situations where you want to serve the file from a URL or CDN and have fewer cache invalidation issues. But sometimes, this is unexpected and you might want the original name instead:
|
||||
|
||||
To disable the content hash, pass `--asset-naming` to `bun build --compile` like this:
|
||||
|
||||
```sh
|
||||
$ bun build --compile --asset-naming="[name].[ext]" ./index.ts
|
||||
```
|
||||
|
||||
## Minification
|
||||
|
||||
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
|
||||
|
||||
## Windows-specific flags
|
||||
|
||||
When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file:
|
||||
|
||||
- `--windows-icon=path/to/icon.ico` to customize the executable file icon.
|
||||
- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY.
|
||||
|
||||
{% callout %}
|
||||
|
||||
These flags currently cannot be used when cross-compiling because they depend on Windows APIs.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Code signing on macOS
|
||||
|
||||
To codesign a standalone executable on macOS (which fixes Gatekeeper warnings), use the `codesign` command.
|
||||
|
||||
```sh
|
||||
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp
|
||||
```
|
||||
|
||||
We recommend including an `entitlements.plist` file with JIT permissions.
|
||||
|
||||
```xml#entitlements.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
To codesign with JIT support, pass the `--entitlements` flag to `codesign`.
|
||||
|
||||
```sh
|
||||
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp
|
||||
```
|
||||
|
||||
After codesigning, verify the executable:
|
||||
|
||||
```sh
|
||||
$ codesign -vvv --verify ./myapp
|
||||
./myapp: valid on disk
|
||||
./myapp: satisfies its Designated Requirement
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
Codesign support requires Bun v1.2.4 or newer.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Unsupported CLI arguments
|
||||
|
||||
Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
|
||||
|
||||
- `--outdir` — use `outfile` instead.
|
||||
- `--splitting`
|
||||
- `--public-path`
|
||||
- `--target=node` or `--target=browser`
|
||||
- `--no-bundle` - we always bundle everything into the executable.
|
||||
418
node_modules/bun-types/docs/bundler/fullstack.md
generated
vendored
Normal file
418
node_modules/bun-types/docs/bundler/fullstack.md
generated
vendored
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
To get started, import HTML files and pass them to the `routes` option in `Bun.serve()`.
|
||||
|
||||
```ts
|
||||
import { sql, serve } from "bun";
|
||||
import dashboard from "./dashboard.html";
|
||||
import homepage from "./index.html";
|
||||
|
||||
const server = serve({
|
||||
routes: {
|
||||
// ** HTML imports **
|
||||
// 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.
|
||||
"/": homepage,
|
||||
// Bundle & route dashboard.html to "/dashboard"
|
||||
"/dashboard": dashboard,
|
||||
|
||||
// ** API endpoints ** (Bun v1.2.3+ required)
|
||||
"/api/users": {
|
||||
async GET(req) {
|
||||
const users = await sql`SELECT * FROM users`;
|
||||
return Response.json(users);
|
||||
},
|
||||
async POST(req) {
|
||||
const { name, email } = await req.json();
|
||||
const [user] =
|
||||
await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`;
|
||||
return Response.json(user);
|
||||
},
|
||||
},
|
||||
"/api/users/:id": async req => {
|
||||
const { id } = req.params;
|
||||
const [user] = await sql`SELECT * FROM users WHERE id = ${id}`;
|
||||
return Response.json(user);
|
||||
},
|
||||
},
|
||||
|
||||
// Enable development mode for:
|
||||
// - Detailed error messages
|
||||
// - Hot reloading (Bun v1.2.3+ required)
|
||||
development: true,
|
||||
|
||||
// Prior to v1.2.3, the `fetch` option was used to handle all API requests. It is now optional.
|
||||
// async fetch(req) {
|
||||
// // Return 404 for unmatched routes
|
||||
// return new Response("Not Found", { status: 404 });
|
||||
// },
|
||||
});
|
||||
|
||||
console.log(`Listening on ${server.url}`);
|
||||
```
|
||||
|
||||
```bash
|
||||
$ bun run app.ts
|
||||
```
|
||||
|
||||
## HTML imports are routes
|
||||
|
||||
The web starts with HTML, and so does Bun's fullstack dev server.
|
||||
|
||||
To specify entrypoints to your frontend, import HTML files into your JavaScript/TypeScript/TSX/JSX files.
|
||||
|
||||
```ts
|
||||
import dashboard from "./dashboard.html";
|
||||
import homepage from "./index.html";
|
||||
```
|
||||
|
||||
These HTML files are used as routes in Bun's dev server you can pass to `Bun.serve()`.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
routes: {
|
||||
"/": homepage,
|
||||
"/dashboard": dashboard,
|
||||
}
|
||||
|
||||
fetch(req) {
|
||||
// ... api requests
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
When you make a request to `/dashboard` or `/`, Bun automatically bundles the `<script>` and `<link>` tags in the HTML files, exposes them as static routes, and serves the result.
|
||||
|
||||
An index.html file like this:
|
||||
|
||||
```html#index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" href="./reset.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./sentry-and-preloads.ts"></script>
|
||||
<script type="module" src="./my-app.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Becomes something like this:
|
||||
|
||||
```html#index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" href="/index-[hash].css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/index-[hash].js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### How to use with React
|
||||
|
||||
To use React in your client-side code, import `react-dom/client` and render your app.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#src/backend.ts
|
||||
import dashboard from "../public/dashboard.html";
|
||||
import { serve } from "bun";
|
||||
|
||||
serve({
|
||||
routes: {
|
||||
"/": dashboard,
|
||||
},
|
||||
|
||||
async fetch(req) {
|
||||
// ...api requests
|
||||
return new Response("hello world");
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```ts#src/frontend.tsx
|
||||
import "./styles.css";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { App } from "./app.tsx";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const root = createRoot(document.getElementById("root"));
|
||||
root.render(<App />);
|
||||
});
|
||||
```
|
||||
|
||||
```html#public/dashboard.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dashboard</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="../src/frontend.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css#src/styles.css
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx#src/app.tsx
|
||||
export function App() {
|
||||
return <div>Hello World</div>;
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### Development mode
|
||||
|
||||
When building locally, enable development mode by setting `development: true` in `Bun.serve()`.
|
||||
|
||||
```js-diff
|
||||
import homepage from "./index.html";
|
||||
import dashboard from "./dashboard.html";
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
"/": homepage,
|
||||
"/dashboard": dashboard,
|
||||
}
|
||||
|
||||
+ development: true,
|
||||
|
||||
fetch(req) {
|
||||
// ... api requests
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
When `development` is `true`, Bun will:
|
||||
|
||||
- Include the `SourceMap` header in the response so that devtools can show the original source code
|
||||
- Disable minification
|
||||
- Re-bundle assets on each request to a .html file
|
||||
- Enable hot module reloading (unless `hmr: false` is set)
|
||||
|
||||
#### Echo console logs from browser to terminal
|
||||
|
||||
Bun.serve() supports echoing console logs from the browser to the terminal.
|
||||
|
||||
To enable this, pass `console: true` in the `development` object in `Bun.serve()`.
|
||||
|
||||
```ts
|
||||
import homepage from "./index.html";
|
||||
|
||||
Bun.serve({
|
||||
// development can also be an object.
|
||||
development: {
|
||||
// Enable Hot Module Reloading
|
||||
hmr: true,
|
||||
|
||||
// Echo console logs from the browser to the terminal
|
||||
console: true,
|
||||
},
|
||||
|
||||
routes: {
|
||||
"/": homepage,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
When `console: true` is set, Bun will stream console logs from the browser to the terminal. This reuses the existing WebSocket connection from HMR to send the logs.
|
||||
|
||||
#### Production mode
|
||||
|
||||
Hot reloading and `development: true` helps you iterate quickly, but in production, your server should be as fast as possible and have as few external dependencies as possible.
|
||||
|
||||
##### Ahead of time bundling (recommended)
|
||||
|
||||
As of Bun v1.2.17, you can use `Bun.build` or `bun build` to bundle your full-stack application ahead of time.
|
||||
|
||||
```sh
|
||||
$ bun build --target=bun --production --outdir=dist ./src/index.ts
|
||||
```
|
||||
|
||||
When Bun's bundler sees an HTML import from server-side code, it will bundle the referenced JavaScript/TypeScript/TSX/JSX and CSS files into a manifest object that Bun.serve() can use to serve the assets.
|
||||
|
||||
```ts
|
||||
import { serve } from "bun";
|
||||
import index from "./index.html";
|
||||
|
||||
serve({
|
||||
routes: { "/": index },
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="Internally, the `index` variable is a manifest object that looks something like this" %}
|
||||
|
||||
```json
|
||||
{
|
||||
"index": "./index.html",
|
||||
"files": [
|
||||
{
|
||||
"input": "index.html",
|
||||
"path": "./index-f2me3qnf.js",
|
||||
"loader": "js",
|
||||
"isEntry": true,
|
||||
"headers": {
|
||||
"etag": "eet6gn75",
|
||||
"content-type": "text/javascript;charset=utf-8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "index.html",
|
||||
"path": "./index.html",
|
||||
"loader": "html",
|
||||
"isEntry": true,
|
||||
"headers": {
|
||||
"etag": "r9njjakd",
|
||||
"content-type": "text/html;charset=utf-8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "index.html",
|
||||
"path": "./index-gysa5fmk.css",
|
||||
"loader": "css",
|
||||
"isEntry": true,
|
||||
"headers": {
|
||||
"etag": "50zb7x61",
|
||||
"content-type": "text/css;charset=utf-8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "logo.svg",
|
||||
"path": "./logo-kygw735p.svg",
|
||||
"loader": "file",
|
||||
"isEntry": false,
|
||||
"headers": {
|
||||
"etag": "kygw735p",
|
||||
"content-type": "application/octet-stream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "react.svg",
|
||||
"path": "./react-ck11dneg.svg",
|
||||
"loader": "file",
|
||||
"isEntry": false,
|
||||
"headers": {
|
||||
"etag": "ck11dneg",
|
||||
"content-type": "application/octet-stream"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
##### Runtime bundling
|
||||
|
||||
When adding a build step is too complicated, you can set `development: false` in `Bun.serve()`.
|
||||
|
||||
- Enable in-memory caching of bundled assets. Bun will bundle assets lazily on the first request to an `.html` file, and cache the result in memory until the server restarts.
|
||||
- Enables `Cache-Control` headers and `ETag` headers
|
||||
- Minifies JavaScript/TypeScript/TSX/JSX files
|
||||
|
||||
## Plugins
|
||||
|
||||
Bun's [bundler plugins](https://bun.com/docs/bundler/plugins) are also supported when bundling static routes.
|
||||
|
||||
To configure plugins for `Bun.serve`, add a `plugins` array in the `[serve.static]` section of your `bunfig.toml`.
|
||||
|
||||
### Using TailwindCSS in HTML routes
|
||||
|
||||
For example, enable TailwindCSS on your routes by installing and adding the `bun-plugin-tailwind` plugin:
|
||||
|
||||
```sh
|
||||
$ bun add bun-plugin-tailwind
|
||||
```
|
||||
|
||||
```toml#bunfig.toml
|
||||
[serve.static]
|
||||
plugins = ["bun-plugin-tailwind"]
|
||||
```
|
||||
|
||||
This will allow you to use TailwindCSS utility classes in your HTML and CSS files. All you need to do is import `tailwindcss` somewhere:
|
||||
|
||||
```html#index.html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" href="tailwindcss" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- the rest of your HTML... -->
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Or in your CSS:
|
||||
|
||||
```css#style.css
|
||||
@import "tailwindcss";
|
||||
```
|
||||
|
||||
### Custom plugins
|
||||
|
||||
Any JS file or module which exports a [valid bundler plugin object](https://bun.com/docs/bundler/plugins#usage) (essentially an object with a `name` and `setup` field) can be placed inside the `plugins` array:
|
||||
|
||||
```toml#bunfig.toml
|
||||
[serve.static]
|
||||
plugins = ["./my-plugin-implementation.ts"]
|
||||
```
|
||||
|
||||
Bun will lazily resolve and load each plugin and use them to bundle your routes.
|
||||
|
||||
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.
|
||||
|
||||
## How this works
|
||||
|
||||
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.
|
||||
|
||||
1. **`<script>` processing**
|
||||
- Transpiles TypeScript, JSX, and TSX in `<script>` tags
|
||||
- Bundles imported dependencies
|
||||
- Generates sourcemaps for debugging
|
||||
- Minifies when `development` is not `true` in `Bun.serve()`
|
||||
|
||||
```html
|
||||
<script type="module" src="./counter.tsx"></script>
|
||||
```
|
||||
|
||||
2. **`<link>` processing**
|
||||
- Processes CSS imports and `<link>` tags
|
||||
- Concatenates CSS files
|
||||
- Rewrites `url` and asset paths to include content-addressable hashes in URLs
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
```
|
||||
|
||||
3. **`<img>` & asset processing**
|
||||
- Links to assets are rewritten to include content-addressable hashes in URLs
|
||||
- Small assets in CSS files are inlined into `data:` URLs, reducing the total number of HTTP requests sent over the wire
|
||||
|
||||
4. **Rewrite HTML**
|
||||
- Combines all `<script>` tags into a single `<script>` tag with a content-addressable hash in the URL
|
||||
- Combines all `<link>` tags into a single `<link>` tag with a content-addressable hash in the URL
|
||||
- Outputs a new HTML file
|
||||
|
||||
5. **Serve**
|
||||
- All the output files from the bundler are exposed as static routes, using the same mechanism internally as when you pass a `Response` object to [`static` in `Bun.serve()`](/docs/api/http#static-routes).
|
||||
|
||||
This works similarly to how [`Bun.build` processes HTML files](/docs/bundler/html).
|
||||
|
||||
## This is a work in progress
|
||||
|
||||
- This doesn't support `bun build` yet. It also will in the future.
|
||||
234
node_modules/bun-types/docs/bundler/hmr.md
generated
vendored
Normal file
234
node_modules/bun-types/docs/bundler/hmr.md
generated
vendored
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
Hot Module Replacement (HMR) allows you to update modules in a running
|
||||
application without needing a full page reload. This preserves the application
|
||||
state and improves the development experience.
|
||||
|
||||
HMR is enabled by default when using Bun's full-stack development server.
|
||||
|
||||
## `import.meta.hot` API Reference
|
||||
|
||||
Bun implements a client-side HMR API modeled after [Vite's `import.meta.hot` API](https://vitejs.dev/guide/api-hmr.html). It can be checked for with `if (import.meta.hot)`, tree-shaking it in production
|
||||
|
||||
```ts
|
||||
if (import.meta.hot) {
|
||||
// HMR APIs are available.
|
||||
}
|
||||
```
|
||||
|
||||
However, **this check is often not needed** as Bun will dead-code-eliminate
|
||||
calls to all of the HMR APIs in production builds.
|
||||
|
||||
```ts
|
||||
// This entire function call will be removed in production!
|
||||
import.meta.hot.dispose(() => {
|
||||
console.log("dispose");
|
||||
});
|
||||
```
|
||||
|
||||
For this to work, Bun forces these APIs to be called without indirection. That means the following do not work:
|
||||
|
||||
```ts#invalid-hmr-usage.ts
|
||||
// INVALID: Assigning `hot` to a variable
|
||||
const hot = import.meta.hot;
|
||||
hot.accept();
|
||||
|
||||
// INVALID: Assigning `import.meta` to a variable
|
||||
const meta = import.meta;
|
||||
meta.hot.accept();
|
||||
console.log(meta.hot.data);
|
||||
|
||||
// INVALID: Passing to a function
|
||||
doSomething(import.meta.hot.dispose);
|
||||
|
||||
// OK: The full phrase "import.meta.hot.<API>" must be called directly:
|
||||
import.meta.hot.accept();
|
||||
|
||||
// OK: `data` can be passed to functions:
|
||||
doSomething(import.meta.hot.data);
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — The HMR API is still a work in progress. Some features are missing. HMR can be disabled in `Bun.serve` by setting the `development` option to `{ hmr: false }`.
|
||||
|
||||
{% endcallout %}
|
||||
|
||||
| | Method | Notes |
|
||||
| --- | ------------------ | --------------------------------------------------------------------- |
|
||||
| ✅ | `hot.accept()` | Indicate that a hot update can be replaced gracefully. |
|
||||
| ✅ | `hot.data` | Persist data between module evaluations. |
|
||||
| ✅ | `hot.dispose()` | Add a callback function to run when a module is about to be replaced. |
|
||||
| ❌ | `hot.invalidate()` | |
|
||||
| ✅ | `hot.on()` | Attach an event listener |
|
||||
| ✅ | `hot.off()` | Remove an event listener from `on`. |
|
||||
| ❌ | `hot.send()` | |
|
||||
| 🚧 | `hot.prune()` | **NOTE**: Callback is currently never called. |
|
||||
| ✅ | `hot.decline()` | No-op to match Vite's `import.meta.hot` |
|
||||
|
||||
### `import.meta.hot.accept()`
|
||||
|
||||
The `accept()` method indicates that a module can be hot-replaced. When called
|
||||
without arguments, it indicates that this module can be replaced simply by
|
||||
re-evaluating the file. After a hot update, importers of this module will be
|
||||
automatically patched.
|
||||
|
||||
```ts#index.ts
|
||||
import { getCount } from "./foo.ts";
|
||||
|
||||
console.log("count is ", getCount());
|
||||
|
||||
import.meta.hot.accept();
|
||||
|
||||
export function getNegativeCount() {
|
||||
return -getCount();
|
||||
}
|
||||
```
|
||||
|
||||
This creates a hot-reloading boundary for all of the files that `index.ts`
|
||||
imports. That means whenever `foo.ts` or any of its dependencies are saved, the
|
||||
update will bubble up to `index.ts` will re-evaluate. Files that import
|
||||
`index.ts` will then be patched to import the new version of
|
||||
`getNegativeCount()`. If only `index.ts` is updated, only the one file will be
|
||||
re-evaluated, and the counter in `foo.ts` is reused.
|
||||
|
||||
This may be used in combination with `import.meta.hot.data` to transfer state
|
||||
from the previous module to the new one.
|
||||
|
||||
When no modules call `import.meta.hot.accept()` (and there isn't React Fast
|
||||
Refresh or a plugin calling it for you), the page will reload when the file
|
||||
updates, and a console warning shows which files were invalidated. This warning
|
||||
is safe to ignore if it makes more sense to rely on full page reloads.
|
||||
|
||||
#### With callback
|
||||
|
||||
When provided one callback, `import.meta.hot.accept` will function how it does
|
||||
in Vite. Instead of patching the importers of this module, it will call the
|
||||
callback with the new module.
|
||||
|
||||
```ts
|
||||
export const count = 0;
|
||||
|
||||
import.meta.hot.accept(newModule => {
|
||||
if (newModule) {
|
||||
// newModule is undefined when SyntaxError happened
|
||||
console.log("updated: count is now ", newModule.count);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Prefer using `import.meta.hot.accept()` without an argument as it usually makes your code easier to understand.
|
||||
|
||||
#### Accepting other modules
|
||||
|
||||
```ts
|
||||
import { count } from "./foo";
|
||||
|
||||
import.meta.hot.accept("./foo", () => {
|
||||
if (!newModule) return;
|
||||
|
||||
console.log("updated: count is now ", count);
|
||||
});
|
||||
```
|
||||
|
||||
Indicates that a dependency's module can be accepted. When the dependency is updated, the callback will be called with the new module.
|
||||
|
||||
#### With multiple dependencies
|
||||
|
||||
```ts
|
||||
import.meta.hot.accept(["./foo", "./bar"], newModules => {
|
||||
// newModules is an array where each item corresponds to the updated module
|
||||
// or undefined if that module had a syntax error
|
||||
});
|
||||
```
|
||||
|
||||
Indicates that multiple dependencies' modules can be accepted. This variant accepts an array of dependencies, where the callback will receive the updated modules, and `undefined` for any that had errors.
|
||||
|
||||
### `import.meta.hot.data`
|
||||
|
||||
`import.meta.hot.data` maintains state between module instances during hot
|
||||
replacement, enabling data transfer from previous to new versions. When
|
||||
`import.meta.hot.data` is written into, Bun will also mark this module as
|
||||
capable of self-accepting (equivalent of calling `import.meta.hot.accept()`).
|
||||
|
||||
```ts
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { App } from "./app";
|
||||
|
||||
const root = import.meta.hot.data.root ??= createRoot(elem);
|
||||
root.render(<App />); // re-use an existing root
|
||||
```
|
||||
|
||||
In production, `data` is inlined to be `{}`, meaning it cannot be used as a state holder.
|
||||
|
||||
The above pattern is recommended for stateful modules because Bun knows it can minify `{}.prop ??= value` into `value` in production.
|
||||
|
||||
### `import.meta.hot.dispose()`
|
||||
|
||||
Attaches an on-dispose callback. This is called:
|
||||
|
||||
- Just before the module is replaced with another copy (before the next is loaded)
|
||||
- After the module is detached (removing all imports to this module, see `import.meta.hot.prune()`)
|
||||
|
||||
```ts
|
||||
const sideEffect = setupSideEffect();
|
||||
|
||||
import.meta.hot.dispose(() => {
|
||||
sideEffect.cleanup();
|
||||
});
|
||||
```
|
||||
|
||||
This callback is not called on route navigation or when the browser tab closes.
|
||||
|
||||
Returning a promise will delay module replacement until the module is disposed.
|
||||
All dispose callbacks are called in parallel.
|
||||
|
||||
### `import.meta.hot.prune()`
|
||||
|
||||
Attaches an on-prune callback. This is called when all imports to this module
|
||||
are removed, but the module was previously loaded.
|
||||
|
||||
This can be used to clean up resources that were created when the module was
|
||||
loaded. Unlike `import.meta.hot.dispose()`, this pairs much better with `accept`
|
||||
and `data` to manage stateful resources. A full example managing a `WebSocket`:
|
||||
|
||||
```ts
|
||||
import { something } from "./something";
|
||||
|
||||
// Initialize or re-use a WebSocket connection
|
||||
export const ws = (import.meta.hot.data.ws ??= new WebSocket(location.origin));
|
||||
|
||||
// If the module's import is removed, clean up the WebSocket connection.
|
||||
import.meta.hot.prune(() => {
|
||||
ws.close();
|
||||
});
|
||||
```
|
||||
|
||||
If `dispose` was used instead, the WebSocket would close and re-open on every
|
||||
hot update. Both versions of the code will prevent page reloads when imported
|
||||
files are updated.
|
||||
|
||||
### `import.meta.hot.on()` and `off()`
|
||||
|
||||
`on()` and `off()` are used to listen for events from the HMR runtime. Event names are prefixed with a prefix so that plugins do not conflict with each other.
|
||||
|
||||
```ts
|
||||
import.meta.hot.on("bun:beforeUpdate", () => {
|
||||
console.log("before a hot update");
|
||||
});
|
||||
```
|
||||
|
||||
When a file is replaced, all of its event listeners are automatically removed.
|
||||
|
||||
A list of all built-in events:
|
||||
|
||||
| Event | Emitted when |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `bun:beforeUpdate` | before a hot update is applied. |
|
||||
| `bun:afterUpdate` | after a hot update is applied. |
|
||||
| `bun:beforeFullReload` | before a full page reload happens. |
|
||||
| `bun:beforePrune` | before prune callbacks are called. |
|
||||
| `bun:invalidate` | when a module is invalidated with `import.meta.hot.invalidate()` |
|
||||
| `bun:error` | when a build or runtime error occurs |
|
||||
| `bun:ws:disconnect` | when the HMR WebSocket connection is lost. This can indicate the development server is offline. |
|
||||
| `bun:ws:connect` | when the HMR WebSocket connects or re-connects. |
|
||||
|
||||
For compatibility with Vite, the above events are also available via `vite:*` prefix instead of `bun:*`.
|
||||
349
node_modules/bun-types/docs/bundler/html.md
generated
vendored
Normal file
349
node_modules/bun-types/docs/bundler/html.md
generated
vendored
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
Bun's bundler has first-class support for HTML. Build static sites, landing pages, and web applications with zero configuration. Just point Bun at your HTML file and it handles everything else.
|
||||
|
||||
```html#index.html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<script src="./app.ts" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="./logo.png" />
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
To get started, pass HTML files to `bun`.
|
||||
|
||||
{% bunDevServerTerminal alt="bun ./index.html" path="./index.html" routes="" /%}
|
||||
|
||||
Bun's development server provides powerful features with zero configuration:
|
||||
|
||||
- **Automatic Bundling** - Bundles and serves your HTML, JavaScript, and CSS
|
||||
- **Multi-Entry Support** - Handles multiple HTML entry points and glob entry points
|
||||
- **Modern JavaScript** - TypeScript & JSX support out of the box
|
||||
- **Smart Configuration** - Reads `tsconfig.json` for paths, JSX options, experimental decorators, and more
|
||||
- **Plugins** - Plugins for TailwindCSS and more
|
||||
- **ESM & CommonJS** - Use ESM and CommonJS in your JavaScript, TypeScript, and JSX files
|
||||
- **CSS Bundling & Minification** - Bundles CSS from `<link>` tags and `@import` statements
|
||||
- **Asset Management**
|
||||
- Automatic copying & hashing of images and assets
|
||||
- Rewrites asset paths in JavaScript, CSS, and HTML
|
||||
|
||||
## Single Page Apps (SPA)
|
||||
|
||||
When you pass a single .html file to Bun, Bun will use it as a fallback route for all paths. This makes it perfect for single page apps that use client-side routing:
|
||||
|
||||
{% bunDevServerTerminal alt="bun index.html" path="index.html" routes="" /%}
|
||||
|
||||
Your React or other SPA will work out of the box — no configuration needed. All routes like `/about`, `/users/123`, etc. will serve the same HTML file, letting your client-side router handle the navigation.
|
||||
|
||||
```html#index.html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>My SPA</title>
|
||||
<script src="./app.tsx" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Multi-page apps (MPA)
|
||||
|
||||
Some projects have several separate routes or HTML files as entry points. To support multiple entry points, pass them all to `bun`
|
||||
|
||||
{% bunDevServerTerminal alt="bun ./index.html ./about.html" path="./index.html ./about.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
|
||||
|
||||
This will serve:
|
||||
|
||||
- `index.html` at `/`
|
||||
- `about.html` at `/about`
|
||||
|
||||
### Glob patterns
|
||||
|
||||
To specify multiple files, you can use glob patterns that end in `.html`:
|
||||
|
||||
{% bunDevServerTerminal alt="bun ./**/*.html" path="./**/*.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
|
||||
|
||||
### Path normalization
|
||||
|
||||
The base path is chosen from the longest common prefix among all the files.
|
||||
|
||||
{% bunDevServerTerminal alt="bun ./index.html ./about/index.html ./about/foo/index.html" path="./index.html ./about/index.html ./about/foo/index.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about/index.html\"}, {\"path\": \"/about/foo\", \"file\": \"./about/foo/index.html\"}]" /%}
|
||||
|
||||
## JavaScript, TypeScript, and JSX
|
||||
|
||||
Bun's transpiler natively implements JavaScript, TypeScript, and JSX support. [Learn more about loaders in Bun](/docs/bundler/loaders).
|
||||
|
||||
Bun's transpiler is also used at runtime.
|
||||
|
||||
### ES Modules & CommonJS
|
||||
|
||||
You can use ESM and CJS in your JavaScript, TypeScript, and JSX files. Bun will handle the transpilation and bundling automatically.
|
||||
|
||||
There is no pre-build or separate optimization step. It's all done at the same time.
|
||||
|
||||
Learn more about [module resolution in Bun](/docs/runtime/modules).
|
||||
|
||||
## CSS
|
||||
|
||||
Bun's CSS parser is also natively implemented (clocking in around 58,000 lines of Zig).
|
||||
|
||||
It's also a CSS bundler. You can use `@import` in your CSS files to import other CSS files.
|
||||
|
||||
For example:
|
||||
|
||||
```css#styles.css
|
||||
@import "./abc.css";
|
||||
|
||||
.container {
|
||||
background-color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
```css#abc.css
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
```
|
||||
|
||||
This outputs:
|
||||
|
||||
```css#styles.css
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
### Referencing local assets in CSS
|
||||
|
||||
You can reference local assets in your CSS files.
|
||||
|
||||
```css#styles.css
|
||||
body {
|
||||
background-image: url("./logo.png");
|
||||
}
|
||||
```
|
||||
|
||||
This will copy `./logo.png` to the output directory and rewrite the path in the CSS file to include a content hash.
|
||||
|
||||
```css#styles.css
|
||||
body {
|
||||
background-image: url("./logo-[ABC123].png");
|
||||
}
|
||||
```
|
||||
|
||||
### Importing CSS in JavaScript
|
||||
|
||||
To associate a CSS file with a JavaScript file, you can import it in your JavaScript file.
|
||||
|
||||
```ts#app.ts
|
||||
import "./styles.css";
|
||||
import "./more-styles.css";
|
||||
```
|
||||
|
||||
This generates `./app.css` and `./app.js` in the output directory. All CSS files imported from JavaScript will be bundled into a single CSS file per entry point. If you import the same CSS file from multiple JavaScript files, it will only be included once in the output CSS file.
|
||||
|
||||
## Plugins
|
||||
|
||||
The dev server supports plugins.
|
||||
|
||||
### Tailwind CSS
|
||||
|
||||
To use TailwindCSS, install the `bun-plugin-tailwind` plugin:
|
||||
|
||||
```bash
|
||||
# Or any npm client
|
||||
$ bun install --dev bun-plugin-tailwind
|
||||
```
|
||||
|
||||
Then, add the plugin to your `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[serve.static]
|
||||
plugins = ["bun-plugin-tailwind"]
|
||||
```
|
||||
|
||||
Then, reference TailwindCSS in your HTML via `<link>` tag, `@import` in CSS, or `import` in JavaScript.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```html#index.html
|
||||
<!-- Reference TailwindCSS in your HTML -->
|
||||
<link rel="stylesheet" href="tailwindcss" />
|
||||
```
|
||||
|
||||
```css#styles.css
|
||||
/* Import TailwindCSS in your CSS */
|
||||
@import "tailwindcss";
|
||||
```
|
||||
|
||||
```ts#app.ts
|
||||
/* Import TailwindCSS in your JavaScript */
|
||||
import "tailwindcss";
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
Only one of those are necessary, not all three.
|
||||
|
||||
### Echo console logs from browser to terminal
|
||||
|
||||
Bun's dev server supports streaming console logs from the browser to the terminal.
|
||||
|
||||
To enable, pass the `--console` CLI flag.
|
||||
|
||||
{% bunDevServerTerminal alt="bun ./index.html --console" path="./index.html --console" routes="" /%}
|
||||
|
||||
Each call to `console.log` or `console.error` will be broadcast to the terminal that started the server. This is useful to see errors from the browser in the same place you run your server. This is also useful for AI agents that watch terminal output.
|
||||
|
||||
Internally, this reuses the existing WebSocket connection from hot module reloading to send the logs.
|
||||
|
||||
### Edit files in the browser
|
||||
|
||||
Bun's frontend dev server has support for [Automatic Workspace Folders](https://chromium.googlesource.com/devtools/devtools-frontend/+/main/docs/ecosystem/automatic_workspace_folders.md) in Chrome DevTools, which lets you save edits to files in the browser.
|
||||
|
||||
{% image src="/images/bun-chromedevtools.gif" alt="Bun's frontend dev server has support for Automatic Workspace Folders in Chrome DevTools, which lets you save edits to files in the browser." /%}
|
||||
|
||||
{% details summary="How it works" %}
|
||||
|
||||
Bun's dev server automatically adds a `/.well-known/appspecific/com.chrome.devtools.json` route to the server.
|
||||
|
||||
This route returns a JSON object with the following shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"workspace": {
|
||||
"root": "/path/to/your/project",
|
||||
"uuid": "a-unique-identifier-for-this-workspace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For security reasons, this is only enabled when:
|
||||
|
||||
1. The request is coming from localhost, 127.0.0.1, or ::1.
|
||||
2. Hot Module Reloading is enabled.
|
||||
3. The `chromeDevToolsAutomaticWorkspaceFolders` flag is set to `true` or `undefined`.
|
||||
4. There are no other routes that match the request.
|
||||
|
||||
You can disable this by passing `development: { chromeDevToolsAutomaticWorkspaceFolders: false }` in `Bun.serve`'s options.
|
||||
|
||||
{% /details %}
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
While the server is running:
|
||||
|
||||
- `o + Enter` - Open in browser
|
||||
- `c + Enter` - Clear console
|
||||
- `q + Enter` (or Ctrl+C) - Quit server
|
||||
|
||||
## Build for Production
|
||||
|
||||
When you're ready to deploy, use `bun build` to create optimized production bundles:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```bash#CLI
|
||||
$ bun build ./index.html --minify --outdir=dist
|
||||
```
|
||||
|
||||
```ts#API
|
||||
Bun.build({
|
||||
entrypoints: ["./index.html"],
|
||||
outdir: "./dist",
|
||||
minify: {
|
||||
whitespace: true,
|
||||
identifiers: true,
|
||||
syntax: true,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
Currently, plugins are only supported through `Bun.build`'s API or through `bunfig.toml` with the frontend dev server - not yet supported in `bun build`'s CLI.
|
||||
|
||||
### Watch Mode
|
||||
|
||||
You can run `bun build --watch` to watch for changes and rebuild automatically. This works nicely for library development.
|
||||
|
||||
You've never seen a watch mode this fast.
|
||||
|
||||
### Plugin API
|
||||
|
||||
Need more control? Configure the bundler through the JavaScript API and use Bun's builtin `HTMLRewriter` to preprocess HTML.
|
||||
|
||||
```ts
|
||||
await Bun.build({
|
||||
entrypoints: ["./index.html"],
|
||||
outdir: "./dist",
|
||||
minify: true,
|
||||
|
||||
plugins: [
|
||||
{
|
||||
// A plugin that makes every HTML tag lowercase
|
||||
name: "lowercase-html-plugin",
|
||||
setup({ onLoad }) {
|
||||
const rewriter = new HTMLRewriter().on("*", {
|
||||
element(element) {
|
||||
element.tagName = element.tagName.toLowerCase();
|
||||
},
|
||||
text(element) {
|
||||
element.replace(element.text.toLowerCase());
|
||||
},
|
||||
});
|
||||
|
||||
onLoad({ filter: /\.html$/ }, async args => {
|
||||
const html = await Bun.file(args.path).text();
|
||||
|
||||
return {
|
||||
// Bun's bundler will scan the HTML for <script> tags, <link rel="stylesheet"> tags, and other assets
|
||||
// and bundle them automatically
|
||||
contents: rewriter.transform(html),
|
||||
loader: "html",
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## What Gets Processed?
|
||||
|
||||
Bun automatically handles all common web assets:
|
||||
|
||||
- Scripts (`<script src>`) are run through Bun's JavaScript/TypeScript/JSX bundler
|
||||
- Stylesheets (`<link rel="stylesheet">`) are run through Bun's CSS parser & bundler
|
||||
- Images (`<img>`, `<picture>`) are copied and hashed
|
||||
- Media (`<video>`, `<audio>`, `<source>`) are copied and hashed
|
||||
- Any `<link>` tag with an `href` attribute pointing to a local file is rewritten to the new path, and hashed
|
||||
|
||||
All paths are resolved relative to your HTML file, making it easy to organize your project however you want.
|
||||
|
||||
## This is a work in progress
|
||||
|
||||
- Need more plugins
|
||||
- Need more configuration options for things like asset handling
|
||||
- Need a way to configure CORS, headers, etc.
|
||||
|
||||
If you want to submit a PR, most of the [code is here](https://github.com/oven-sh/bun/blob/main/src/js/internal/html.ts). You could even copy paste that file into your project and use it as a starting point.
|
||||
|
||||
## How this works
|
||||
|
||||
This is a small wrapper around Bun's support for HTML imports in JavaScript.
|
||||
|
||||
### Adding a backend to your frontend
|
||||
|
||||
To add a backend to your frontend, you can use the `"routes"` option in `Bun.serve`.
|
||||
|
||||
Learn more in [the full-stack docs](/docs/bundler/fullstack).
|
||||
1634
node_modules/bun-types/docs/bundler/index.md
generated
vendored
Normal file
1634
node_modules/bun-types/docs/bundler/index.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
75
node_modules/bun-types/docs/bundler/intro.md
generated
vendored
Normal file
75
node_modules/bun-types/docs/bundler/intro.md
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<!-- This document is a work in progress. It's not currently included in the actual docs. -->
|
||||
|
||||
The goal of this document is to break down why bundling is necessary, how it works, and how the bundler became such a key part of modern JavaScript development. The content is not specific to Bun's bundler, but is rather aimed at anyone looking for a greater understanding of how bundlers work and, by extension, how most modern frameworks are implemented.
|
||||
|
||||
## What is bundling
|
||||
|
||||
With the adoption of ECMAScript modules (ESM), browsers can now resolve `import`/`export` statements in JavaScript files loaded via `<script>` tags.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```html#index.html
|
||||
<html>
|
||||
<head>
|
||||
<script type="module" src="/index.js" ></script>
|
||||
</head>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js#index.js
|
||||
import {sayHello} from "./hello.js";
|
||||
|
||||
sayHello();
|
||||
```
|
||||
|
||||
```js#hello.js
|
||||
export function sayHello() {
|
||||
console.log("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
When a user visits this website, the files are loaded in the following order:
|
||||
|
||||
{% image src="/images/module_loading_unbundled.png" /%}
|
||||
|
||||
{% callout %}
|
||||
**Relative imports** — Relative imports are resolved relative to the URL of the importing file. Because we're importing `./hello.js` from `/index.js`, the browser resolves it to `/hello.js`. If instead we'd imported `./hello.js` from `/src/index.js`, the browser would have resolved it to `/src/hello.js`.
|
||||
{% /callout %}
|
||||
|
||||
This approach works, it requires three round-trip HTTP requests before the browser is ready to render the page. On slow internet connections, this may add up to a non-trivial delay.
|
||||
|
||||
This example is extremely simplistic. A modern app may be loading dozens of modules from `node_modules`, each consisting of hundred of files. Loading each of these files with a separate HTTP request becomes untenable very quickly. While most of these requests will be running in parallel, the number of round-trip requests can still be very high; plus, there are limits on how many simultaneous requests a browser can make.
|
||||
|
||||
{% callout %}
|
||||
Some recent advances like modulepreload and HTTP/3 are intended to solve some of these problems, but at the moment bundling is still the most performant approach.
|
||||
{% /callout %}
|
||||
|
||||
The answer: bundling.
|
||||
|
||||
## Entrypoints
|
||||
|
||||
A bundler accepts an "entrypoint" to your source code (in this case, `/index.js`) and outputs a single file containing all of the code needed to run your app. If does so by parsing your source code, reading the `import`/`export` statements, and building a "module graph" of your app's dependencies.
|
||||
|
||||
{% image src="/images/bundling.png" /%}
|
||||
|
||||
We can now load `/bundle.js` from our `index.html` file and eliminate a round trip request, decreasing load times for our app.
|
||||
|
||||
{% image src="/images/module_loading_bundled.png" /%}
|
||||
|
||||
## Loaders
|
||||
|
||||
Bundlers typically have some set of built-in "loaders".
|
||||
|
||||
## Transpilation
|
||||
|
||||
The JavaScript files above are just that: plain JavaScript. They can be directly executed by any modern browser.
|
||||
|
||||
But modern tooling goes far beyond HTML, JavaScript, and CSS. JSX, TypeScript, and PostCSS/CSS-in-JS are all popular technologies that involve non-standard syntax that must be converted into vanilla JavaScript and CSS before if can be consumed by a browser.
|
||||
|
||||
## Chunking
|
||||
|
||||
## Module resolution
|
||||
|
||||
## Plugins
|
||||
361
node_modules/bun-types/docs/bundler/loaders.md
generated
vendored
Normal file
361
node_modules/bun-types/docs/bundler/loaders.md
generated
vendored
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
The Bun bundler implements a set of default loaders out of the box. As a rule of thumb, the bundler and the runtime both support the same set of file types out of the box.
|
||||
|
||||
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node` `.html`
|
||||
|
||||
Bun uses the file extension to determine which built-in _loader_ should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](https://bun.com/docs/bundler/plugins) that extend Bun with custom loaders.
|
||||
|
||||
You can explicitly specify which loader to use using the 'loader' import attribute.
|
||||
|
||||
```ts
|
||||
import my_toml from "./my_file" with { loader: "toml" };
|
||||
```
|
||||
|
||||
## Built-in loaders
|
||||
|
||||
### `js`
|
||||
|
||||
**JavaScript**. Default for `.cjs` and `.mjs`.
|
||||
|
||||
Parses the code and applies a set of default transforms like dead-code elimination and tree shaking. Note that Bun does not attempt to down-convert syntax at the moment.
|
||||
|
||||
### `jsx`
|
||||
|
||||
**JavaScript + JSX.**. Default for `.js` and `.jsx`.
|
||||
|
||||
Same as the `js` loader, but JSX syntax is supported. By default, JSX is down-converted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the TypeScript documentation [on JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) for more information.
|
||||
|
||||
### `ts`
|
||||
|
||||
**TypeScript loader**. Default for `.ts`, `.mts`, and `.cts`.
|
||||
|
||||
Strips out all TypeScript syntax, then behaves identically to the `js` loader. Bun does not perform typechecking.
|
||||
|
||||
### `tsx`
|
||||
|
||||
**TypeScript + JSX loader**. Default for `.tsx`. Transpiles both TypeScript and JSX to vanilla JavaScript.
|
||||
|
||||
### `json`
|
||||
|
||||
**JSON loader**. Default for `.json`.
|
||||
|
||||
JSON files can be directly imported.
|
||||
|
||||
```ts
|
||||
import pkg from "./package.json";
|
||||
pkg.name; // => "my-package"
|
||||
```
|
||||
|
||||
During bundling, the parsed JSON is inlined into the bundle as a JavaScript object.
|
||||
|
||||
```ts
|
||||
var pkg = {
|
||||
name: "my-package",
|
||||
// ... other fields
|
||||
};
|
||||
pkg.name;
|
||||
```
|
||||
|
||||
If a `.json` file is passed as an entrypoint to the bundler, it will be converted to a `.js` module that `export default`s the parsed object.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```json#Input
|
||||
{
|
||||
"name": "John Doe",
|
||||
"age": 35,
|
||||
"email": "johndoe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
```js#Output
|
||||
export default {
|
||||
name: "John Doe",
|
||||
age: 35,
|
||||
email: "johndoe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `toml`
|
||||
|
||||
**TOML loader**. Default for `.toml`.
|
||||
|
||||
TOML files can be directly imported. Bun will parse them with its fast native TOML parser.
|
||||
|
||||
```ts
|
||||
import config from "./bunfig.toml";
|
||||
config.logLevel; // => "debug"
|
||||
|
||||
// via import attribute:
|
||||
// import myCustomTOML from './my.config' with {type: "toml"};
|
||||
```
|
||||
|
||||
During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
|
||||
|
||||
```ts
|
||||
var config = {
|
||||
logLevel: "debug",
|
||||
// ...other fields
|
||||
};
|
||||
config.logLevel;
|
||||
```
|
||||
|
||||
If a `.toml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```toml#Input
|
||||
name = "John Doe"
|
||||
age = 35
|
||||
email = "johndoe@example.com"
|
||||
```
|
||||
|
||||
```js#Output
|
||||
export default {
|
||||
name: "John Doe",
|
||||
age: 35,
|
||||
email: "johndoe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `text`
|
||||
|
||||
**Text loader**. Default for `.txt`.
|
||||
|
||||
The contents of the text file are read and inlined into the bundle as a string.
|
||||
Text files can be directly imported. The file is read and returned as a string.
|
||||
|
||||
```ts
|
||||
import contents from "./file.txt";
|
||||
console.log(contents); // => "Hello, world!"
|
||||
|
||||
// To import an html file as text
|
||||
// The "type' attribute can be used to override the default loader.
|
||||
import html from "./index.html" with { type: "text" };
|
||||
```
|
||||
|
||||
When referenced during a build, the contents are inlined into the bundle as a string.
|
||||
|
||||
```ts
|
||||
var contents = `Hello, world!`;
|
||||
console.log(contents);
|
||||
```
|
||||
|
||||
If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the file contents.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```txt#Input
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
```js#Output
|
||||
export default "Hello, world!";
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `napi`
|
||||
|
||||
**Native addon loader**. Default for `.node`.
|
||||
|
||||
In the runtime, native addons can be directly imported.
|
||||
|
||||
```ts
|
||||
import addon from "./addon.node";
|
||||
console.log(addon);
|
||||
```
|
||||
|
||||
In the bundler, `.node` files are handled using the [`file`](#file) loader.
|
||||
|
||||
### `sqlite`
|
||||
|
||||
**SQLite loader**. `with { "type": "sqlite" }` import attribute
|
||||
|
||||
In the runtime and bundler, SQLite databases can be directly imported. This will load the database using [`bun:sqlite`](https://bun.com/docs/api/sqlite).
|
||||
|
||||
```ts
|
||||
import db from "./my.db" with { type: "sqlite" };
|
||||
```
|
||||
|
||||
This is only supported when the `target` is `bun`.
|
||||
|
||||
By default, the database is external to the bundle (so that you can potentially use a database loaded elsewhere), so the database file on-disk won't be bundled into the final output.
|
||||
|
||||
You can change this behavior with the `"embed"` attribute:
|
||||
|
||||
```ts
|
||||
// embed the database into the bundle
|
||||
import db from "./my.db" with { type: "sqlite", embed: "true" };
|
||||
```
|
||||
|
||||
When using a [standalone executable](https://bun.com/docs/bundler/executables), the database is embedded into the single-file executable.
|
||||
|
||||
Otherwise, the database to embed is copied into the `outdir` with a hashed filename.
|
||||
|
||||
### `html`
|
||||
|
||||
The html loader processes HTML files and bundles any referenced assets. It will:
|
||||
|
||||
- Bundle and hash referenced JavaScript files (`<script src="...">`)
|
||||
- Bundle and hash referenced CSS files (`<link rel="stylesheet" href="...">`)
|
||||
- Hash referenced images (`<img src="...">`)
|
||||
- Preserve external URLs (by default, anything starting with `http://` or `https://`)
|
||||
|
||||
For example, given this HTML file:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```html#src/index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<img src="./image.jpg" alt="Local image">
|
||||
<img src="https://example.com/image.jpg" alt="External image">
|
||||
<script type="module" src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
It will output a new HTML file with the bundled assets:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```html#dist/output.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<img src="./image-HASHED.jpg" alt="Local image">
|
||||
<img src="https://example.com/image.jpg" alt="External image">
|
||||
<script type="module" src="./output-ALSO-HASHED.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
Under the hood, it uses [`lol-html`](https://github.com/cloudflare/lol-html) to extract script and link tags as entrypoints, and other assets as external.
|
||||
|
||||
Currently, the list of selectors is:
|
||||
|
||||
- `audio[src]`
|
||||
- `iframe[src]`
|
||||
- `img[src]`
|
||||
- `img[srcset]`
|
||||
- `link:not([rel~='stylesheet']):not([rel~='modulepreload']):not([rel~='manifest']):not([rel~='icon']):not([rel~='apple-touch-icon'])[href]`
|
||||
- `link[as='font'][href], link[type^='font/'][href]`
|
||||
- `link[as='image'][href]`
|
||||
- `link[as='style'][href]`
|
||||
- `link[as='video'][href], link[as='audio'][href]`
|
||||
- `link[as='worker'][href]`
|
||||
- `link[rel='icon'][href], link[rel='apple-touch-icon'][href]`
|
||||
- `link[rel='manifest'][href]`
|
||||
- `link[rel='stylesheet'][href]`
|
||||
- `script[src]`
|
||||
- `source[src]`
|
||||
- `source[srcset]`
|
||||
- `video[poster]`
|
||||
- `video[src]`
|
||||
|
||||
{% callout %}
|
||||
|
||||
**HTML Loader Behavior in Different Contexts**
|
||||
|
||||
The `html` loader behaves differently depending on how it's used:
|
||||
|
||||
1. **Static Build:** When you run `bun build ./index.html`, Bun produces a static site with all assets bundled and hashed.
|
||||
|
||||
2. **Runtime:** When you run `bun run server.ts` (where `server.ts` imports an HTML file), Bun bundles assets on-the-fly during development, enabling features like hot module replacement.
|
||||
|
||||
3. **Full-stack Build:** When you run `bun build --target=bun server.ts` (where `server.ts` imports an HTML file), the import resolves to a manifest object that `Bun.serve` uses to efficiently serve pre-bundled assets in production.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
### `sh` loader
|
||||
|
||||
**Bun Shell loader**. Default for `.sh` files
|
||||
|
||||
This loader is used to parse [Bun Shell](https://bun.com/docs/runtime/shell) scripts. It's only supported when starting Bun itself, so it's not available in the bundler or in the runtime.
|
||||
|
||||
```sh
|
||||
$ bun run ./script.sh
|
||||
```
|
||||
|
||||
### `file`
|
||||
|
||||
**File loader**. Default for all unrecognized file types.
|
||||
|
||||
The file loader resolves the import as a _path/URL_ to the imported file. It's commonly used for referencing media or font assets.
|
||||
|
||||
```ts#logo.ts
|
||||
import logo from "./logo.svg";
|
||||
console.log(logo);
|
||||
```
|
||||
|
||||
_In the runtime_, Bun checks that the `logo.svg` file exists and converts it to an absolute path to the location of `logo.svg` on disk.
|
||||
|
||||
```bash
|
||||
$ bun run logo.ts
|
||||
/path/to/project/logo.svg
|
||||
```
|
||||
|
||||
_In the bundler_, things are slightly different. The file is copied into `outdir` as-is, and the import is resolved as a relative path pointing to the copied file.
|
||||
|
||||
```ts#Output
|
||||
var logo = "./logo.svg";
|
||||
console.log(logo);
|
||||
```
|
||||
|
||||
If a value is specified for `publicPath`, the import will use value as a prefix to construct an absolute path/URL.
|
||||
|
||||
{% table %}
|
||||
|
||||
- Public path
|
||||
- Resolved import
|
||||
|
||||
---
|
||||
|
||||
- `""` (default)
|
||||
- `/logo.svg`
|
||||
|
||||
---
|
||||
|
||||
- `"/assets"`
|
||||
- `/assets/logo.svg`
|
||||
|
||||
---
|
||||
|
||||
- `"https://cdn.example.com/"`
|
||||
- `https://cdn.example.com/logo.svg`
|
||||
|
||||
{% /table %}
|
||||
|
||||
{% callout %}
|
||||
The location and file name of the copied file is determined by the value of [`naming.asset`](https://bun.com/docs/bundler#naming).
|
||||
{% /callout %}
|
||||
This loader is copied into the `outdir` as-is. The name of the copied file is determined using the value of `naming.asset`.
|
||||
|
||||
{% details summary="Fixing TypeScript import errors" %}
|
||||
If you're using TypeScript, you may get an error like this:
|
||||
|
||||
```ts
|
||||
// TypeScript error
|
||||
// Cannot find module './logo.svg' or its corresponding type declarations.
|
||||
```
|
||||
|
||||
This can be fixed by creating `*.d.ts` file anywhere in your project (any name will work) with the following contents:
|
||||
|
||||
```ts
|
||||
declare module "*.svg" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
```
|
||||
|
||||
This tells TypeScript that any default imports from `.svg` should be treated as a string.
|
||||
{% /details %}
|
||||
329
node_modules/bun-types/docs/bundler/macros.md
generated
vendored
Normal file
329
node_modules/bun-types/docs/bundler/macros.md
generated
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
Macros are a mechanism for running JavaScript functions _at bundle-time_. The value returned from these functions are directly inlined into your bundle.
|
||||
|
||||
<!-- embed the result in your (browser) bundle. This is useful for things like embedding the current Git commit hash in your code, making fetch requests to your API at build-time, dead code elimination, and more. -->
|
||||
|
||||
As a toy example, consider this simple function that returns a random number.
|
||||
|
||||
```ts
|
||||
export function random() {
|
||||
return Math.random();
|
||||
}
|
||||
```
|
||||
|
||||
This is just a regular function in a regular file, but we can use it as a macro like so:
|
||||
|
||||
```ts#cli.tsx
|
||||
import { random } from './random.ts' with { type: 'macro' };
|
||||
|
||||
console.log(`Your random number is ${random()}`);
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** — Macros are indicated using [_import attribute_](https://github.com/tc39/proposal-import-attributes) syntax. If you haven't seen this syntax before, it's a Stage 3 TC39 proposal that lets you attach additional metadata to `import` statements.
|
||||
{% /callout %}
|
||||
|
||||
Now we'll bundle this file with `bun build`. The bundled file will be printed to stdout.
|
||||
|
||||
```bash
|
||||
$ bun build ./cli.tsx
|
||||
console.log(`Your random number is ${0.6805550949689833}`);
|
||||
```
|
||||
|
||||
As you can see, the source code of the `random` function occurs nowhere in the bundle. Instead, it is executed _during bundling_ and function call (`random()`) is replaced with the result of the function. Since the source code will never be included in the bundle, macros can safely perform privileged operations like reading from a database.
|
||||
|
||||
## When to use macros
|
||||
|
||||
If you have several build scripts for small things where you would otherwise have a one-off build script, bundle-time code execution can be easier to maintain. It lives with the rest of your code, it runs with the rest of the build, it is automatically parallelized, and if it fails, the build fails too.
|
||||
|
||||
If you find yourself running a lot of code at bundle-time though, consider running a server instead.
|
||||
|
||||
## Import attributes
|
||||
|
||||
Bun Macros are import statements annotated using either:
|
||||
|
||||
- `with { type: 'macro' }` — an [import attribute](https://github.com/tc39/proposal-import-attributes), a Stage 3 ECMA Scrd
|
||||
- `assert { type: 'macro' }` — an import assertion, an earlier incarnation of import attributes that has now been abandoned (but is [already supported](https://caniuse.com/mdn-javascript_statements_import_import_assertions) by a number of browsers and runtimes)
|
||||
|
||||
## Security considerations
|
||||
|
||||
Macros must explicitly be imported with `{ type: "macro" }` in order to be executed at bundle-time. These imports have no effect if they are not called, unlike regular JavaScript imports which may have side effects.
|
||||
|
||||
You can disable macros entirely by passing the `--no-macros` flag to Bun. It produces a build error like this:
|
||||
|
||||
```js
|
||||
error: Macros are disabled
|
||||
|
||||
foo();
|
||||
^
|
||||
./hello.js:3:1 53
|
||||
```
|
||||
|
||||
To reduce the potential attack surface for malicious packages, macros cannot be _invoked_ from inside `node_modules/**/*`. If a package attempts to invoke a macro, you'll see an error like this:
|
||||
|
||||
```js
|
||||
error: For security reasons, macros cannot be run from node_modules.
|
||||
|
||||
beEvil();
|
||||
^
|
||||
node_modules/evil/index.js:3:1 50
|
||||
```
|
||||
|
||||
Your application code can still import macros from `node_modules` and invoke them.
|
||||
|
||||
```ts
|
||||
import { macro } from "some-package" with { type: "macro" };
|
||||
|
||||
macro();
|
||||
```
|
||||
|
||||
## Export condition `"macro"`
|
||||
|
||||
When shipping a library containing a macro to `npm` or another package registry, use the `"macro"` [export condition](https://nodejs.org/api/packages.html#conditional-exports) to provide a special version of your package exclusively for the macro environment.
|
||||
|
||||
```jsonc#package.json
|
||||
{
|
||||
"name": "my-package",
|
||||
"exports": {
|
||||
"import": "./index.js",
|
||||
"require": "./index.js",
|
||||
"default": "./index.js",
|
||||
"macro": "./index.macro.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this configuration, users can consume your package at runtime or at bundle-time using the same import specifier:
|
||||
|
||||
```ts
|
||||
import pkg from "my-package"; // runtime import
|
||||
import { macro } from "my-package" with { type: "macro" }; // macro import
|
||||
```
|
||||
|
||||
The first import will resolve to `./node_modules/my-package/index.js`, while the second will be resolved by Bun's bundler to `./node_modules/my-package/index.macro.js`.
|
||||
|
||||
## Execution
|
||||
|
||||
When Bun's transpiler sees a macro import, it calls the function inside the transpiler using Bun's JavaScript runtime and converts the return value from JavaScript into an AST node. These JavaScript functions are called at bundle-time, not runtime.
|
||||
|
||||
Macros are executed synchronously in the transpiler during the visiting phase—before plugins and before the transpiler generates the AST. They are executed in the order they are imported. The transpiler will wait for the macro to finish executing before continuing. The transpiler will also `await` any `Promise` returned by a macro.
|
||||
|
||||
Bun's bundler is multi-threaded. As such, macros execute in parallel inside of multiple spawned JavaScript "workers".
|
||||
|
||||
## Dead code elimination
|
||||
|
||||
The bundler performs dead code elimination _after_ running and inlining macros. So given the following macro:
|
||||
|
||||
```ts#returnFalse.ts
|
||||
export function returnFalse() {
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
...then bundling the following file will produce an empty bundle, provided that the minify syntax option is enabled.
|
||||
|
||||
```ts
|
||||
import { returnFalse } from "./returnFalse.ts" with { type: "macro" };
|
||||
|
||||
if (returnFalse()) {
|
||||
console.log("This code is eliminated");
|
||||
}
|
||||
```
|
||||
|
||||
## Serializability
|
||||
|
||||
Bun's transpiler needs to be able to serialize the result of the macro so it can be inlined into the AST. All JSON-compatible data structures are supported:
|
||||
|
||||
```ts#macro.ts
|
||||
export function getObject() {
|
||||
return {
|
||||
foo: "bar",
|
||||
baz: 123,
|
||||
array: [ 1, 2, { nested: "value" }],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Macros can be async, or return `Promise` instances. Bun's transpiler will automatically `await` the `Promise` and inline the result.
|
||||
|
||||
```ts#macro.ts
|
||||
export async function getText() {
|
||||
return "async value";
|
||||
}
|
||||
```
|
||||
|
||||
The transpiler implements special logic for serializing common data formats like `Response`, `Blob`, `TypedArray`.
|
||||
|
||||
- `TypedArray`: Resolves to a base64-encoded string.
|
||||
- `Response`: Bun will read the `Content-Type` and serialize accordingly; for instance, a `Response` with type `application/json` will be automatically parsed into an object and `text/plain` will be inlined as a string. Responses with an unrecognized or `undefined` `type` will be base-64 encoded.
|
||||
- `Blob`: As with `Response`, the serialization depends on the `type` property.
|
||||
|
||||
The result of `fetch` is `Promise<Response>`, so it can be directly returned.
|
||||
|
||||
```ts#macro.ts
|
||||
export function getObject() {
|
||||
return fetch("https://bun.com")
|
||||
}
|
||||
```
|
||||
|
||||
Functions and instances of most classes (except those mentioned above) are not serializable.
|
||||
|
||||
```ts
|
||||
export function getText(url: string) {
|
||||
// this doesn't work!
|
||||
return () => {};
|
||||
}
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
Macros can accept inputs, but only in limited cases. The value must be statically known. For example, the following is not allowed:
|
||||
|
||||
```ts
|
||||
import { getText } from "./getText.ts" with { type: "macro" };
|
||||
|
||||
export function howLong() {
|
||||
// the value of `foo` cannot be statically known
|
||||
const foo = Math.random() ? "foo" : "bar";
|
||||
|
||||
const text = getText(`https://example.com/${foo}`);
|
||||
console.log("The page is ", text.length, " characters long");
|
||||
}
|
||||
```
|
||||
|
||||
However, if the value of `foo` is known at bundle-time (say, if it's a constant or the result of another macro) then it's allowed:
|
||||
|
||||
```ts
|
||||
import { getText } from "./getText.ts" with { type: "macro" };
|
||||
import { getFoo } from "./getFoo.ts" with { type: "macro" };
|
||||
|
||||
export function howLong() {
|
||||
// this works because getFoo() is statically known
|
||||
const foo = getFoo();
|
||||
const text = getText(`https://example.com/${foo}`);
|
||||
console.log("The page is", text.length, "characters long");
|
||||
}
|
||||
```
|
||||
|
||||
This outputs:
|
||||
|
||||
```ts
|
||||
function howLong() {
|
||||
console.log("The page is", 1322, "characters long");
|
||||
}
|
||||
export { howLong };
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Embed latest git commit hash
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#getGitCommitHash.ts
|
||||
export function getGitCommitHash() {
|
||||
const {stdout} = Bun.spawnSync({
|
||||
cmd: ["git", "rev-parse", "HEAD"],
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
return stdout.toString();
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
<!-- --target=browser so they can clearly see it's for browsers -->
|
||||
|
||||
When we build it, the `getGitCommitHash` is replaced with the result of calling the function:
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#input
|
||||
import { getGitCommitHash } from './getGitCommitHash.ts' with { type: 'macro' };
|
||||
|
||||
console.log(`The current Git commit hash is ${getGitCommitHash()}`);
|
||||
```
|
||||
|
||||
```bash#output
|
||||
console.log(`The current Git commit hash is 3ee3259104f`);
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
You're probably thinking "Why not just use `process.env.GIT_COMMIT_HASH`?" Well, you can do that too. But can you do this with an environment variable?
|
||||
|
||||
### Make `fetch()` requests at bundle-time
|
||||
|
||||
In this example, we make an outgoing HTTP request using `fetch()`, parse the HTML response using `HTMLRewriter`, and return an object containing the title and meta tags–all at bundle-time.
|
||||
|
||||
```ts
|
||||
export async function extractMetaTags(url: string) {
|
||||
const response = await fetch(url);
|
||||
const meta = {
|
||||
title: "",
|
||||
};
|
||||
new HTMLRewriter()
|
||||
.on("title", {
|
||||
text(element) {
|
||||
meta.title += element.text;
|
||||
},
|
||||
})
|
||||
.on("meta", {
|
||||
element(element) {
|
||||
const name =
|
||||
element.getAttribute("name") ||
|
||||
element.getAttribute("property") ||
|
||||
element.getAttribute("itemprop");
|
||||
|
||||
if (name) meta[name] = element.getAttribute("content");
|
||||
},
|
||||
})
|
||||
.transform(response);
|
||||
|
||||
return meta;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- --target=browser so they can clearly see it's for browsers -->
|
||||
|
||||
The `extractMetaTags` function is erased at bundle-time and replaced with the result of the function call. This means that the `fetch` request happens at bundle-time, and the result is embedded in the bundle. Also, the branch throwing the error is eliminated since it's unreachable.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#input
|
||||
import { extractMetaTags } from './meta.ts' with { type: 'macro' };
|
||||
|
||||
export const Head = () => {
|
||||
const headTags = extractMetaTags("https://example.com");
|
||||
|
||||
if (headTags.title !== "Example Domain") {
|
||||
throw new Error("Expected title to be 'Example Domain'");
|
||||
}
|
||||
|
||||
return <head>
|
||||
<title>{headTags.title}</title>
|
||||
<meta name="viewport" content={headTags.viewport} />
|
||||
</head>;
|
||||
};
|
||||
```
|
||||
|
||||
```ts#output
|
||||
import { jsx, jsxs } from "react/jsx-runtime";
|
||||
export const Head = () => {
|
||||
jsxs("head", {
|
||||
children: [
|
||||
jsx("title", {
|
||||
children: "Example Domain",
|
||||
}),
|
||||
jsx("meta", {
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1",
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
export { Head };
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
400
node_modules/bun-types/docs/bundler/plugins.md
generated
vendored
Normal file
400
node_modules/bun-types/docs/bundler/plugins.md
generated
vendored
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
Bun provides a universal plugin API that can be used to extend both the _runtime_ and _bundler_.
|
||||
|
||||
Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.
|
||||
|
||||
## Lifecycle hooks
|
||||
|
||||
Plugins can register callbacks to be run at various points in the lifecycle of a bundle:
|
||||
|
||||
- [`onStart()`](#onstart): Run once the bundler has started a bundle
|
||||
- [`onResolve()`](#onresolve): Run before a module is resolved
|
||||
- [`onLoad()`](#onload): Run before a module is loaded.
|
||||
- [`onBeforeParse()`](#onbeforeparse): Run zero-copy native addons in the parser thread before a file is parsed.
|
||||
|
||||
### Reference
|
||||
|
||||
A rough overview of the types (please refer to Bun's `bun.d.ts` for the full type definitions):
|
||||
|
||||
```ts
|
||||
type PluginBuilder = {
|
||||
onStart(callback: () => void): void;
|
||||
onResolve: (
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
callback: (args: { path: string; importer: string }) => {
|
||||
path: string;
|
||||
namespace?: string;
|
||||
} | void,
|
||||
) => void;
|
||||
onLoad: (
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
defer: () => Promise<void>,
|
||||
callback: (args: { path: string }) => {
|
||||
loader?: Loader;
|
||||
contents?: string;
|
||||
exports?: Record<string, any>;
|
||||
},
|
||||
) => void;
|
||||
config: BuildConfig;
|
||||
};
|
||||
|
||||
type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml";
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function.
|
||||
|
||||
```tsx#myPlugin.ts
|
||||
import type { BunPlugin } from "bun";
|
||||
|
||||
const myPlugin: BunPlugin = {
|
||||
name: "Custom loader",
|
||||
setup(build) {
|
||||
// implementation
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
This plugin can be passed into the `plugins` array when calling `Bun.build`.
|
||||
|
||||
```ts
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./out",
|
||||
plugins: [myPlugin],
|
||||
});
|
||||
```
|
||||
|
||||
## Plugin lifecycle
|
||||
|
||||
### Namespaces
|
||||
|
||||
`onLoad` and `onResolve` accept an optional `namespace` string. What is a namespace?
|
||||
|
||||
Every module has a namespace. Namespaces are used to prefix the import in transpiled code; for instance, a loader with a `filter: /\.yaml$/` and `namespace: "yaml:"` will transform an import from `./myfile.yaml` into `yaml:./myfile.yaml`.
|
||||
|
||||
The default namespace is `"file"` and it is not necessary to specify it, for instance: `import myModule from "./my-module.ts"` is the same as `import myModule from "file:./my-module.ts"`.
|
||||
|
||||
Other common namespaces are:
|
||||
|
||||
- `"bun"`: for Bun-specific modules (e.g. `"bun:test"`, `"bun:sqlite"`)
|
||||
- `"node"`: for Node.js modules (e.g. `"node:fs"`, `"node:path"`)
|
||||
|
||||
### `onStart`
|
||||
|
||||
```ts
|
||||
onStart(callback: () => void): Promise<void> | void;
|
||||
```
|
||||
|
||||
Registers a callback to be run when the bundler starts a new bundle.
|
||||
|
||||
```ts
|
||||
import { plugin } from "bun";
|
||||
|
||||
plugin({
|
||||
name: "onStart example",
|
||||
|
||||
setup(build) {
|
||||
build.onStart(() => {
|
||||
console.log("Bundle started!");
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The callback can return a `Promise`. After the bundle process has initialized, the bundler waits until all `onStart()` callbacks have completed before continuing.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const result = await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
sourcemap: "external",
|
||||
plugins: [
|
||||
{
|
||||
name: "Sleep for 10 seconds",
|
||||
setup(build) {
|
||||
build.onStart(async () => {
|
||||
await Bunlog.sleep(10_000);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Log bundle time to a file",
|
||||
setup(build) {
|
||||
build.onStart(async () => {
|
||||
const now = Date.now();
|
||||
await Bun.$`echo ${now} > bundle-time.txt`;
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
In the above example, Bun will wait until the first `onStart()` (sleeping for 10 seconds) has completed, _as well as_ the second `onStart()` (writing the bundle time to a file).
|
||||
|
||||
Note that `onStart()` callbacks (like every other lifecycle callback) do not have the ability to modify the `build.config` object. If you want to mutate `build.config`, you must do so directly in the `setup()` function.
|
||||
|
||||
### `onResolve`
|
||||
|
||||
```ts
|
||||
onResolve(
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
callback: (args: { path: string; importer: string }) => {
|
||||
path: string;
|
||||
namespace?: string;
|
||||
} | void,
|
||||
): void;
|
||||
```
|
||||
|
||||
To bundle your project, Bun walks down the dependency tree of all modules in your project. For each imported module, Bun actually has to find and read that module. The "finding" part is known as "resolving" a module.
|
||||
|
||||
The `onResolve()` plugin lifecycle callback allows you to configure how a module is resolved.
|
||||
|
||||
The first argument to `onResolve()` is an object with a `filter` and [`namespace`](#what-is-a-namespace) property. The filter is a regular expression which is run on the import string. Effectively, these allow you to filter which modules your custom resolution logic will apply to.
|
||||
|
||||
The second argument to `onResolve()` is a callback which is run for each module import Bun finds that matches the `filter` and `namespace` defined in the first argument.
|
||||
|
||||
The callback receives as input the _path_ to the matching module. The callback can return a _new path_ for the module. Bun will read the contents of the _new path_ and parse it as a module.
|
||||
|
||||
For example, redirecting all imports to `images/` to `./public/images/`:
|
||||
|
||||
```ts
|
||||
import { plugin } from "bun";
|
||||
|
||||
plugin({
|
||||
name: "onResolve example",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /.*/, namespace: "file" }, args => {
|
||||
if (args.path.startsWith("images/")) {
|
||||
return {
|
||||
path: args.path.replace("images/", "./public/images/"),
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### `onLoad`
|
||||
|
||||
```ts
|
||||
onLoad(
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
defer: () => Promise<void>,
|
||||
callback: (args: { path: string, importer: string, namespace: string, kind: ImportKind }) => {
|
||||
loader?: Loader;
|
||||
contents?: string;
|
||||
exports?: Record<string, any>;
|
||||
},
|
||||
): void;
|
||||
```
|
||||
|
||||
After Bun's bundler has resolved a module, it needs to read the contents of the module and parse it.
|
||||
|
||||
The `onLoad()` plugin lifecycle callback allows you to modify the _contents_ of a module before it is read and parsed by Bun.
|
||||
|
||||
Like `onResolve()`, the first argument to `onLoad()` allows you to filter which modules this invocation of `onLoad()` will apply to.
|
||||
|
||||
The second argument to `onLoad()` is a callback which is run for each matching module _before_ Bun loads the contents of the module into memory.
|
||||
|
||||
This callback receives as input the _path_ to the matching module, the _importer_ of the module (the module that imported the module), the _namespace_ of the module, and the _kind_ of the module.
|
||||
|
||||
The callback can return a new `contents` string for the module as well as a new `loader`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import { plugin } from "bun";
|
||||
|
||||
const envPlugin: BunPlugin = {
|
||||
name: "env plugin",
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /env/, namespace: "file" }, args => {
|
||||
return {
|
||||
contents: `export default ${JSON.stringify(process.env)}`,
|
||||
loader: "js",
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
plugins: [envPlugin],
|
||||
});
|
||||
|
||||
// import env from "env"
|
||||
// env.FOO === "bar"
|
||||
```
|
||||
|
||||
This plugin will transform all imports of the form `import env from "env"` into a JavaScript module that exports the current environment variables.
|
||||
|
||||
#### `.defer()`
|
||||
|
||||
One of the arguments passed to the `onLoad` callback is a `defer` function. This function returns a `Promise` that is resolved when all _other_ modules have been loaded.
|
||||
|
||||
This allows you to delay execution of the `onLoad` callback until all other modules have been loaded.
|
||||
|
||||
This is useful for returning contents of a module that depends on other modules.
|
||||
|
||||
##### Example: tracking and reporting unused exports
|
||||
|
||||
```ts
|
||||
import { plugin } from "bun";
|
||||
|
||||
plugin({
|
||||
name: "track imports",
|
||||
setup(build) {
|
||||
const transpiler = new Bun.Transpiler();
|
||||
|
||||
let trackedImports: Record<string, number> = {};
|
||||
|
||||
// Each module that goes through this onLoad callback
|
||||
// will record its imports in `trackedImports`
|
||||
build.onLoad({ filter: /\.ts/ }, async ({ path }) => {
|
||||
const contents = await Bun.file(path).arrayBuffer();
|
||||
|
||||
const imports = transpiler.scanImports(contents);
|
||||
|
||||
for (const i of imports) {
|
||||
trackedImports[i.path] = (trackedImports[i.path] || 0) + 1;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
build.onLoad({ filter: /stats\.json/ }, async ({ defer }) => {
|
||||
// Wait for all files to be loaded, ensuring
|
||||
// that every file goes through the above `onLoad()` function
|
||||
// and their imports tracked
|
||||
await defer();
|
||||
|
||||
// Emit JSON containing the stats of each import
|
||||
return {
|
||||
contents: `export default ${JSON.stringify(trackedImports)}`,
|
||||
loader: "json",
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback.
|
||||
|
||||
## Native plugins
|
||||
|
||||
One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel.
|
||||
|
||||
However, one limitation of plugins written in JavaScript is that JavaScript itself is single-threaded.
|
||||
|
||||
Native plugins are written as [NAPI](https://bun.com/docs/api/node-api) modules and can be run on multiple threads. This allows native plugins to run much faster than JavaScript plugins.
|
||||
|
||||
In addition, native plugins can skip unnecessary work such as the UTF-8 -> UTF-16 conversion needed to pass strings to JavaScript.
|
||||
|
||||
These are the following lifecycle hooks which are available to native plugins:
|
||||
|
||||
- [`onBeforeParse()`](#onbeforeparse): Called on any thread before a file is parsed by Bun's bundler.
|
||||
|
||||
Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions.
|
||||
|
||||
To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement.
|
||||
|
||||
### Creating a native plugin in Rust
|
||||
|
||||
Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions.
|
||||
|
||||
To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement.
|
||||
|
||||
```bash
|
||||
bun add -g @napi-rs/cli
|
||||
napi new
|
||||
```
|
||||
|
||||
Then install this crate:
|
||||
|
||||
```bash
|
||||
cargo add bun-native-plugin
|
||||
```
|
||||
|
||||
Now, inside the `lib.rs` file, we'll use the `bun_native_plugin::bun` proc macro to define a function which
|
||||
will implement our native plugin.
|
||||
|
||||
Here's an example implementing the `onBeforeParse` hook:
|
||||
|
||||
```rs
|
||||
use bun_native_plugin::{define_bun_plugin, OnBeforeParse, bun, Result, anyhow, BunLoader};
|
||||
use napi_derive::napi;
|
||||
|
||||
/// Define the plugin and its name
|
||||
define_bun_plugin!("replace-foo-with-bar");
|
||||
|
||||
/// Here we'll implement `onBeforeParse` with code that replaces all occurrences of
|
||||
/// `foo` with `bar`.
|
||||
///
|
||||
/// We use the #[bun] macro to generate some of the boilerplate code.
|
||||
///
|
||||
/// The argument of the function (`handle: &mut OnBeforeParse`) tells
|
||||
/// the macro that this function implements the `onBeforeParse` hook.
|
||||
#[bun]
|
||||
pub fn replace_foo_with_bar(handle: &mut OnBeforeParse) -> Result<()> {
|
||||
// Fetch the input source code.
|
||||
let input_source_code = handle.input_source_code()?;
|
||||
|
||||
// Get the Loader for the file
|
||||
let loader = handle.output_loader();
|
||||
|
||||
|
||||
let output_source_code = input_source_code.replace("foo", "bar");
|
||||
|
||||
handle.set_output_source_code(output_source_code, BunLoader::BUN_LOADER_JSX);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
And to use it in Bun.build():
|
||||
|
||||
```typescript
|
||||
import myNativeAddon from "./my-native-addon";
|
||||
Bun.build({
|
||||
entrypoints: ["./app.tsx"],
|
||||
plugins: [
|
||||
{
|
||||
name: "my-plugin",
|
||||
|
||||
setup(build) {
|
||||
build.onBeforeParse(
|
||||
{
|
||||
namespace: "file",
|
||||
filter: "**/*.tsx",
|
||||
},
|
||||
{
|
||||
napiModule: myNativeAddon,
|
||||
symbol: "replace_foo_with_bar",
|
||||
// external: myNativeAddon.getSharedState()
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### `onBeforeParse`
|
||||
|
||||
```ts
|
||||
onBeforeParse(
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
callback: { napiModule: NapiModule; symbol: string; external?: unknown },
|
||||
): void;
|
||||
```
|
||||
|
||||
This lifecycle callback is run immediately before a file is parsed by Bun's bundler.
|
||||
|
||||
As input, it receives the file's contents and can optionally return new source code.
|
||||
|
||||
This callback can be called from any thread and so the napi module implementation must be thread-safe.
|
||||
1127
node_modules/bun-types/docs/bundler/vs-esbuild.md
generated
vendored
Normal file
1127
node_modules/bun-types/docs/bundler/vs-esbuild.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
173
node_modules/bun-types/docs/cli/add.md
generated
vendored
Normal file
173
node_modules/bun-types/docs/cli/add.md
generated
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
To add a particular package:
|
||||
|
||||
```bash
|
||||
$ bun add preact
|
||||
```
|
||||
|
||||
To specify a version, version range, or tag:
|
||||
|
||||
```bash
|
||||
$ bun add zod@3.20.0
|
||||
$ bun add zod@^3.0.0
|
||||
$ bun add zod@latest
|
||||
```
|
||||
|
||||
## `--dev`
|
||||
|
||||
{% callout %}
|
||||
**Alias** — `--development`, `-d`, `-D`
|
||||
{% /callout %}
|
||||
|
||||
To add a package as a dev dependency (`"devDependencies"`):
|
||||
|
||||
```bash
|
||||
$ bun add --dev @types/react
|
||||
$ bun add -d @types/react
|
||||
```
|
||||
|
||||
## `--optional`
|
||||
|
||||
To add a package as an optional dependency (`"optionalDependencies"`):
|
||||
|
||||
```bash
|
||||
$ bun add --optional lodash
|
||||
```
|
||||
|
||||
## `--peer`
|
||||
|
||||
To add a package as a peer dependency (`"peerDependencies"`):
|
||||
|
||||
```bash
|
||||
$ bun add --peer @types/bun
|
||||
```
|
||||
|
||||
## `--exact`
|
||||
|
||||
{% callout %}
|
||||
**Alias** — `-E`
|
||||
{% /callout %}
|
||||
|
||||
To add a package and pin to the resolved version, use `--exact`. This will resolve the version of the package and add it to your `package.json` with an exact version number instead of a version range.
|
||||
|
||||
```bash
|
||||
$ bun add react --exact
|
||||
$ bun add react -E
|
||||
```
|
||||
|
||||
This will add the following to your `package.json`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"dependencies": {
|
||||
// without --exact
|
||||
"react": "^18.2.0", // this matches >= 18.2.0 < 19.0.0
|
||||
|
||||
// with --exact
|
||||
"react": "18.2.0", // this matches only 18.2.0 exactly
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
To view a complete list of options for this command:
|
||||
|
||||
```bash
|
||||
$ bun add --help
|
||||
```
|
||||
|
||||
## `--global`
|
||||
|
||||
{% callout %}
|
||||
**Note** — This would not modify package.json of your current project folder.
|
||||
**Alias** - `bun add --global`, `bun add -g`, `bun install --global` and `bun install -g`
|
||||
{% /callout %}
|
||||
|
||||
To install a package globally, use the `-g`/`--global` flag. This will not modify the `package.json` of your current project. Typically this is used for installing command-line tools.
|
||||
|
||||
```bash
|
||||
$ bun add --global cowsay # or `bun add -g cowsay`
|
||||
$ cowsay "Bun!"
|
||||
______
|
||||
< Bun! >
|
||||
------
|
||||
\ ^__^
|
||||
\ (oo)\_______
|
||||
(__)\ )\/\
|
||||
||----w |
|
||||
|| ||
|
||||
```
|
||||
|
||||
{% details summary="Configuring global installation behavior" %}
|
||||
|
||||
```toml
|
||||
[install]
|
||||
# where `bun add --global` installs packages
|
||||
globalDir = "~/.bun/install/global"
|
||||
|
||||
# where globally-installed package bins are linked
|
||||
globalBinDir = "~/.bun/bin"
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
## Trusted dependencies
|
||||
|
||||
Unlike other npm clients, Bun does not execute arbitrary lifecycle scripts for installed dependencies, such as `postinstall`. These scripts represent a potential security risk, as they can execute arbitrary code on your machine.
|
||||
|
||||
To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
|
||||
|
||||
```json-diff
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
+ "trustedDependencies": ["my-trusted-package"]
|
||||
}
|
||||
```
|
||||
|
||||
Bun reads this field and will run lifecycle scripts for `my-trusted-package`.
|
||||
|
||||
<!-- Bun maintains an allow-list of popular packages containing `postinstall` scripts that are known to be safe. To run lifecycle scripts for packages that aren't on this list, add the package to `trustedDependencies` in your package.json. -->
|
||||
|
||||
## Git dependencies
|
||||
|
||||
To add a dependency from a public or private git repository:
|
||||
|
||||
```bash
|
||||
$ bun add git@github.com:moment/moment.git
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** — To install private repositories, your system needs the appropriate SSH credentials to access the repository.
|
||||
{% /callout %}
|
||||
|
||||
Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more.
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"dayjs": "git+https://github.com/iamkun/dayjs.git",
|
||||
"lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
|
||||
"moment": "git@github.com:moment/moment.git",
|
||||
"zod": "github:colinhacks/zod"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tarball dependencies
|
||||
|
||||
A package name can correspond to a publicly hosted `.tgz` file. During installation, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
|
||||
|
||||
```sh
|
||||
$ bun add zod@https://registry.npmjs.org/zod/-/zod-3.21.4.tgz
|
||||
```
|
||||
|
||||
This will add the following line to your `package.json`:
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"zod": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% bunCLIUsage command="add" /%}
|
||||
3
node_modules/bun-types/docs/cli/bun-completions.md
generated
vendored
Normal file
3
node_modules/bun-types/docs/cli/bun-completions.md
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
This command installs completions for `zsh` and/or `fish`. It runs automatically on every `bun upgrade` and on install. It reads from `$SHELL` to determine which shell to install for. It tries several common shell completion directories for your shell and OS.
|
||||
|
||||
If you want to copy the completions manually, run `bun completions > path-to-file`. If you know the completions directory to install them to, run `bun completions /path/to/directory`.
|
||||
338
node_modules/bun-types/docs/cli/bun-create.md
generated
vendored
Normal file
338
node_modules/bun-types/docs/cli/bun-create.md
generated
vendored
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
{% callout %}
|
||||
**Note** — You don’t need `bun create` to use Bun. You don’t need any configuration at all. This command exists to make getting started a bit quicker and easier.
|
||||
{% /callout %}
|
||||
|
||||
Template a new Bun project with `bun create`. This is a flexible command that can be used to create a new project from a React component, a `create-<template>` npm package, a GitHub repo, or a local template.
|
||||
|
||||
If you're looking to create a brand new empty project, use [`bun init`](https://bun.com/docs/cli/init).
|
||||
|
||||
## From a React component
|
||||
|
||||
`bun create ./MyComponent.tsx` turns an existing React component into a complete dev environment with hot reload and production builds in one command.
|
||||
|
||||
```bash
|
||||
$ bun create ./MyComponent.jsx # .tsx also supported
|
||||
```
|
||||
|
||||
{% raw %}
|
||||
|
||||
<video style="aspect-ratio: 2062 / 1344; width: 100%; height: 100%; object-fit: contain;" loop autoplay muted playsinline>
|
||||
<source src="/bun-create-shadcn.mp4" style="width: 100%; height: 100%; object-fit: contain;" type="video/mp4">
|
||||
</video>
|
||||
|
||||
{% /raw %}
|
||||
|
||||
{% callout %}
|
||||
🚀 **Create React App Successor** — `bun create <component>` provides everything developers loved about Create React App, but with modern tooling, faster builds, and backend support.
|
||||
{% /callout %}
|
||||
|
||||
#### How this works
|
||||
|
||||
When you run `bun create <component>`, Bun:
|
||||
|
||||
1. Uses [Bun's JavaScript bundler](https://bun.com/docs/bundler) to analyze your module graph.
|
||||
2. Collects all the dependencies needed to run the component.
|
||||
3. Scans the exports of the entry point for a React component.
|
||||
4. Generates a `package.json` file with the dependencies and scripts needed to run the component.
|
||||
5. Installs any missing dependencies using [`bun install --only-missing`](https://bun.com/docs/cli/install).
|
||||
6. Generates the following files:
|
||||
- `${component}.html`
|
||||
- `${component}.client.tsx` (entry point for the frontend)
|
||||
- `${component}.css` (css file)
|
||||
7. Starts a frontend dev server automatically.
|
||||
|
||||
### Using TailwindCSS with Bun
|
||||
|
||||
[TailwindCSS](https://tailwindcss.com/) is an extremely popular utility-first CSS framework used to style web applications.
|
||||
|
||||
When you run `bun create <component>`, Bun scans your JSX/TSX file for TailwindCSS class names (and any files it imports). If it detects TailwindCSS class names, it will add the following dependencies to your `package.json`:
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4",
|
||||
"bun-plugin-tailwind": "latest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We also configure `bunfig.toml` to use Bun's TailwindCSS plugin with `Bun.serve()`
|
||||
|
||||
```toml#bunfig.toml
|
||||
[serve.static]
|
||||
plugins = ["bun-plugin-tailwind"]
|
||||
```
|
||||
|
||||
And a `${component}.css` file with `@import "tailwindcss";` at the top:
|
||||
|
||||
```css#MyComponent.css
|
||||
@import "tailwindcss";
|
||||
```
|
||||
|
||||
### Using `shadcn/ui` with Bun
|
||||
|
||||
[`shadcn/ui`](https://ui.shadcn.com/) is an extremely popular component library tool for building web applications.
|
||||
|
||||
`bun create <component>` scans for any shadcn/ui components imported from `@/components/ui`.
|
||||
|
||||
If it finds any, it runs:
|
||||
|
||||
```bash
|
||||
# Assuming bun detected imports to @/components/ui/accordion and @/components/ui/button
|
||||
$ bunx shadcn@canary add accordion button # and any other components
|
||||
```
|
||||
|
||||
Since `shadcn/ui` itself uses TailwindCSS, `bun create` also adds the necessary TailwindCSS dependencies to your `package.json` and configures `bunfig.toml` to use Bun's TailwindCSS plugin with `Bun.serve()` as described above.
|
||||
|
||||
Additionally, we setup the following:
|
||||
|
||||
- `tsconfig.json` to alias `"@/*"` to `"src/*"` or `.` (depending on if there is a `src/` directory)
|
||||
- `components.json` so that shadcn/ui knows its a shadcn/ui project
|
||||
- `styles/globals.css` file that configures Tailwind v4 in the way that shadcn/ui expects
|
||||
- `${component}.build.ts` file that builds the component for production with `bun-plugin-tailwind` configured
|
||||
|
||||
`bun create ./MyComponent.jsx` is one of the easiest ways to run code generated from LLMs like [Claude](https://claude.ai) or ChatGPT locally.
|
||||
|
||||
## From `npm`
|
||||
|
||||
```sh
|
||||
$ bun create <template> [<destination>]
|
||||
```
|
||||
|
||||
Assuming you don't have a [local template](#from-a-local-template) with the same name, this command will download and execute the `create-<template>` package from npm. The following two commands will behave identically:
|
||||
|
||||
```sh
|
||||
$ bun create remix
|
||||
$ bunx create-remix
|
||||
```
|
||||
|
||||
Refer to the documentation of the associated `create-<template>` package for complete documentation and usage instructions.
|
||||
|
||||
## From GitHub
|
||||
|
||||
This will download the contents of the GitHub repo to disk.
|
||||
|
||||
```bash
|
||||
$ bun create <user>/<repo>
|
||||
$ bun create github.com/<user>/<repo>
|
||||
```
|
||||
|
||||
Optionally specify a name for the destination folder. If no destination is specified, the repo name will be used.
|
||||
|
||||
```bash
|
||||
$ bun create <user>/<repo> mydir
|
||||
$ bun create github.com/<user>/<repo> mydir
|
||||
```
|
||||
|
||||
Bun will perform the following steps:
|
||||
|
||||
- Download the template
|
||||
- Copy all template files into the destination folder
|
||||
- Install dependencies with `bun install`.
|
||||
- Initialize a fresh Git repo. Opt out with the `--no-git` flag.
|
||||
- Run the template's configured `start` script, if defined.
|
||||
|
||||
{% callout %}
|
||||
By default Bun will _not overwrite_ any existing files. Use the `--force` flag to overwrite existing files.
|
||||
{% /callout %}
|
||||
|
||||
<!-- ### Official templates
|
||||
|
||||
The following official templates are available.
|
||||
|
||||
```bash
|
||||
bun create next ./myapp
|
||||
bun create react ./myapp
|
||||
bun create svelte-kit ./myapp
|
||||
bun create elysia ./myapp
|
||||
bun create hono ./myapp
|
||||
bun create kingworld ./myapp
|
||||
```
|
||||
|
||||
Each of these corresponds to a directory in the [bun-community/create-templates](https://github.com/bun-community/create-templates) repo. If you think a major framework is missing, please open a PR there. This list will change over time as additional examples are added. To see an up-to-date list, run `bun create` with no arguments.
|
||||
|
||||
```bash
|
||||
$ bun create
|
||||
Welcome to bun! Create a new project by pasting any of the following:
|
||||
<list of templates>
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
⚡️ **Speed** — At the time of writing, `bun create react app` runs ~11x faster on a M1 Macbook Pro than `yarn create react-app app`.
|
||||
{% /callout %} -->
|
||||
|
||||
<!-- ### GitHub repos
|
||||
|
||||
A template of the form `<username>/<repo>` will be downloaded from GitHub.
|
||||
|
||||
```bash
|
||||
$ bun create ahfarmer/calculator ./myapp
|
||||
```
|
||||
|
||||
Complete GitHub URLs will also work:
|
||||
|
||||
```bash
|
||||
$ bun create github.com/ahfarmer/calculator ./myapp
|
||||
$ bun create https://github.com/ahfarmer/calculator ./myapp
|
||||
```
|
||||
|
||||
Bun installs the files as they currently exist current default branch (usually `main` or `master`). Unlike `git clone` it doesn't download the commit history or configure a remote. -->
|
||||
|
||||
## From a local template
|
||||
|
||||
{% callout %}
|
||||
**⚠️ Warning** — Unlike remote templates, running `bun create` with a local template will delete the entire destination folder if it already exists! Be careful.
|
||||
{% /callout %}
|
||||
Bun's templater can be extended to support custom templates defined on your local file system. These templates should live in one of the following directories:
|
||||
|
||||
- `$HOME/.bun-create/<name>`: global templates
|
||||
- `<project root>/.bun-create/<name>`: project-specific templates
|
||||
|
||||
{% callout %}
|
||||
**Note** — You can customize the global template path by setting the `BUN_CREATE_DIR` environment variable.
|
||||
{% /callout %}
|
||||
|
||||
To create a local template, navigate to `$HOME/.bun-create` and create a new directory with the desired name of your template.
|
||||
|
||||
```bash
|
||||
$ cd $HOME/.bun-create
|
||||
$ mkdir foo
|
||||
$ cd foo
|
||||
```
|
||||
|
||||
Then, create a `package.json` file in that directory with the following contents:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "foo"
|
||||
}
|
||||
```
|
||||
|
||||
You can run `bun create foo` elsewhere on your file system to verify that Bun is correctly finding your local template.
|
||||
|
||||
#### Setup logic
|
||||
|
||||
You can specify pre- and post-install setup scripts in the `"bun-create"` section of your local template's `package.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@bun-examples/simplereact",
|
||||
"version": "0.0.1",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"bun-create": {
|
||||
"preinstall": "echo 'Installing...'", // a single command
|
||||
"postinstall": ["echo 'Done!'"], // an array of commands
|
||||
"start": "bun run echo 'Hello world!'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following fields are supported. Each of these can correspond to a string or array of strings. An array of commands will be executed in order.
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- `postinstall`
|
||||
- runs after installing dependencies
|
||||
|
||||
---
|
||||
|
||||
- `preinstall`
|
||||
- runs before installing dependencies
|
||||
|
||||
{% /table %}
|
||||
|
||||
After cloning a template, `bun create` will automatically remove the `"bun-create"` section from `package.json` before writing it to the destination folder.
|
||||
|
||||
## Reference
|
||||
|
||||
### CLI flags
|
||||
|
||||
{% table %}
|
||||
|
||||
- Flag
|
||||
- Description
|
||||
|
||||
---
|
||||
|
||||
- `--force`
|
||||
- Overwrite existing files
|
||||
|
||||
---
|
||||
|
||||
- `--no-install`
|
||||
- Skip installing `node_modules` & tasks
|
||||
|
||||
---
|
||||
|
||||
- `--no-git`
|
||||
- Don’t initialize a git repository
|
||||
|
||||
---
|
||||
|
||||
- `--open`
|
||||
- Start & open in-browser after finish
|
||||
|
||||
{% /table %}
|
||||
|
||||
### Environment variables
|
||||
|
||||
{% table %}
|
||||
|
||||
- Name
|
||||
- Description
|
||||
|
||||
---
|
||||
|
||||
- `GITHUB_API_DOMAIN`
|
||||
- If you’re using a GitHub enterprise or a proxy, you can customize the GitHub domain Bun pings for downloads
|
||||
|
||||
---
|
||||
|
||||
- `GITHUB_TOKEN` (or `GITHUB_ACCESS_TOKEN`)
|
||||
- This lets `bun create` work with private repositories or if you get rate-limited. `GITHUB_TOKEN` is chosen over `GITHUB_ACCESS_TOKEN` if both exist.
|
||||
|
||||
{% /table %}
|
||||
|
||||
{% details summary="How `bun create` works" %}
|
||||
|
||||
When you run `bun create ${template} ${destination}`, here’s what happens:
|
||||
|
||||
IF remote template
|
||||
|
||||
1. GET `registry.npmjs.org/@bun-examples/${template}/latest` and parse it
|
||||
2. GET `registry.npmjs.org/@bun-examples/${template}/-/${template}-${latestVersion}.tgz`
|
||||
3. Decompress & extract `${template}-${latestVersion}.tgz` into `${destination}`
|
||||
- If there are files that would overwrite, warn and exit unless `--force` is passed
|
||||
|
||||
IF GitHub repo
|
||||
|
||||
1. Download the tarball from GitHub’s API
|
||||
2. Decompress & extract into `${destination}`
|
||||
- If there are files that would overwrite, warn and exit unless `--force` is passed
|
||||
|
||||
ELSE IF local template
|
||||
|
||||
1. Open local template folder
|
||||
2. Delete destination directory recursively
|
||||
3. Copy files recursively using the fastest system calls available (on macOS `fcopyfile` and Linux, `copy_file_range`). Do not copy or traverse into `node_modules` folder if exists (this alone makes it faster than `cp`)
|
||||
|
||||
4. Parse the `package.json` (again!), update `name` to be `${basename(destination)}`, remove the `bun-create` section from the `package.json` and save the updated `package.json` to disk.
|
||||
- IF Next.js is detected, add `bun-framework-next` to the list of dependencies
|
||||
- IF Create React App is detected, add the entry point in /src/index.{js,jsx,ts,tsx} to `public/index.html`
|
||||
- IF Relay is detected, add `bun-macro-relay` so that Relay works
|
||||
5. Auto-detect the npm client, preferring `pnpm`, `yarn` (v1), and lastly `npm`
|
||||
6. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client
|
||||
7. Run `${npmClient} install` unless `--no-install` is passed OR no dependencies are in package.json
|
||||
8. Run any tasks defined in `"bun-create": { "postinstall" }` with the npm client
|
||||
9. Run `git init; git add -A .; git commit -am "Initial Commit";`
|
||||
- Rename `gitignore` to `.gitignore`. NPM automatically removes `.gitignore` files from appearing in packages.
|
||||
- If there are dependencies, this runs in a separate thread concurrently while node_modules are being installed
|
||||
- Using libgit2 if available was tested and performed 3x slower in microbenchmarks
|
||||
|
||||
{% /details %}
|
||||
248
node_modules/bun-types/docs/cli/bun-install.md
generated
vendored
Normal file
248
node_modules/bun-types/docs/cli/bun-install.md
generated
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
### `bun install`
|
||||
|
||||
bun install is a fast package manager & npm client.
|
||||
|
||||
bun install can be configured via `bunfig.toml`, environment variables, and CLI flags.
|
||||
|
||||
#### Configuring `bun install` with `bunfig.toml`
|
||||
|
||||
`bunfig.toml` is searched for in the following paths on `bun install`, `bun remove`, and `bun add`:
|
||||
|
||||
1. `$XDG_CONFIG_HOME/.bunfig.toml` or `$HOME/.bunfig.toml`
|
||||
2. `./bunfig.toml`
|
||||
|
||||
If both are found, the results are merged together.
|
||||
|
||||
Configuring with `bunfig.toml` is optional. Bun tries to be zero configuration in general, but that's not always possible.
|
||||
|
||||
```toml
|
||||
# Using scoped packages with bun install
|
||||
[install.scopes]
|
||||
|
||||
# Scope name The value can be a URL string or an object
|
||||
"@mybigcompany" = { token = "123456", url = "https://registry.mybigcompany.com" }
|
||||
# URL is optional and falls back to the default registry
|
||||
|
||||
# The "@" in the scope is optional
|
||||
mybigcompany2 = { token = "123456" }
|
||||
|
||||
# Environment variables can be referenced as a string that starts with $ and it will be replaced
|
||||
mybigcompany3 = { token = "$npm_config_token" }
|
||||
|
||||
# Setting username and password turns it into a Basic Auth header by taking base64("username:password")
|
||||
mybigcompany4 = { username = "myusername", password = "$npm_config_password", url = "https://registry.yarnpkg.com/" }
|
||||
# You can set username and password in the registry URL. This is the same as above.
|
||||
mybigcompany5 = "https://username:password@registry.yarnpkg.com/"
|
||||
|
||||
# You can set a token for a registry URL:
|
||||
mybigcompany6 = "https://:$NPM_CONFIG_TOKEN@registry.yarnpkg.com/"
|
||||
|
||||
[install]
|
||||
# Default registry
|
||||
# can be a URL string or an object
|
||||
registry = "https://registry.yarnpkg.com/"
|
||||
# as an object
|
||||
#registry = { url = "https://registry.yarnpkg.com/", token = "123456" }
|
||||
|
||||
# Install for production? This is the equivalent to the "--production" CLI argument
|
||||
production = false
|
||||
|
||||
# Save a text-based lockfile? This is equivalent to the "--save-text-lockfile" CLI argument
|
||||
saveTextLockfile = false
|
||||
|
||||
# Disallow changes to lockfile? This is the equivalent to the "--frozen-lockfile" CLI argument
|
||||
frozenLockfile = false
|
||||
|
||||
# Don't actually install
|
||||
dryRun = true
|
||||
|
||||
# Install optionalDependencies (default: true)
|
||||
# Setting this to false is equivalent to the `--omit=optional` CLI argument
|
||||
optional = true
|
||||
|
||||
# Install local devDependencies (default: true)
|
||||
# Setting this to false is equivalent to the `--omit=dev` CLI argument
|
||||
dev = true
|
||||
|
||||
# Install peerDependencies (default: true)
|
||||
# Setting this to false is equivalent to the `--omit=peer` CLI argument
|
||||
peer = true
|
||||
|
||||
# Max number of concurrent lifecycle scripts (default: (cpu count or GOMAXPROCS) x2)
|
||||
concurrentScripts = 16
|
||||
|
||||
# When using `bun install -g`, install packages here
|
||||
globalDir = "~/.bun/install/global"
|
||||
|
||||
# When using `bun install -g`, link package bins here
|
||||
globalBinDir = "~/.bun/bin"
|
||||
|
||||
# cache-related configuration
|
||||
[install.cache]
|
||||
# The directory to use for the cache
|
||||
dir = "~/.bun/install/cache"
|
||||
|
||||
# Don't load from the global cache.
|
||||
# Note: Bun may still write to node_modules/.cache
|
||||
disable = false
|
||||
|
||||
|
||||
# Always resolve the latest versions from the registry
|
||||
disableManifest = false
|
||||
|
||||
|
||||
# Lockfile-related configuration
|
||||
[install.lockfile]
|
||||
|
||||
# Print a yarn v1 lockfile
|
||||
# Note: it does not load the lockfile, it just converts bun.lock into a yarn.lock
|
||||
print = "yarn"
|
||||
|
||||
# Save the lockfile to disk
|
||||
save = true
|
||||
|
||||
```
|
||||
|
||||
If it's easier to read as TypeScript types:
|
||||
|
||||
```ts
|
||||
export interface Root {
|
||||
install: Install;
|
||||
}
|
||||
|
||||
export interface Install {
|
||||
scopes: Scopes;
|
||||
registry: Registry;
|
||||
production: boolean;
|
||||
saveTextLockfile: boolean;
|
||||
frozenLockfile: boolean;
|
||||
dryRun: boolean;
|
||||
optional: boolean;
|
||||
dev: boolean;
|
||||
peer: boolean;
|
||||
globalDir: string;
|
||||
globalBinDir: string;
|
||||
cache: Cache;
|
||||
lockfile: Lockfile;
|
||||
logLevel: "debug" | "error" | "warn";
|
||||
}
|
||||
|
||||
type Registry =
|
||||
| string
|
||||
| {
|
||||
url?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
};
|
||||
|
||||
type Scopes = Record<string, Registry>;
|
||||
|
||||
export interface Cache {
|
||||
dir: string;
|
||||
disable: boolean;
|
||||
disableManifest: boolean;
|
||||
}
|
||||
|
||||
export interface Lockfile {
|
||||
print?: "yarn";
|
||||
save: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring with environment variables
|
||||
|
||||
Environment variables have a higher priority than `bunfig.toml`.
|
||||
|
||||
| Name | Description |
|
||||
| -------------------------------- | ------------------------------------------------------------- |
|
||||
| BUN_CONFIG_REGISTRY | Set an npm registry (default: <https://registry.npmjs.org>) |
|
||||
| BUN_CONFIG_TOKEN | Set an auth token (currently does nothing) |
|
||||
| BUN_CONFIG_YARN_LOCKFILE | Save a Yarn v1-style yarn.lock |
|
||||
| BUN_CONFIG_LINK_NATIVE_BINS | Point `bin` in package.json to a platform-specific dependency |
|
||||
| BUN_CONFIG_SKIP_SAVE_LOCKFILE | Don’t save a lockfile |
|
||||
| BUN_CONFIG_SKIP_LOAD_LOCKFILE | Don’t load a lockfile |
|
||||
| BUN_CONFIG_SKIP_INSTALL_PACKAGES | Don’t install any packages |
|
||||
|
||||
Bun always tries to use the fastest available installation method for the target platform. On macOS, that’s `clonefile` and on Linux, that’s `hardlink`. You can change which installation method is used with the `--backend` flag. When unavailable or on error, `clonefile` and `hardlink` fallsback to a platform-specific implementation of copying files.
|
||||
|
||||
Bun stores installed packages from npm in `~/.bun/install/cache/${name}@${version}`. Note that if the semver version has a `build` or a `pre` tag, it is replaced with a hash of that value instead. This is to reduce the chances of errors from long file paths, but unfortunately complicates figuring out where a package was installed on disk.
|
||||
|
||||
When the `node_modules` folder exists, before installing, Bun checks if the `"name"` and `"version"` in `package/package.json` in the expected node_modules folder matches the expected `name` and `version`. This is how it determines whether it should install. It uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`.
|
||||
|
||||
When a `bun.lock` doesn’t exist or `package.json` has changed dependencies, tarballs are downloaded & extracted eagerly while resolving.
|
||||
|
||||
When a `bun.lock` exists and `package.json` hasn’t changed, Bun downloads missing dependencies lazily. If the package with a matching `name` & `version` already exists in the expected location within `node_modules`, Bun won’t attempt to download the tarball.
|
||||
|
||||
## Platform-specific dependencies?
|
||||
|
||||
bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change.
|
||||
|
||||
## Peer dependencies?
|
||||
|
||||
Peer dependencies are handled similarly to yarn. `bun install` will automatically install peer dependencies. If the dependency is marked optional in `peerDependenciesMeta`, an existing dependency will be chosen if possible.
|
||||
|
||||
## Lockfile
|
||||
|
||||
`bun.lock` is Bun’s lockfile format. See [our blogpost about the text lockfile](https://bun.com/blog/bun-lock-text-lockfile).
|
||||
|
||||
Prior to Bun 1.2, the lockfile was binary and called `bun.lockb`. Old lockfiles can be upgraded to the new format by running `bun install --save-text-lockfile --frozen-lockfile --lockfile-only`, and then deleting `bun.lockb`.
|
||||
|
||||
## Cache
|
||||
|
||||
To delete the cache:
|
||||
|
||||
```bash
|
||||
$ rm -rf ~/.bun/install/cache
|
||||
```
|
||||
|
||||
## Platform-specific backends
|
||||
|
||||
`bun install` uses different system calls to install dependencies depending on the platform. This is a performance optimization. You can force a specific backend with the `--backend` flag.
|
||||
|
||||
**`hardlink`** is the default backend on Linux. Benchmarking showed it to be the fastest on Linux.
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend hardlink
|
||||
```
|
||||
|
||||
**`clonefile`** is the default backend on macOS. Benchmarking showed it to be the fastest on macOS. It is only available on macOS.
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend clonefile
|
||||
```
|
||||
|
||||
**`clonefile_each_dir`** is similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`. Unlike `clonefile`, this does not recursively clone subdirectories in one system call.
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend clonefile_each_dir
|
||||
```
|
||||
|
||||
**`copyfile`** is the fallback used when any of the above fail, and is the slowest. on macOS, it uses `fcopyfile()` and on linux it uses `copy_file_range()`.
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend copyfile
|
||||
```
|
||||
|
||||
**`symlink`** is typically only used for `file:` dependencies (and eventually `link:`) internally. To prevent infinite loops, it skips symlinking the `node_modules` folder.
|
||||
|
||||
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend symlink
|
||||
$ node --preserve-symlinks ./my-file.js # https://nodejs.org/api/cli.html#--preserve-symlinks
|
||||
```
|
||||
|
||||
Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`, though the code for it does exist.
|
||||
|
||||
## npm registry metadata
|
||||
|
||||
bun uses a binary format for caching NPM registry responses. This loads much faster than JSON and tends to be smaller on disk.
|
||||
You will see these files in `~/.bun/install/cache/*.npm`. The filename pattern is `${hash(packageName)}.npm`. It’s a hash so that extra directories don’t need to be created for scoped packages.
|
||||
|
||||
Bun's usage of `Cache-Control` ignores `Age`. This improves performance, but means bun may be about 5 minutes out of date to receive the latest package version metadata from npm.
|
||||
39
node_modules/bun-types/docs/cli/bun-upgrade.md
generated
vendored
Normal file
39
node_modules/bun-types/docs/cli/bun-upgrade.md
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
To upgrade Bun, run `bun upgrade`.
|
||||
|
||||
It automatically downloads the latest version of Bun and overwrites the currently-running version.
|
||||
|
||||
This works by checking the latest version of Bun in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases) and unzipping it using the system-provided `unzip` library (so that Gatekeeper works on macOS)
|
||||
|
||||
If for any reason you run into issues, you can also use the curl install script:
|
||||
|
||||
```bash
|
||||
$ curl https://bun.com/install | bash
|
||||
```
|
||||
|
||||
It will still work when Bun is already installed.
|
||||
|
||||
Bun is distributed as a single binary file, so you can also do this manually:
|
||||
|
||||
- Download the latest version of Bun for your platform in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases/latest) (`darwin` == macOS)
|
||||
- Unzip the folder
|
||||
- Move the `bun` binary to `~/.bun/bin` (or anywhere)
|
||||
|
||||
## `--canary`
|
||||
|
||||
[Canary](https://github.com/oven-sh/bun/releases/tag/canary) builds are generated on every commit.
|
||||
|
||||
To install a [canary](https://github.com/oven-sh/bun/releases/tag/canary) build of Bun, run:
|
||||
|
||||
```bash
|
||||
$ bun upgrade --canary
|
||||
```
|
||||
|
||||
This flag is not persistent (though that might change in the future). If you want to always run the canary build of Bun, set the `BUN_CANARY` environment variable to `1` in your shell's startup script.
|
||||
|
||||
This will download the release zip from https://github.com/oven-sh/bun/releases/tag/canary.
|
||||
|
||||
To revert to the latest published version of Bun, run:
|
||||
|
||||
```bash
|
||||
$ bun upgrade
|
||||
```
|
||||
80
node_modules/bun-types/docs/cli/bunx.md
generated
vendored
Normal file
80
node_modules/bun-types/docs/cli/bunx.md
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
{% callout %}
|
||||
**Note** — `bunx` is an alias for `bun x`. The `bunx` CLI will be auto-installed when you install `bun`.
|
||||
{% /callout %}
|
||||
|
||||
Use `bunx` to auto-install and run packages from `npm`. It's Bun's equivalent of `npx` or `yarn dlx`.
|
||||
|
||||
```bash
|
||||
$ bunx cowsay "Hello world!"
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
⚡️ **Speed** — With Bun's fast startup times, `bunx` is [roughly 100x faster](https://twitter.com/jarredsumner/status/1606163655527059458) than `npx` for locally installed packages.
|
||||
{% /callout %}
|
||||
|
||||
Packages can declare executables in the `"bin"` field of their `package.json`. These are known as _package executables_ or _package binaries_.
|
||||
|
||||
```jsonc#package.json
|
||||
{
|
||||
// ... other fields
|
||||
"name": "my-cli",
|
||||
"bin": {
|
||||
"my-cli": "dist/index.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These executables are commonly plain JavaScript files marked with a [shebang line](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) to indicate which program should be used to execute them. The following file indicates that it should be executed with `node`.
|
||||
|
||||
```js#dist/index.js
|
||||
#!/usr/bin/env node
|
||||
|
||||
console.log("Hello world!");
|
||||
```
|
||||
|
||||
These executables can be run with `bunx`,
|
||||
|
||||
```bash
|
||||
$ bunx my-cli
|
||||
```
|
||||
|
||||
As with `npx`, `bunx` will check for a locally installed package first, then fall back to auto-installing the package from `npm`. Installed packages will be stored in Bun's global cache for future use.
|
||||
|
||||
## Arguments and flags
|
||||
|
||||
To pass additional command-line flags and arguments through to the executable, place them after the executable name.
|
||||
|
||||
```bash
|
||||
$ bunx my-cli --foo bar
|
||||
```
|
||||
|
||||
## Shebangs
|
||||
|
||||
By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using Bun's runtime, even if the executable indicates otherwise. To do so, include the `--bun` flag.
|
||||
|
||||
```bash
|
||||
$ bunx --bun my-cli
|
||||
```
|
||||
|
||||
The `--bun` flag must occur _before_ the executable name. Flags that appear _after_ the name are passed through to the executable.
|
||||
|
||||
```bash
|
||||
$ bunx --bun my-cli # good
|
||||
$ bunx my-cli --bun # bad
|
||||
```
|
||||
|
||||
To force bun to always be used with a script, use a shebang.
|
||||
|
||||
```
|
||||
#!/usr/bin/env bun
|
||||
```
|
||||
|
||||
<!-- ## Environment variables
|
||||
|
||||
Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order:
|
||||
|
||||
1. `.env.local` (first)
|
||||
2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development`
|
||||
3. `.env`
|
||||
|
||||
To debug environment variables, run `bun --print process.env` to view a list of resolved environment variables. -->
|
||||
90
node_modules/bun-types/docs/cli/filter.md
generated
vendored
Normal file
90
node_modules/bun-types/docs/cli/filter.md
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
The `--filter` (or `-F`) flag is used for selecting packages by pattern in a monorepo. Patterns can be used to match package names or package paths, with full glob syntax support.
|
||||
|
||||
Currently `--filter` is supported by `bun install` and `bun outdated`, and can also be used to run scripts for multiple packages at once.
|
||||
|
||||
## Matching
|
||||
|
||||
### Package Name `--filter <pattern>`
|
||||
|
||||
Name patterns select packages based on the package name, as specified in `package.json`. For example, if you have packages `pkg-a`, `pkg-b` and `other`, you can match all packages with `*`, only `pkg-a` and `pkg-b` with `pkg*`, and a specific package by providing the full name of the package.
|
||||
|
||||
### Package Path `--filter ./<glob>`
|
||||
|
||||
Path patterns are specified by starting the pattern with `./`, and will select all packages in directories that match the pattern. For example, to match all packages in subdirectories of `packages`, you can use `--filter './packages/**'`. To match a package located in `packages/foo`, use `--filter ./packages/foo`.
|
||||
|
||||
## `bun install` and `bun outdated`
|
||||
|
||||
Both `bun install` and `bun outdated` support the `--filter` flag.
|
||||
|
||||
`bun install` by default will install dependencies for all packages in the monorepo. To install dependencies for specific packages, use `--filter`.
|
||||
|
||||
Given a monorepo with workspaces `pkg-a`, `pkg-b`, and `pkg-c` under `./packages`:
|
||||
|
||||
```bash
|
||||
# Install dependencies for all workspaces except `pkg-c`
|
||||
$ bun install --filter '!pkg-c'
|
||||
|
||||
# Install dependencies for packages in `./packages` (`pkg-a`, `pkg-b`, `pkg-c`)
|
||||
$ bun install --filter './packages/*'
|
||||
|
||||
# Save as above, but exclude the root package.json
|
||||
$ bun install --filter '!./' --filter './packages/*'
|
||||
```
|
||||
|
||||
Similarly, `bun outdated` will display outdated dependencies for all packages in the monorepo, and `--filter` can be used to restrict the command to a subset of the packages:
|
||||
|
||||
```bash
|
||||
# Display outdated dependencies for workspaces starting with `pkg-`
|
||||
$ bun outdated --filter 'pkg-*'
|
||||
|
||||
# Display outdated dependencies for only the root package.json
|
||||
$ bun outdated --filter './'
|
||||
```
|
||||
|
||||
For more information on both these commands, see [`bun install`](https://bun.com/docs/cli/install) and [`bun outdated`](https://bun.com/docs/cli/outdated).
|
||||
|
||||
## Running scripts with `--filter`
|
||||
|
||||
Use the `--filter` flag to execute scripts in multiple packages at once:
|
||||
|
||||
```bash
|
||||
bun --filter <pattern> <script>
|
||||
```
|
||||
|
||||
Say you have a monorepo with two packages: `packages/api` and `packages/frontend`, both with a `dev` script that will start a local development server. Normally, you would have to open two separate terminal tabs, cd into each package directory, and run `bun dev`:
|
||||
|
||||
```bash
|
||||
cd packages/api
|
||||
bun dev
|
||||
|
||||
# in another terminal
|
||||
cd packages/frontend
|
||||
bun dev
|
||||
```
|
||||
|
||||
Using `--filter`, you can run the `dev` script in both packages at once:
|
||||
|
||||
```bash
|
||||
bun --filter '*' dev
|
||||
```
|
||||
|
||||
Both commands will be run in parallel, and you will see a nice terminal UI showing their respective outputs:
|
||||

|
||||
|
||||
### Running scripts in workspaces
|
||||
|
||||
Filters respect your [workspace configuration](https://bun.com/docs/install/workspaces): If you have a `package.json` file that specifies which packages are part of the workspace,
|
||||
`--filter` will be restricted to only these packages. Also, in a workspace you can use `--filter` to run scripts in packages that are located anywhere in the workspace:
|
||||
|
||||
```bash
|
||||
# Packages
|
||||
# src/foo
|
||||
# src/bar
|
||||
|
||||
# in src/bar: runs myscript in src/foo, no need to cd!
|
||||
bun run --filter foo myscript
|
||||
```
|
||||
|
||||
### Dependency Order
|
||||
|
||||
Bun will respect package dependency order when running scripts. Say you have a package `foo` that depends on another package `bar` in your workspace, and both packages have a `build` script. When you run `bun --filter '*' build`, you will notice that `foo` will only start running once `bar` is done.
|
||||
65
node_modules/bun-types/docs/cli/info.md
generated
vendored
Normal file
65
node_modules/bun-types/docs/cli/info.md
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
`bun info` displays package metadata from the npm registry.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
$ bun info react
|
||||
```
|
||||
|
||||
This will display information about the `react` package, including its latest version, description, homepage, dependencies, and more.
|
||||
|
||||
## Viewing specific versions
|
||||
|
||||
To view information about a specific version:
|
||||
|
||||
```bash
|
||||
$ bun info react@18.0.0
|
||||
```
|
||||
|
||||
## Viewing specific properties
|
||||
|
||||
You can also query specific properties from the package metadata:
|
||||
|
||||
```bash
|
||||
$ bun info react version
|
||||
$ bun info react dependencies
|
||||
$ bun info react repository.url
|
||||
```
|
||||
|
||||
## JSON output
|
||||
|
||||
To get the output in JSON format, use the `--json` flag:
|
||||
|
||||
```bash
|
||||
$ bun info react --json
|
||||
```
|
||||
|
||||
## Alias
|
||||
|
||||
`bun pm view` is an alias for `bun info`:
|
||||
|
||||
```bash
|
||||
$ bun pm view react # equivalent to: bun info react
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# View basic package information
|
||||
$ bun info is-number
|
||||
|
||||
# View a specific version
|
||||
$ bun info is-number@7.0.0
|
||||
|
||||
# View all available versions
|
||||
$ bun info is-number versions
|
||||
|
||||
# View package dependencies
|
||||
$ bun info express dependencies
|
||||
|
||||
# View package homepage
|
||||
$ bun info lodash homepage
|
||||
|
||||
# Get JSON output
|
||||
$ bun info react --json
|
||||
```
|
||||
71
node_modules/bun-types/docs/cli/init.md
generated
vendored
Normal file
71
node_modules/bun-types/docs/cli/init.md
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
Scaffold an empty Bun project with the interactive `bun init` command.
|
||||
|
||||
```bash
|
||||
$ bun init
|
||||
bun init helps you get started with a minimal project and tries to
|
||||
guess sensible defaults. Press ^C anytime to quit.
|
||||
|
||||
package name (quickstart):
|
||||
entry point (index.ts):
|
||||
|
||||
Done! A package.json file was saved in the current directory.
|
||||
+ index.ts
|
||||
+ .gitignore
|
||||
+ tsconfig.json (for editor auto-complete)
|
||||
+ README.md
|
||||
|
||||
To get started, run:
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults.
|
||||
|
||||
{% details summary="How `bun init` works" %}
|
||||
|
||||
`bun init` is a quick way to start a blank project with Bun. It guesses with sane defaults and is non-destructive when run multiple times.
|
||||
|
||||

|
||||
|
||||
It creates:
|
||||
|
||||
- a `package.json` file with a name that defaults to the current directory name
|
||||
- a `tsconfig.json` file or a `jsconfig.json` file, depending if the entry point is a TypeScript file or not
|
||||
- an entry point which defaults to `index.ts` unless any of `index.{tsx, jsx, js, mts, mjs}` exist or the `package.json` specifies a `module` or `main` field
|
||||
- a `README.md` file
|
||||
|
||||
If you pass `-y` or `--yes`, it will assume you want to continue without asking questions.
|
||||
|
||||
At the end, it runs `bun install` to install `@types/bun`.
|
||||
|
||||
{% /details %}
|
||||
|
||||
{% bunCLIUsage command="init" /%}
|
||||
|
||||
## React
|
||||
|
||||
The `--react` flag will scaffold a React project:
|
||||
|
||||
```bash
|
||||
$ bun init --react
|
||||
```
|
||||
|
||||
The `--react` flag accepts the following values:
|
||||
|
||||
- `tailwind` - Scaffold a React project with Tailwind CSS
|
||||
- `shadcn` - Scaffold a React project with Shadcn/UI and Tailwind CSS
|
||||
|
||||
### React + TailwindCSS
|
||||
|
||||
This will create a React project with Tailwind CSS configured with Bun's bundler and dev server.
|
||||
|
||||
```bash
|
||||
$ bun init --react=tailwind
|
||||
```
|
||||
|
||||
### React + @shadcn/ui
|
||||
|
||||
This will create a React project with shadcn/ui and Tailwind CSS configured with Bun's bundler and dev server.
|
||||
|
||||
```bash
|
||||
$ bun init --react=shadcn
|
||||
```
|
||||
239
node_modules/bun-types/docs/cli/install.md
generated
vendored
Normal file
239
node_modules/bun-types/docs/cli/install.md
generated
vendored
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
The `bun` CLI contains a Node.js-compatible package manager designed to be a dramatically faster replacement for `npm`, `yarn`, and `pnpm`. It's a standalone tool that will work in pre-existing Node.js projects; if your project has a `package.json`, `bun install` can help you speed up your workflow.
|
||||
|
||||
{% callout %}
|
||||
|
||||
**⚡️ 25x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 25x faster.
|
||||
|
||||
{% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%}
|
||||
|
||||
{% /callout %}
|
||||
|
||||
{% details summary="For Linux users" %}
|
||||
The recommended minimum Linux Kernel version is 5.6. If you're on Linux kernel 5.1 - 5.5, `bun install` will work, but HTTP requests will be slow due to a lack of support for io_uring's `connect()` operation.
|
||||
|
||||
If you're using Ubuntu 20.04, here's how to install a [newer kernel](https://wiki.ubuntu.com/Kernel/LTSEnablementStack):
|
||||
|
||||
```bash
|
||||
# If this returns a version >= 5.6, you don't need to do anything
|
||||
$ uname -r
|
||||
|
||||
# Install the official Ubuntu hardware enablement kernel
|
||||
$ sudo apt install --install-recommends linux-generic-hwe-20.04
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
To install all dependencies of a project:
|
||||
|
||||
```bash
|
||||
$ bun install
|
||||
```
|
||||
|
||||
Running `bun install` will:
|
||||
|
||||
- **Install** all `dependencies`, `devDependencies`, and `optionalDependencies`. Bun will install `peerDependencies` by default.
|
||||
- **Run** your project's `{pre|post}install` and `{pre|post}prepare` scripts at the appropriate time. For security reasons Bun _does not execute_ lifecycle scripts of installed dependencies.
|
||||
- **Write** a `bun.lock` lockfile to the project root.
|
||||
|
||||
## Logging
|
||||
|
||||
To modify logging verbosity:
|
||||
|
||||
```bash
|
||||
$ bun install --verbose # debug logging
|
||||
$ bun install --silent # no logging
|
||||
```
|
||||
|
||||
## Lifecycle scripts
|
||||
|
||||
Unlike other npm clients, Bun does not execute arbitrary lifecycle scripts like `postinstall` for installed dependencies. Executing arbitrary scripts represents a potential security risk.
|
||||
|
||||
To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
|
||||
|
||||
```json-diff
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
+ "trustedDependencies": ["my-trusted-package"]
|
||||
}
|
||||
```
|
||||
|
||||
Then re-install the package. Bun will read this field and run lifecycle scripts for `my-trusted-package`.
|
||||
|
||||
Lifecycle scripts will run in parallel during installation. To adjust the maximum number of concurrent scripts, use the `--concurrent-scripts` flag. The default is two times the reported cpu count or GOMAXPROCS.
|
||||
|
||||
```bash
|
||||
$ bun install --concurrent-scripts 5
|
||||
```
|
||||
|
||||
## Workspaces
|
||||
|
||||
Bun supports `"workspaces"` in package.json. For complete documentation refer to [Package manager > Workspaces](https://bun.com/docs/install/workspaces).
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
"workspaces": ["packages/*"],
|
||||
"dependencies": {
|
||||
"preact": "^10.5.13"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Installing dependencies for specific packages
|
||||
|
||||
In a monorepo, you can install the dependencies for a subset of packages using the `--filter` flag.
|
||||
|
||||
```bash
|
||||
# Install dependencies for all workspaces except `pkg-c`
|
||||
$ bun install --filter '!pkg-c'
|
||||
|
||||
# Install dependencies for only `pkg-a` in `./packages/pkg-a`
|
||||
$ bun install --filter './packages/pkg-a'
|
||||
```
|
||||
|
||||
For more information on filtering with `bun install`, refer to [Package Manager > Filtering](https://bun.com/docs/cli/filter#bun-install-and-bun-outdated)
|
||||
|
||||
## Overrides and resolutions
|
||||
|
||||
Bun supports npm's `"overrides"` and Yarn's `"resolutions"` in `package.json`. These are mechanisms for specifying a version range for _metadependencies_—the dependencies of your dependencies. Refer to [Package manager > Overrides and resolutions](https://bun.com/docs/install/overrides) for complete documentation.
|
||||
|
||||
```json-diff#package.json
|
||||
{
|
||||
"name": "my-app",
|
||||
"dependencies": {
|
||||
"foo": "^2.0.0"
|
||||
},
|
||||
+ "overrides": {
|
||||
+ "bar": "~4.4.0"
|
||||
+ }
|
||||
}
|
||||
```
|
||||
|
||||
## Global packages
|
||||
|
||||
To install a package globally, use the `-g`/`--global` flag. Typically this is used for installing command-line tools.
|
||||
|
||||
```bash
|
||||
$ bun install --global cowsay # or `bun install -g cowsay`
|
||||
$ cowsay "Bun!"
|
||||
______
|
||||
< Bun! >
|
||||
------
|
||||
\ ^__^
|
||||
\ (oo)\_______
|
||||
(__)\ )\/\
|
||||
||----w |
|
||||
|| ||
|
||||
```
|
||||
|
||||
## Production mode
|
||||
|
||||
To install in production mode (i.e. without `devDependencies` or `optionalDependencies`):
|
||||
|
||||
```bash
|
||||
$ bun install --production
|
||||
```
|
||||
|
||||
For reproducible installs, use `--frozen-lockfile`. This will install the exact versions of each package specified in the lockfile. If your `package.json` disagrees with `bun.lock`, Bun will exit with an error. The lockfile will not be updated.
|
||||
|
||||
```bash
|
||||
$ bun install --frozen-lockfile
|
||||
```
|
||||
|
||||
For more information on Bun's lockfile `bun.lock`, refer to [Package manager > Lockfile](https://bun.com/docs/install/lockfile).
|
||||
|
||||
## Omitting dependencies
|
||||
|
||||
To omit dev, peer, or optional dependencies use the `--omit` flag.
|
||||
|
||||
```bash
|
||||
# Exclude "devDependencies" from the installation. This will apply to the
|
||||
# root package and workspaces if they exist. Transitive dependencies will
|
||||
# not have "devDependencies".
|
||||
$ bun install --omit dev
|
||||
|
||||
# Install only dependencies from "dependencies"
|
||||
$ bun install --omit=dev --omit=peer --omit=optional
|
||||
```
|
||||
|
||||
## Dry run
|
||||
|
||||
To perform a dry run (i.e. don't actually install anything):
|
||||
|
||||
```bash
|
||||
$ bun install --dry-run
|
||||
```
|
||||
|
||||
## Non-npm dependencies
|
||||
|
||||
Bun supports installing dependencies from Git, GitHub, and local or remotely-hosted tarballs. For complete documentation refer to [Package manager > Git, GitHub, and tarball dependencies](https://bun.com/docs/cli/add).
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"dayjs": "git+https://github.com/iamkun/dayjs.git",
|
||||
"lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
|
||||
"moment": "git@github.com:moment/moment.git",
|
||||
"zod": "github:colinhacks/zod",
|
||||
"react": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||
"bun-types": "npm:@types/bun"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The default behavior of `bun install` can be configured in `bunfig.toml`. The default values are shown below.
|
||||
|
||||
```toml
|
||||
[install]
|
||||
|
||||
# whether to install optionalDependencies
|
||||
optional = true
|
||||
|
||||
# whether to install devDependencies
|
||||
dev = true
|
||||
|
||||
# whether to install peerDependencies
|
||||
peer = true
|
||||
|
||||
# equivalent to `--production` flag
|
||||
production = false
|
||||
|
||||
# equivalent to `--save-text-lockfile` flag
|
||||
saveTextLockfile = false
|
||||
|
||||
# equivalent to `--frozen-lockfile` flag
|
||||
frozenLockfile = false
|
||||
|
||||
# equivalent to `--dry-run` flag
|
||||
dryRun = false
|
||||
|
||||
# equivalent to `--concurrent-scripts` flag
|
||||
concurrentScripts = 16 # (cpu count or GOMAXPROCS) x2
|
||||
```
|
||||
|
||||
## CI/CD
|
||||
|
||||
Looking to speed up your CI? Use the official [`oven-sh/setup-bun`](https://github.com/oven-sh/setup-bun) action to install `bun` in a GitHub Actions pipeline.
|
||||
|
||||
```yaml#.github/workflows/release.yml
|
||||
name: bun-types
|
||||
jobs:
|
||||
build:
|
||||
name: build-app
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Install bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
- name: Build app
|
||||
run: bun run build
|
||||
```
|
||||
|
||||
{% bunCLIUsage command="install" /%}
|
||||
40
node_modules/bun-types/docs/cli/link.md
generated
vendored
Normal file
40
node_modules/bun-types/docs/cli/link.md
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Use `bun link` in a local directory to register the current package as a "linkable" package.
|
||||
|
||||
```bash
|
||||
$ cd /path/to/cool-pkg
|
||||
$ cat package.json
|
||||
{
|
||||
"name": "cool-pkg",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
$ bun link
|
||||
bun link v1.x (7416672e)
|
||||
Success! Registered "cool-pkg"
|
||||
|
||||
To use cool-pkg in a project, run:
|
||||
bun link cool-pkg
|
||||
|
||||
Or add it in dependencies in your package.json file:
|
||||
"cool-pkg": "link:cool-pkg"
|
||||
```
|
||||
|
||||
This package can now be "linked" into other projects using `bun link cool-pkg`. This will create a symlink in the `node_modules` directory of the target project, pointing to the local directory.
|
||||
|
||||
```bash
|
||||
$ cd /path/to/my-app
|
||||
$ bun link cool-pkg
|
||||
```
|
||||
|
||||
In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencies` field of your app's package.json with a special version specifier that tells Bun to load from the registered local directory instead of installing from `npm`:
|
||||
|
||||
```json-diff
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
+ "cool-pkg": "link:cool-pkg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% bunCLIUsage command="link" /%}
|
||||
47
node_modules/bun-types/docs/cli/outdated.md
generated
vendored
Normal file
47
node_modules/bun-types/docs/cli/outdated.md
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Use `bun outdated` to check for outdated dependencies in your project. This command displays a table of dependencies that have newer versions available.
|
||||
|
||||
{% bunOutdatedTerminal displayGlob="" filter="" glob="" /%}
|
||||
|
||||
## Version Information
|
||||
|
||||
The output table shows three version columns:
|
||||
|
||||
- **Current**: The version currently installed
|
||||
- **Update**: The latest version that satisfies your package.json version range
|
||||
- **Latest**: The latest version published to the registry
|
||||
|
||||
### Dependency Filters
|
||||
|
||||
`bun outdated` supports searching for outdated dependencies by package names and glob patterns.
|
||||
|
||||
To check if specific dependencies are outdated, pass the package names as positional arguments:
|
||||
|
||||
{% bunOutdatedTerminal displayGlob="eslint-plugin-security eslint-plugin-sonarjs" glob="eslint-plugin-*" /%}
|
||||
|
||||
You can also pass glob patterns to check for outdated packages:
|
||||
|
||||
{% bunOutdatedTerminal displayGlob="'eslint*'" glob="eslint*" /%}
|
||||
|
||||
For example, to check for outdated `@types/*` packages:
|
||||
|
||||
{% bunOutdatedTerminal displayGlob="'@types/*'" glob="@types/*" /%}
|
||||
|
||||
Or to exclude all `@types/*` packages:
|
||||
|
||||
{% bunOutdatedTerminal displayGlob="'!@types/*'" glob="!@types/*" /%}
|
||||
|
||||
### Workspace Filters
|
||||
|
||||
Use the `--filter` flag to check for outdated dependencies in a different workspace package:
|
||||
|
||||
{% bunOutdatedTerminal glob="t*" filter="@monorepo/types" /%}
|
||||
|
||||
You can pass multiple `--filter` flags to check multiple workspaces:
|
||||
|
||||
{% bunOutdatedTerminal glob="{e,t}*" displayGlob="--filter @monorepo/types --filter @monorepo/cli" /%}
|
||||
|
||||
You can also pass glob patterns to filter by workspace names:
|
||||
|
||||
{% bunOutdatedTerminal glob="{e,t}*" displayGlob="--filter='@monorepo/{types,cli}'" /%}
|
||||
|
||||
{% bunCLIUsage command="outdated" /%}
|
||||
11
node_modules/bun-types/docs/cli/patch-commit.md
generated
vendored
Normal file
11
node_modules/bun-types/docs/cli/patch-commit.md
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
An alias for `bun patch --commit` to maintain compatibility with pnpm.
|
||||
|
||||
To get started with patch, first prepare the package for patching with [`bun patch <pkg>`](https://bun.com/docs/install/patch).
|
||||
|
||||
### `--patches-dir`
|
||||
|
||||
By default, `bun patch-commit` will use the `patches` directory in the temporary directory.
|
||||
|
||||
You can specify a different directory with the `--patches-dir` flag.
|
||||
|
||||
{% bunCLIUsage command="patch-commit" /%}
|
||||
285
node_modules/bun-types/docs/cli/pm.md
generated
vendored
Normal file
285
node_modules/bun-types/docs/cli/pm.md
generated
vendored
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
The `bun pm` command group provides a set of utilities for working with Bun's package manager.
|
||||
|
||||
## pack
|
||||
|
||||
To create a tarball of the current workspace:
|
||||
|
||||
```bash
|
||||
$ bun pm pack
|
||||
```
|
||||
|
||||
This command creates a `.tgz` file containing all files that would be published to npm, following the same rules as `npm pack`.
|
||||
|
||||
## Examples
|
||||
|
||||
Basic usage:
|
||||
|
||||
```bash
|
||||
$ bun pm pack
|
||||
# Creates my-package-1.0.0.tgz in current directory
|
||||
```
|
||||
|
||||
Quiet mode for scripting:
|
||||
|
||||
```bash
|
||||
$ TARBALL=$(bun pm pack --quiet)
|
||||
$ echo "Created: $TARBALL"
|
||||
# Output: Created: my-package-1.0.0.tgz
|
||||
```
|
||||
|
||||
Custom destination:
|
||||
|
||||
```bash
|
||||
$ bun pm pack --destination ./dist
|
||||
# Saves tarball in ./dist/ directory
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
- `--dry-run`: Perform all tasks except writing the tarball to disk. Shows what would be included.
|
||||
- `--destination <dir>`: Specify the directory where the tarball will be saved.
|
||||
- `--filename <name>`: Specify an exact file name for the tarball to be saved at.
|
||||
- `--ignore-scripts`: Skip running pre/postpack and prepare scripts.
|
||||
- `--gzip-level <0-9>`: Set a custom compression level for gzip, ranging from 0 to 9 (default is 9).
|
||||
- `--quiet`: Only output the tarball filename, suppressing verbose output. Ideal for scripts and automation.
|
||||
|
||||
> **Note:** `--filename` and `--destination` cannot be used at the same time.
|
||||
|
||||
## Output Modes
|
||||
|
||||
**Default output:**
|
||||
|
||||
```bash
|
||||
$ bun pm pack
|
||||
bun pack v1.2.19
|
||||
|
||||
packed 131B package.json
|
||||
packed 40B index.js
|
||||
|
||||
my-package-1.0.0.tgz
|
||||
|
||||
Total files: 2
|
||||
Shasum: f2451d6eb1e818f500a791d9aace80b394258a90
|
||||
Unpacked size: 171B
|
||||
Packed size: 249B
|
||||
```
|
||||
|
||||
**Quiet output:**
|
||||
|
||||
```bash
|
||||
$ bun pm pack --quiet
|
||||
my-package-1.0.0.tgz
|
||||
```
|
||||
|
||||
The `--quiet` flag is particularly useful for automation workflows where you need to capture the generated tarball filename for further processing.
|
||||
|
||||
## bin
|
||||
|
||||
To print the path to the `bin` directory for the local project:
|
||||
|
||||
```bash
|
||||
$ bun pm bin
|
||||
/path/to/current/project/node_modules/.bin
|
||||
```
|
||||
|
||||
To print the path to the global `bin` directory:
|
||||
|
||||
```bash
|
||||
$ bun pm bin -g
|
||||
<$HOME>/.bun/bin
|
||||
```
|
||||
|
||||
## ls
|
||||
|
||||
To print a list of installed dependencies in the current project and their resolved versions, excluding their dependencies.
|
||||
|
||||
```bash
|
||||
$ bun pm ls
|
||||
/path/to/project node_modules (135)
|
||||
├── eslint@8.38.0
|
||||
├── react@18.2.0
|
||||
├── react-dom@18.2.0
|
||||
├── typescript@5.0.4
|
||||
└── zod@3.21.4
|
||||
```
|
||||
|
||||
To print all installed dependencies, including nth-order dependencies.
|
||||
|
||||
```bash
|
||||
$ bun pm ls --all
|
||||
/path/to/project node_modules (135)
|
||||
├── @eslint-community/eslint-utils@4.4.0
|
||||
├── @eslint-community/regexpp@4.5.0
|
||||
├── @eslint/eslintrc@2.0.2
|
||||
├── @eslint/js@8.38.0
|
||||
├── @nodelib/fs.scandir@2.1.5
|
||||
├── @nodelib/fs.stat@2.0.5
|
||||
├── @nodelib/fs.walk@1.2.8
|
||||
├── acorn@8.8.2
|
||||
├── acorn-jsx@5.3.2
|
||||
├── ajv@6.12.6
|
||||
├── ansi-regex@5.0.1
|
||||
├── ...
|
||||
```
|
||||
|
||||
## whoami
|
||||
|
||||
Print your npm username. Requires you to be logged in (`bunx npm login`) with credentials in either `bunfig.toml` or `.npmrc`:
|
||||
|
||||
```bash
|
||||
$ bun pm whoami
|
||||
```
|
||||
|
||||
## hash
|
||||
|
||||
To generate and print the hash of the current lockfile:
|
||||
|
||||
```bash
|
||||
$ bun pm hash
|
||||
```
|
||||
|
||||
To print the string used to hash the lockfile:
|
||||
|
||||
```bash
|
||||
$ bun pm hash-string
|
||||
```
|
||||
|
||||
To print the hash stored in the current lockfile:
|
||||
|
||||
```bash
|
||||
$ bun pm hash-print
|
||||
```
|
||||
|
||||
## cache
|
||||
|
||||
To print the path to Bun's global module cache:
|
||||
|
||||
```bash
|
||||
$ bun pm cache
|
||||
```
|
||||
|
||||
To clear Bun's global module cache:
|
||||
|
||||
```bash
|
||||
$ bun pm cache rm
|
||||
```
|
||||
|
||||
## migrate
|
||||
|
||||
To migrate another package manager's lockfile without installing anything:
|
||||
|
||||
```bash
|
||||
$ bun pm migrate
|
||||
```
|
||||
|
||||
## untrusted
|
||||
|
||||
To print current untrusted dependencies with scripts:
|
||||
|
||||
```bash
|
||||
$ bun pm untrusted
|
||||
|
||||
./node_modules/@biomejs/biome @1.8.3
|
||||
» [postinstall]: node scripts/postinstall.js
|
||||
|
||||
These dependencies had their lifecycle scripts blocked during install.
|
||||
```
|
||||
|
||||
## trust
|
||||
|
||||
To run scripts for untrusted dependencies and add to `trustedDependencies`:
|
||||
|
||||
```bash
|
||||
$ bun pm trust <names>
|
||||
```
|
||||
|
||||
Options for the `trust` command:
|
||||
|
||||
- `--all`: Trust all untrusted dependencies.
|
||||
|
||||
## default-trusted
|
||||
|
||||
To print the default trusted dependencies list:
|
||||
|
||||
```bash
|
||||
$ bun pm default-trusted
|
||||
```
|
||||
|
||||
see the current list on GitHub [here](https://github.com/oven-sh/bun/blob/main/src/install/default-trusted-dependencies.txt)
|
||||
|
||||
## version
|
||||
|
||||
To display current package version and help:
|
||||
|
||||
```bash
|
||||
$ bun pm version
|
||||
bun pm version v1.2.19 (ca7428e9)
|
||||
Current package version: v1.0.0
|
||||
|
||||
Increment:
|
||||
patch 1.0.0 → 1.0.1
|
||||
minor 1.0.0 → 1.1.0
|
||||
major 1.0.0 → 2.0.0
|
||||
prerelease 1.0.0 → 1.0.1-0
|
||||
prepatch 1.0.0 → 1.0.1-0
|
||||
preminor 1.0.0 → 1.1.0-0
|
||||
premajor 1.0.0 → 2.0.0-0
|
||||
from-git Use version from latest git tag
|
||||
1.2.3 Set specific version
|
||||
|
||||
Options:
|
||||
--no-git-tag-version Skip git operations
|
||||
--allow-same-version Prevents throwing error if version is the same
|
||||
--message=<val>, -m Custom commit message, use %s for version substitution
|
||||
--preid=<val> Prerelease identifier (i.e beta → 1.0.1-beta.0)
|
||||
--force, -f Bypass dirty git history check
|
||||
|
||||
Examples:
|
||||
$ bun pm version patch
|
||||
$ bun pm version 1.2.3 --no-git-tag-version
|
||||
$ bun pm version prerelease --preid beta --message "Release beta: %s"
|
||||
```
|
||||
|
||||
To bump the version in `package.json`:
|
||||
|
||||
```bash
|
||||
$ bun pm version patch
|
||||
v1.0.1
|
||||
```
|
||||
|
||||
Supports `patch`, `minor`, `major`, `premajor`, `preminor`, `prepatch`, `prerelease`, `from-git`, or specific versions like `1.2.3`. By default creates git commit and tag unless `--no-git-tag-version` was used to skip.
|
||||
|
||||
## pkg
|
||||
|
||||
Manage `package.json` data with get, set, delete, and fix operations.
|
||||
|
||||
All commands support dot and bracket notation:
|
||||
|
||||
```bash
|
||||
scripts.build # dot notation
|
||||
contributors[0] # array access
|
||||
workspaces.0 # dot with numeric index
|
||||
scripts[test:watch] # bracket for special chars
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# set
|
||||
$ bun pm pkg get name # single property
|
||||
$ bun pm pkg get name version # multiple properties
|
||||
$ bun pm pkg get # entire package.json
|
||||
$ bun pm pkg get scripts.build # nested property
|
||||
|
||||
# set
|
||||
$ bun pm pkg set name="my-package" # simple property
|
||||
$ bun pm pkg set scripts.test="jest" version=2.0.0 # multiple properties
|
||||
$ bun pm pkg set {"private":"true"} --json # JSON values with --json flag
|
||||
|
||||
# delete
|
||||
$ bun pm pkg delete description # single property
|
||||
$ bun pm pkg delete scripts.test contributors[0] # multiple/nested
|
||||
|
||||
# fix
|
||||
$ bun pm pkg fix # auto-fix common issues
|
||||
```
|
||||
112
node_modules/bun-types/docs/cli/publish.md
generated
vendored
Normal file
112
node_modules/bun-types/docs/cli/publish.md
generated
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
Use `bun publish` to publish a package to the npm registry.
|
||||
|
||||
`bun publish` will automatically pack your package into a tarball, strip catalog and workspace protocols from the `package.json` (resolving versions if necessary), and publish to the registry specified in your configuration files. Both `bunfig.toml` and `.npmrc` files are supported.
|
||||
|
||||
```sh
|
||||
## Publishing the package from the current working directory
|
||||
$ bun publish
|
||||
|
||||
## Output
|
||||
bun publish v1.2.19 (ca7428e9)
|
||||
|
||||
packed 203B package.json
|
||||
packed 224B README.md
|
||||
packed 30B index.ts
|
||||
packed 0.64KB tsconfig.json
|
||||
|
||||
Total files: 4
|
||||
Shasum: 79e2b4377b63f4de38dc7ea6e5e9dbee08311a69
|
||||
Integrity: sha512-6QSNlDdSwyG/+[...]X6wXHriDWr6fA==
|
||||
Unpacked size: 1.1KB
|
||||
Packed size: 0.76KB
|
||||
Tag: latest
|
||||
Access: default
|
||||
Registry: http://localhost:4873/
|
||||
|
||||
+ publish-1@1.0.0
|
||||
```
|
||||
|
||||
Alternatively, you can pack and publish your package separately by using `bun pm pack` followed by `bun publish` with the path to the output tarball.
|
||||
|
||||
```sh
|
||||
$ bun pm pack
|
||||
...
|
||||
$ bun publish ./package.tgz
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** - `bun publish` will not run lifecycle scripts (`prepublishOnly/prepack/prepare/postpack/publish/postpublish`) if a tarball path is provided. Scripts will only be run if the package is packed by `bun publish`.
|
||||
{% /callout %}
|
||||
|
||||
### `--access`
|
||||
|
||||
The `--access` flag can be used to set the access level of the package being published. The access level can be one of `public` or `restricted`. Unscoped packages are always public, and attempting to publish an unscoped package with `--access restricted` will result in an error.
|
||||
|
||||
```sh
|
||||
$ bun publish --access public
|
||||
```
|
||||
|
||||
`--access` can also be set in the `publishConfig` field of your `package.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"publishConfig": {
|
||||
"access": "restricted"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `--tag`
|
||||
|
||||
Set the tag of the package version being published. By default, the tag is `latest`. The initial version of a package is always given the `latest` tag in addition to the specified tag.
|
||||
|
||||
```sh
|
||||
$ bun publish --tag alpha
|
||||
```
|
||||
|
||||
`--tag` can also be set in the `publishConfig` field of your `package.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"publishConfig": {
|
||||
"tag": "next"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `--dry-run`
|
||||
|
||||
The `--dry-run` flag can be used to simulate the publish process without actually publishing the package. This is useful for verifying the contents of the published package without actually publishing the package.
|
||||
|
||||
```sh
|
||||
$ bun publish --dry-run
|
||||
```
|
||||
|
||||
### `--gzip-level`
|
||||
|
||||
Specify the level of gzip compression to use when packing the package. Only applies to `bun publish` without a tarball path argument. Values range from `0` to `9` (default is `9`).
|
||||
{% bunCLIUsage command="publish" /%}
|
||||
|
||||
### `--auth-type`
|
||||
|
||||
If you have 2FA enabled for your npm account, `bun publish` will prompt you for a one-time password. This can be done through a browser or the CLI. The `--auth-type` flag can be used to tell the npm registry which method you prefer. The possible values are `web` and `legacy`, with `web` being the default.
|
||||
|
||||
```sh
|
||||
$ bun publish --auth-type legacy
|
||||
...
|
||||
This operation requires a one-time password.
|
||||
Enter OTP: 123456
|
||||
...
|
||||
```
|
||||
|
||||
### `--otp`
|
||||
|
||||
Provide a one-time password directly to the CLI. If the password is valid, this will skip the extra prompt for a one-time password before publishing. Example usage:
|
||||
|
||||
```sh
|
||||
$ bun publish --otp 123456
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** - `bun publish` respects the `NPM_CONFIG_TOKEN` environment variable which can be used when publishing in github actions or automated workflows.
|
||||
{% /callout %}
|
||||
7
node_modules/bun-types/docs/cli/remove.md
generated
vendored
Normal file
7
node_modules/bun-types/docs/cli/remove.md
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
To remove a dependency:
|
||||
|
||||
```bash
|
||||
$ bun remove ts-node
|
||||
```
|
||||
|
||||
{% bunCLIUsage command="remove" /%}
|
||||
226
node_modules/bun-types/docs/cli/run.md
generated
vendored
Normal file
226
node_modules/bun-types/docs/cli/run.md
generated
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
The `bun` CLI can be used to execute JavaScript/TypeScript files, `package.json` scripts, and [executable packages](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#bin).
|
||||
|
||||
## Performance
|
||||
|
||||
Bun is designed to start fast and run fast.
|
||||
|
||||
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. Its transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
|
||||
|
||||
{% table %}
|
||||
|
||||
---
|
||||
|
||||
- `bun hello.js`
|
||||
- `5.2ms`
|
||||
|
||||
---
|
||||
|
||||
- `node hello.js`
|
||||
- `25.1ms`
|
||||
|
||||
{% /table %}
|
||||
{% caption content="Running a simple Hello World script on Linux" /%}
|
||||
|
||||
<!-- {% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%} -->
|
||||
|
||||
<!-- ## Speed -->
|
||||
|
||||
<!--
|
||||
Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers. -->
|
||||
|
||||
## Run a file
|
||||
|
||||
{% callout %}
|
||||
Compare to `node <file>`
|
||||
{% /callout %}
|
||||
|
||||
Use `bun run` to execute a source file.
|
||||
|
||||
```bash
|
||||
$ bun run index.js
|
||||
```
|
||||
|
||||
Bun supports TypeScript and JSX out of the box. Every file is transpiled on the fly by Bun's fast native transpiler before being executed.
|
||||
|
||||
```bash
|
||||
$ bun run index.js
|
||||
$ bun run index.jsx
|
||||
$ bun run index.ts
|
||||
$ bun run index.tsx
|
||||
```
|
||||
|
||||
Alternatively, you can omit the `run` keyword and use the "naked" command; it behaves identically.
|
||||
|
||||
```bash
|
||||
$ bun index.tsx
|
||||
$ bun index.js
|
||||
```
|
||||
|
||||
### `--watch`
|
||||
|
||||
To run a file in watch mode, use the `--watch` flag.
|
||||
|
||||
```bash
|
||||
$ bun --watch run index.tsx
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** — When using `bun run`, put Bun flags like `--watch` immediately after `bun`.
|
||||
|
||||
```bash
|
||||
$ bun --watch run dev # ✔️ do this
|
||||
$ bun run dev --watch # ❌ don't do this
|
||||
```
|
||||
|
||||
Flags that occur at the end of the command will be ignored and passed through to the `"dev"` script itself.
|
||||
{% /callout %}
|
||||
|
||||
## Run a `package.json` script
|
||||
|
||||
{% note %}
|
||||
Compare to `npm run <script>` or `yarn <script>`
|
||||
{% /note %}
|
||||
|
||||
```sh
|
||||
$ bun [bun flags] run <script> [script flags]
|
||||
```
|
||||
|
||||
Your `package.json` can define a number of named `"scripts"` that correspond to shell commands.
|
||||
|
||||
```json
|
||||
{
|
||||
// ... other fields
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist && echo 'Done.'",
|
||||
"dev": "bun server.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `bun run <script>` to execute these scripts.
|
||||
|
||||
```bash
|
||||
$ bun run clean
|
||||
$ rm -rf dist && echo 'Done.'
|
||||
Cleaning...
|
||||
Done.
|
||||
```
|
||||
|
||||
Bun executes the script command in a subshell. On Linux & macOS, it checks for the following shells in order, using the first one it finds: `bash`, `sh`, `zsh`. On windows, it uses [bun shell](https://bun.com/docs/runtime/shell) to support bash-like syntax and many common commands.
|
||||
|
||||
{% callout %}
|
||||
⚡️ The startup time for `npm run` on Linux is roughly 170ms; with Bun it is `6ms`.
|
||||
{% /callout %}
|
||||
|
||||
Scripts can also be run with the shorter command `bun <script>`, however if there is a built-in bun command with the same name, the built-in command takes precedence. In this case, use the more explicit `bun run <script>` command to execute your package script.
|
||||
|
||||
```bash
|
||||
$ bun run dev
|
||||
```
|
||||
|
||||
To see a list of available scripts, run `bun run` without any arguments.
|
||||
|
||||
```bash
|
||||
$ bun run
|
||||
quickstart scripts:
|
||||
|
||||
bun run clean
|
||||
rm -rf dist && echo 'Done.'
|
||||
|
||||
bun run dev
|
||||
bun server.ts
|
||||
|
||||
2 scripts
|
||||
```
|
||||
|
||||
Bun respects lifecycle hooks. For instance, `bun run clean` will execute `preclean` and `postclean`, if defined. If the `pre<script>` fails, Bun will not execute the script itself.
|
||||
|
||||
### `--bun`
|
||||
|
||||
It's common for `package.json` scripts to reference locally-installed CLIs like `vite` or `next`. These CLIs are often JavaScript files marked with a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) to indicate that they should be executed with `node`.
|
||||
|
||||
```js
|
||||
#!/usr/bin/env node
|
||||
|
||||
// do stuff
|
||||
```
|
||||
|
||||
By default, Bun respects this shebang and executes the script with `node`. However, you can override this behavior with the `--bun` flag. For Node.js-based CLIs, this will run the CLI with Bun instead of Node.js.
|
||||
|
||||
```bash
|
||||
$ bun run --bun vite
|
||||
```
|
||||
|
||||
### Filtering
|
||||
|
||||
In monorepos containing multiple packages, you can use the `--filter` argument to execute scripts in many packages at once.
|
||||
|
||||
Use `bun run --filter <name_pattern> <script>` to execute `<script>` in all packages whose name matches `<name_pattern>`.
|
||||
For example, if you have subdirectories containing packages named `foo`, `bar` and `baz`, running
|
||||
|
||||
```bash
|
||||
bun run --filter 'ba*' <script>
|
||||
```
|
||||
|
||||
will execute `<script>` in both `bar` and `baz`, but not in `foo`.
|
||||
|
||||
Find more details in the docs page for [filter](https://bun.com/docs/cli/filter#running-scripts-with-filter).
|
||||
|
||||
## `bun run -` to pipe code from stdin
|
||||
|
||||
`bun run -` lets you read JavaScript, TypeScript, TSX, or JSX from stdin and execute it without writing to a temporary file first.
|
||||
|
||||
```bash
|
||||
$ echo "console.log('Hello')" | bun run -
|
||||
Hello
|
||||
```
|
||||
|
||||
You can also use `bun run -` to redirect files into Bun. For example, to run a `.js` file as if it were a `.ts` file:
|
||||
|
||||
```bash
|
||||
$ echo "console.log!('This is TypeScript!' as any)" > secretly-typescript.js
|
||||
$ bun run - < secretly-typescript.js
|
||||
This is TypeScript!
|
||||
```
|
||||
|
||||
For convenience, all code is treated as TypeScript with JSX support when using `bun run -`.
|
||||
|
||||
## `bun run --console-depth`
|
||||
|
||||
Control the depth of object inspection in console output with the `--console-depth` flag.
|
||||
|
||||
```bash
|
||||
$ bun --console-depth 5 run index.tsx
|
||||
```
|
||||
|
||||
This sets how deeply nested objects are displayed in `console.log()` output. The default depth is `2`. Higher values show more nested properties but may produce verbose output for complex objects.
|
||||
|
||||
```js
|
||||
const nested = { a: { b: { c: { d: "deep" } } } };
|
||||
console.log(nested);
|
||||
// With --console-depth 2 (default): { a: { b: [Object] } }
|
||||
// With --console-depth 4: { a: { b: { c: { d: 'deep' } } } }
|
||||
```
|
||||
|
||||
## `bun run --smol`
|
||||
|
||||
In memory-constrained environments, use the `--smol` flag to reduce memory usage at a cost to performance.
|
||||
|
||||
```bash
|
||||
$ bun --smol run index.tsx
|
||||
```
|
||||
|
||||
This causes the garbage collector to run more frequently, which can slow down execution. However, it can be useful in environments with limited memory. Bun automatically adjusts the garbage collector's heap size based on the available memory (accounting for cgroups and other memory limits) with and without the `--smol` flag, so this is mostly useful for cases where you want to make the heap size grow more slowly.
|
||||
|
||||
## Resolution order
|
||||
|
||||
Absolute paths and paths starting with `./` or `.\\` are always executed as source files. Unless using `bun run`, running a file with an allowed extension will prefer the file over a package.json script.
|
||||
|
||||
When there is a package.json script and a file with the same name, `bun run` prioritizes the package.json script. The full resolution order is:
|
||||
|
||||
1. package.json scripts, eg `bun run build`
|
||||
2. Source files, eg `bun run src/main.js`
|
||||
3. Binaries from project packages, eg `bun add eslint && bun run eslint`
|
||||
4. (`bun run` only) System commands, eg `bun run ls`
|
||||
|
||||
{% bunCLIUsage command="run" /%}
|
||||
280
node_modules/bun-types/docs/cli/test.md
generated
vendored
Normal file
280
node_modules/bun-types/docs/cli/test.md
generated
vendored
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
Bun ships with a fast, built-in, Jest-compatible test runner. Tests are executed with the Bun runtime, and support the following features.
|
||||
|
||||
- TypeScript and JSX
|
||||
- Lifecycle hooks
|
||||
- Snapshot testing
|
||||
- UI & DOM testing
|
||||
- Watch mode with `--watch`
|
||||
- Script pre-loading with `--preload`
|
||||
|
||||
{% callout %}
|
||||
Bun aims for compatibility with Jest, but not everything is implemented. To track compatibility, see [this tracking issue](https://github.com/oven-sh/bun/issues/1825).
|
||||
{% /callout %}
|
||||
|
||||
## Run tests
|
||||
|
||||
```bash
|
||||
$ bun test
|
||||
```
|
||||
|
||||
Tests are written in JavaScript or TypeScript with a Jest-like API. Refer to [Writing tests](https://bun.com/docs/test/writing) for full documentation.
|
||||
|
||||
```ts#math.test.ts
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
test("2 + 2", () => {
|
||||
expect(2 + 2).toBe(4);
|
||||
});
|
||||
```
|
||||
|
||||
The runner recursively searches the working directory for files that match the following patterns:
|
||||
|
||||
- `*.test.{js|jsx|ts|tsx}`
|
||||
- `*_test.{js|jsx|ts|tsx}`
|
||||
- `*.spec.{js|jsx|ts|tsx}`
|
||||
- `*_spec.{js|jsx|ts|tsx}`
|
||||
|
||||
You can filter the set of _test files_ to run by passing additional positional arguments to `bun test`. Any test file with a path that matches one of the filters will run. Commonly, these filters will be file or directory names; glob patterns are not yet supported.
|
||||
|
||||
```bash
|
||||
$ bun test <filter> <filter> ...
|
||||
```
|
||||
|
||||
To filter by _test name_, use the `-t`/`--test-name-pattern` flag.
|
||||
|
||||
```sh
|
||||
# run all tests or test suites with "addition" in the name
|
||||
$ bun test --test-name-pattern addition
|
||||
```
|
||||
|
||||
To run a specific file in the test runner, make sure the path starts with `./` or `/` to distinguish it from a filter name.
|
||||
|
||||
```bash
|
||||
$ bun test ./test/specific-file.test.ts
|
||||
```
|
||||
|
||||
The test runner runs all tests in a single process. It loads all `--preload` scripts (see [Lifecycle](https://bun.com/docs/test/lifecycle) for details), then runs all tests. If a test fails, the test runner will exit with a non-zero exit code.
|
||||
|
||||
## CI/CD integration
|
||||
|
||||
`bun test` supports a variety of CI/CD integrations.
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
`bun test` automatically detects if it's running inside GitHub Actions and will emit GitHub Actions annotations to the console directly.
|
||||
|
||||
No configuration is needed, other than installing `bun` in the workflow and running `bun test`.
|
||||
|
||||
#### How to install `bun` in a GitHub Actions workflow
|
||||
|
||||
To use `bun test` in a GitHub Actions workflow, add the following step:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
name: build-app
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
- name: Install dependencies # (assuming your project has dependencies)
|
||||
run: bun install # You can use npm/yarn/pnpm instead if you prefer
|
||||
- name: Run tests
|
||||
run: bun test
|
||||
```
|
||||
|
||||
From there, you'll get GitHub Actions annotations.
|
||||
|
||||
### JUnit XML reports (GitLab, etc.)
|
||||
|
||||
To use `bun test` with a JUnit XML reporter, you can use the `--reporter=junit` in combination with `--reporter-outfile`.
|
||||
|
||||
```sh
|
||||
$ bun test --reporter=junit --reporter-outfile=./bun.xml
|
||||
```
|
||||
|
||||
This will continue to output to stdout/stderr as usual, and also write a JUnit
|
||||
XML report to the given path at the very end of the test run.
|
||||
|
||||
JUnit XML is a popular format for reporting test results in CI/CD pipelines.
|
||||
|
||||
## Timeouts
|
||||
|
||||
Use the `--timeout` flag to specify a _per-test_ timeout in milliseconds. If a test times out, it will be marked as failed. The default value is `5000`.
|
||||
|
||||
```bash
|
||||
# default value is 5000
|
||||
$ bun test --timeout 20
|
||||
```
|
||||
|
||||
## Rerun tests
|
||||
|
||||
Use the `--rerun-each` flag to run each test multiple times. This is useful for detecting flaky or non-deterministic test failures.
|
||||
|
||||
```sh
|
||||
$ bun test --rerun-each 100
|
||||
```
|
||||
|
||||
## Bail out with `--bail`
|
||||
|
||||
Use the `--bail` flag to abort the test run early after a pre-determined number of test failures. By default Bun will run all tests and report all failures, but sometimes in CI environments it's preferable to terminate earlier to reduce CPU usage.
|
||||
|
||||
```sh
|
||||
# bail after 1 failure
|
||||
$ bun test --bail
|
||||
|
||||
# bail after 10 failure
|
||||
$ bun test --bail=10
|
||||
```
|
||||
|
||||
## Watch mode
|
||||
|
||||
Similar to `bun run`, you can pass the `--watch` flag to `bun test` to watch for changes and re-run tests.
|
||||
|
||||
```bash
|
||||
$ bun test --watch
|
||||
```
|
||||
|
||||
## Lifecycle hooks
|
||||
|
||||
Bun supports the following lifecycle hooks:
|
||||
|
||||
| Hook | Description |
|
||||
| ------------ | --------------------------- |
|
||||
| `beforeAll` | Runs once before all tests. |
|
||||
| `beforeEach` | Runs before each test. |
|
||||
| `afterEach` | Runs after each test. |
|
||||
| `afterAll` | Runs once after all tests. |
|
||||
|
||||
These hooks can be defined inside test files, or in a separate file that is preloaded with the `--preload` flag.
|
||||
|
||||
```ts
|
||||
$ bun test --preload ./setup.ts
|
||||
```
|
||||
|
||||
See [Test > Lifecycle](https://bun.com/docs/test/lifecycle) for complete documentation.
|
||||
|
||||
## Mocks
|
||||
|
||||
Create mock functions with the `mock` function. Mocks are automatically reset between tests.
|
||||
|
||||
```ts
|
||||
import { test, expect, mock } from "bun:test";
|
||||
const random = mock(() => Math.random());
|
||||
|
||||
test("random", () => {
|
||||
const val = random();
|
||||
expect(val).toBeGreaterThan(0);
|
||||
expect(random).toHaveBeenCalled();
|
||||
expect(random).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, you can use `jest.fn()`, it behaves identically.
|
||||
|
||||
```ts-diff
|
||||
- import { test, expect, mock } from "bun:test";
|
||||
+ import { test, expect, jest } from "bun:test";
|
||||
|
||||
- const random = mock(() => Math.random());
|
||||
+ const random = jest.fn(() => Math.random());
|
||||
```
|
||||
|
||||
See [Test > Mocks](https://bun.com/docs/test/mocks) for complete documentation.
|
||||
|
||||
## Snapshot testing
|
||||
|
||||
Snapshots are supported by `bun test`.
|
||||
|
||||
```ts
|
||||
// example usage of toMatchSnapshot
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("snapshot", () => {
|
||||
expect({ a: 1 }).toMatchSnapshot();
|
||||
});
|
||||
```
|
||||
|
||||
To update snapshots, use the `--update-snapshots` flag.
|
||||
|
||||
```sh
|
||||
$ bun test --update-snapshots
|
||||
```
|
||||
|
||||
See [Test > Snapshots](https://bun.com/docs/test/snapshots) for complete documentation.
|
||||
|
||||
## UI & DOM testing
|
||||
|
||||
Bun is compatible with popular UI testing libraries:
|
||||
|
||||
- [HappyDOM](https://github.com/capricorn86/happy-dom)
|
||||
- [DOM Testing Library](https://testing-library.com/docs/dom-testing-library/intro/)
|
||||
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
|
||||
|
||||
See [Test > DOM Testing](https://bun.com/docs/test/dom) for complete documentation.
|
||||
|
||||
## Performance
|
||||
|
||||
Bun's test runner is fast.
|
||||
|
||||
{% image src="/images/buntest.jpeg" caption="Running 266 React SSR tests faster than Jest can print its version number." /%}
|
||||
|
||||
<!--
|
||||
Consider the following directory structure:
|
||||
|
||||
```
|
||||
.
|
||||
├── a.test.ts
|
||||
├── b.test.ts
|
||||
├── c.test.ts
|
||||
└── foo
|
||||
├── a.test.ts
|
||||
└── b.test.ts
|
||||
```
|
||||
|
||||
To run both `a.test.ts` files:
|
||||
|
||||
```
|
||||
$ bun test a
|
||||
```
|
||||
|
||||
To run all tests in the `foo` directory:
|
||||
|
||||
```
|
||||
$ bun test foo
|
||||
```
|
||||
|
||||
Any test file in the directory with an _absolute path_ that contains one of the targets will run. Glob patterns are not yet supported. -->
|
||||
|
||||
## AI Agent Integration
|
||||
|
||||
When using Bun's test runner with AI coding assistants, you can enable quieter output to improve readability and reduce context noise. This feature minimizes test output verbosity while preserving essential failure information.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Set any of the following environment variables to enable AI-friendly output:
|
||||
|
||||
- `CLAUDECODE=1` - For Claude Code
|
||||
- `REPL_ID=1` - For Replit
|
||||
- `AGENT=1` - Generic AI agent flag
|
||||
|
||||
### Behavior
|
||||
|
||||
When an AI agent environment is detected:
|
||||
|
||||
- Only test failures are displayed in detail
|
||||
- Passing, skipped, and todo test indicators are hidden
|
||||
- Summary statistics remain intact
|
||||
|
||||
```bash
|
||||
# Example: Enable quiet output for Claude Code
|
||||
$ CLAUDECODE=1 bun test
|
||||
|
||||
# Still shows failures and summary, but hides verbose passing test output
|
||||
```
|
||||
|
||||
This feature is particularly useful in AI-assisted development workflows where reduced output verbosity improves context efficiency while maintaining visibility into test failures.
|
||||
|
||||
{% bunCLIUsage command="test" /%}
|
||||
9
node_modules/bun-types/docs/cli/unlink.md
generated
vendored
Normal file
9
node_modules/bun-types/docs/cli/unlink.md
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Use `bun unlink` in the root directory to unregister a local package.
|
||||
|
||||
```bash
|
||||
$ cd /path/to/cool-pkg
|
||||
$ bun unlink
|
||||
bun unlink v1.x (7416672e)
|
||||
```
|
||||
|
||||
{% bunCLIUsage command="unlink" /%}
|
||||
36
node_modules/bun-types/docs/cli/update.md
generated
vendored
Normal file
36
node_modules/bun-types/docs/cli/update.md
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
To update all dependencies to the latest version:
|
||||
|
||||
```sh
|
||||
$ bun update
|
||||
```
|
||||
|
||||
To update a specific dependency to the latest version:
|
||||
|
||||
```sh
|
||||
$ bun update [package]
|
||||
```
|
||||
|
||||
## `--latest`
|
||||
|
||||
By default, `bun update` will update to the latest version of a dependency that satisfies the version range specified in your `package.json`.
|
||||
|
||||
To update to the latest version, regardless of if it's compatible with the current version range, use the `--latest` flag:
|
||||
|
||||
```sh
|
||||
$ bun update --latest
|
||||
```
|
||||
|
||||
For example, with the following `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `bun update` would update to a version that matches `17.x`.
|
||||
- `bun update --latest` would update to a version that matches `18.x` or later.
|
||||
|
||||
{% bunCLIUsage command="update" /%}
|
||||
67
node_modules/bun-types/docs/cli/why.md
generated
vendored
Normal file
67
node_modules/bun-types/docs/cli/why.md
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
The `bun why` command explains why a package is installed in your project by showing the dependency chain that led to its installation.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
$ bun why <package>
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
- `<package>`: The name of the package to explain. Supports glob patterns like `@org/*` or `*-lodash`.
|
||||
|
||||
## Options
|
||||
|
||||
- `--top`: Show only the top-level dependencies instead of the complete dependency tree.
|
||||
- `--depth <number>`: Maximum depth of the dependency tree to display.
|
||||
|
||||
## Examples
|
||||
|
||||
Check why a specific package is installed:
|
||||
|
||||
```bash
|
||||
$ bun why react
|
||||
react@18.2.0
|
||||
└─ my-app@1.0.0 (requires ^18.0.0)
|
||||
```
|
||||
|
||||
Check why all packages with a specific pattern are installed:
|
||||
|
||||
```bash
|
||||
$ bun why "@types/*"
|
||||
@types/react@18.2.15
|
||||
└─ dev my-app@1.0.0 (requires ^18.0.0)
|
||||
|
||||
@types/react-dom@18.2.7
|
||||
└─ dev my-app@1.0.0 (requires ^18.0.0)
|
||||
```
|
||||
|
||||
Show only top-level dependencies:
|
||||
|
||||
```bash
|
||||
$ bun why express --top
|
||||
express@4.18.2
|
||||
└─ my-app@1.0.0 (requires ^4.18.2)
|
||||
```
|
||||
|
||||
Limit the dependency tree depth:
|
||||
|
||||
```bash
|
||||
$ bun why express --depth 2
|
||||
express@4.18.2
|
||||
└─ express-pollyfill@1.20.1 (requires ^4.18.2)
|
||||
└─ body-parser@1.20.1 (requires ^1.20.1)
|
||||
└─ accepts@1.3.8 (requires ^1.3.8)
|
||||
└─ (deeper dependencies hidden)
|
||||
```
|
||||
|
||||
## Understanding the Output
|
||||
|
||||
The output shows:
|
||||
|
||||
- The package name and version being queried
|
||||
- The dependency chain that led to its installation
|
||||
- The type of dependency (dev, peer, optional, or production)
|
||||
- The version requirement specified in each package's dependencies
|
||||
|
||||
For nested dependencies, the command shows the complete dependency tree by default, with indentation indicating the relationship hierarchy.
|
||||
57
node_modules/bun-types/docs/contributing/upgrading-webkit.md
generated
vendored
Normal file
57
node_modules/bun-types/docs/contributing/upgrading-webkit.md
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
Bun uses [a fork](https://github.com/oven-sh/WebKit) of WebKit with a small number of changes.
|
||||
|
||||
It's important to periodically update WebKit for many reasons:
|
||||
|
||||
- Security
|
||||
- Performance
|
||||
- Compatibility
|
||||
- …and many more.
|
||||
|
||||
To upgrade, first find the commit in **Bun's WebKit fork** (not Bun!) between when we last upgraded and now.
|
||||
|
||||
```bash
|
||||
$ cd src/bun.js/WebKit # In the WebKit directory! not bun
|
||||
$ git checkout $COMMIT
|
||||
```
|
||||
|
||||
This is the main command to run:
|
||||
|
||||
```bash
|
||||
$ git merge upstream main
|
||||
# If you get an error saying histories are unrelated, run this and try again:
|
||||
$ git fetch --unshallow
|
||||
```
|
||||
|
||||
Then, you will likely see some silly merge conflicts. Fix them and then run:
|
||||
|
||||
```bash
|
||||
# You might have to run this multiple times.
|
||||
$ rm -rf WebKitBuild
|
||||
|
||||
# Go to Bun's directory! Not WebKit.
|
||||
cd ../../../../
|
||||
make jsc-build-mac-compile
|
||||
```
|
||||
|
||||
Make sure that JSC's CLI is able to load successfully. This verifies that the build is working.
|
||||
|
||||
You know this worked when it printed help options. If it complains about symbols, crashes, or anything else that looks wrong, something is wrong.
|
||||
|
||||
```bash
|
||||
src/bun.js/WebKit/WebKitBuild/Release/bin/jsc --help
|
||||
```
|
||||
|
||||
Then, clear out our bindings and regenerate the C++<>Zig headers:
|
||||
|
||||
```bash
|
||||
make clean-bindings headers builtins
|
||||
```
|
||||
|
||||
Now update Bun's bindings wherever there are compiler errors:
|
||||
|
||||
```bash
|
||||
# It will take awhile if you don't pass -j here
|
||||
make bindings -j10
|
||||
```
|
||||
|
||||
This is the hard part. It might involve digging through WebKit's commit history to figure out what changed and why. Fortunately, WebKit contributors write great commit messages.
|
||||
24
node_modules/bun-types/docs/ecosystem/elysia.md
generated
vendored
Normal file
24
node_modules/bun-types/docs/ecosystem/elysia.md
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[Elysia](https://elysiajs.com) is a Bun-first performance focused web framework that takes full advantage of Bun's HTTP, file system, and hot reloading APIs.
|
||||
Designed with TypeScript in mind, you don't need to understand TypeScript to gain the benefit of TypeScript with Elysia. The library understands what you want and automatically infers the type from your code.
|
||||
|
||||
⚡️ Elysia is [one of the fastest Bun web frameworks](https://github.com/SaltyAom/bun-http-framework-benchmark)
|
||||
|
||||
```ts#server.ts
|
||||
import { Elysia } from 'elysia'
|
||||
|
||||
const app = new Elysia()
|
||||
.get('/', () => 'Hello Elysia')
|
||||
.listen(8080)
|
||||
|
||||
console.log(`🦊 Elysia is running at on port ${app.server.port}...`)
|
||||
```
|
||||
|
||||
Get started with `bun create`.
|
||||
|
||||
```bash
|
||||
$ bun create elysia ./myapp
|
||||
$ cd myapp
|
||||
$ bun run dev
|
||||
```
|
||||
|
||||
Refer to the Elysia [documentation](https://elysiajs.com/quick-start.html) for more information.
|
||||
37
node_modules/bun-types/docs/ecosystem/express.md
generated
vendored
Normal file
37
node_modules/bun-types/docs/ecosystem/express.md
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
Projects that use Express and other major Node.js HTTP libraries should work out of the box.
|
||||
|
||||
{% callout %}
|
||||
If you run into bugs, [please file an issue](https://bun.com/issues) _in Bun's repo_, not the library. It is Bun's responsibility to address Node.js compatibility issues.
|
||||
{% /callout %}
|
||||
|
||||
```ts
|
||||
import express from "express";
|
||||
|
||||
const app = express();
|
||||
const port = 8080;
|
||||
|
||||
app.get("/", (req, res) => {
|
||||
res.send("Hello World!");
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Listening on port ${port}...`);
|
||||
});
|
||||
```
|
||||
|
||||
Bun implements the [`node:http`](https://nodejs.org/api/http.html) and [`node:https`](https://nodejs.org/api/https.html) modules that these libraries rely on. These modules can also be used directly, though [`Bun.serve`](https://bun.com/docs/api/http) is recommended for most use cases.
|
||||
|
||||
{% callout %}
|
||||
**Note** — Refer to the [Runtime > Node.js APIs](https://bun.com/docs/runtime/nodejs-apis#node-http) page for more detailed compatibility information.
|
||||
{% /callout %}
|
||||
|
||||
```ts
|
||||
import * as http from "node:http";
|
||||
|
||||
http
|
||||
.createServer(function (req, res) {
|
||||
res.write("Hello World!");
|
||||
res.end();
|
||||
})
|
||||
.listen(8080);
|
||||
```
|
||||
18
node_modules/bun-types/docs/ecosystem/hono.md
generated
vendored
Normal file
18
node_modules/bun-types/docs/ecosystem/hono.md
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[Hono](https://github.com/honojs/hono) is a lightweight ultrafast web framework designed for the edge.
|
||||
|
||||
```ts
|
||||
import { Hono } from "hono";
|
||||
const app = new Hono();
|
||||
|
||||
app.get("/", c => c.text("Hono!"));
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
Get started with `bun create` or follow Hono's [Bun quickstart](https://hono.dev/getting-started/bun).
|
||||
|
||||
```bash
|
||||
$ bun create hono ./myapp
|
||||
$ cd myapp
|
||||
$ bun run start
|
||||
```
|
||||
65
node_modules/bun-types/docs/ecosystem/react.md
generated
vendored
Normal file
65
node_modules/bun-types/docs/ecosystem/react.md
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution.
|
||||
|
||||
```tsx#react.tsx
|
||||
function Component(props: {message: string}) {
|
||||
return (
|
||||
<body>
|
||||
<h1 style={{color: 'red'}}>{props.message}</h1>
|
||||
</body>
|
||||
);
|
||||
}
|
||||
|
||||
console.log(<Component message="Hello world!" />);
|
||||
```
|
||||
|
||||
Bun implements special logging for JSX to make debugging easier.
|
||||
|
||||
```bash
|
||||
$ bun run react.tsx
|
||||
<Component message="Hello world!" />
|
||||
```
|
||||
|
||||
### Prop punning
|
||||
|
||||
The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name.
|
||||
|
||||
```tsx
|
||||
function Div(props: {className: string;}) {
|
||||
const {className} = props;
|
||||
|
||||
// without punning
|
||||
return <div className={className} />;
|
||||
// with punning
|
||||
return <div {className} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Server-side rendering
|
||||
|
||||
To server-side render (SSR) React in an [HTTP server](https://bun.com/docs/api/http):
|
||||
|
||||
```tsx#ssr.tsx
|
||||
import {renderToReadableStream} from 'react-dom/server';
|
||||
|
||||
function Component(props: {message: string}) {
|
||||
return (
|
||||
<body>
|
||||
<h1 style={{color: 'red'}}>{props.message}</h1>
|
||||
</body>
|
||||
);
|
||||
}
|
||||
|
||||
Bun.serve({
|
||||
port: 4000,
|
||||
async fetch() {
|
||||
const stream = await renderToReadableStream(
|
||||
<Component message="Hello from server!" />
|
||||
);
|
||||
return new Response(stream, {
|
||||
headers: {'Content-Type': 'text/html'},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
React `18.3` and later includes an [SSR optimization](https://github.com/facebook/react/pull/25597) that takes advantage of Bun's "direct" `ReadableStream` implementation.
|
||||
38
node_modules/bun-types/docs/ecosystem/stric.md
generated
vendored
Normal file
38
node_modules/bun-types/docs/ecosystem/stric.md
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
[Stric](https://github.com/bunsvr) is a minimalist, fast web framework for Bun.
|
||||
|
||||
```ts#index.ts
|
||||
import { Router } from '@stricjs/router';
|
||||
|
||||
// Export the fetch handler and serve with Bun
|
||||
export default new Router()
|
||||
// Return 'Hi' on every request
|
||||
.get('/', () => new Response('Hi'));
|
||||
```
|
||||
|
||||
Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#src/App.ts
|
||||
import { html } from '@stricjs/arrow/utils';
|
||||
|
||||
// Code inside this function can use web APIs
|
||||
export function render() {
|
||||
// Render a <p> element with text 'Hi'
|
||||
html`<p>Hi</p>`;
|
||||
};
|
||||
|
||||
// Set the path to handle
|
||||
export const path = '/';
|
||||
```
|
||||
|
||||
```ts#index.ts
|
||||
import { PageRouter } from '@stricjs/arrow';
|
||||
|
||||
// Create a page router, build and serve directly
|
||||
new PageRouter().serve();
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
For more info, see Stric's [documentation](https://stricjs.gitbook.io/docs).
|
||||
27
node_modules/bun-types/docs/guides/binary/arraybuffer-to-array.md
generated
vendored
Normal file
27
node_modules/bun-types/docs/guides/binary/arraybuffer-to-array.md
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
name: Convert an ArrayBuffer to an array of numbers
|
||||
---
|
||||
|
||||
To retrieve the contents of an `ArrayBuffer` as an array of numbers, create a [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) over of the buffer. and use the [`Array.from()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) method to convert it to an array.
|
||||
|
||||
```ts
|
||||
const buf = new ArrayBuffer(64);
|
||||
const arr = new Uint8Array(buf);
|
||||
arr.length; // 64
|
||||
arr[0]; // 0 (instantiated with all zeros)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The `Uint8Array` class supports array indexing and iteration. However if you wish to convert the instance to a regular `Array`, use `Array.from()`. (This will likely be slower than using the `Uint8Array` directly.)
|
||||
|
||||
```ts
|
||||
const buf = new ArrayBuffer(64);
|
||||
const uintArr = new Uint8Array(buf);
|
||||
const regularArr = Array.from(uintArr);
|
||||
// number[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
24
node_modules/bun-types/docs/guides/binary/arraybuffer-to-blob.md
generated
vendored
Normal file
24
node_modules/bun-types/docs/guides/binary/arraybuffer-to-blob.md
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
name: Convert an ArrayBuffer to a Blob
|
||||
---
|
||||
|
||||
A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) can be constructed from an array of "chunks", where each chunk is a string, binary data structure, or another `Blob`.
|
||||
|
||||
```ts
|
||||
const buf = new ArrayBuffer(64);
|
||||
const blob = new Blob([buf]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
By default the `type` of the resulting `Blob` will be unset. This can be set manually.
|
||||
|
||||
```ts
|
||||
const buf = new ArrayBuffer(64);
|
||||
const blob = new Blob([buf], { type: "application/octet-stream" });
|
||||
blob.type; // => "application/octet-stream"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
25
node_modules/bun-types/docs/guides/binary/arraybuffer-to-buffer.md
generated
vendored
Normal file
25
node_modules/bun-types/docs/guides/binary/arraybuffer-to-buffer.md
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: Convert an ArrayBuffer to a Buffer
|
||||
---
|
||||
|
||||
The Node.js [`Buffer`](https://nodejs.org/api/buffer.html) API predates the introduction of `ArrayBuffer` into the JavaScript language. Bun implements both.
|
||||
|
||||
Use the static `Buffer.from()` method to create a `Buffer` from an `ArrayBuffer`.
|
||||
|
||||
```ts
|
||||
const arrBuffer = new ArrayBuffer(64);
|
||||
const nodeBuffer = Buffer.from(arrBuffer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To create a `Buffer` that only views a portion of the underlying buffer, pass the offset and length to the constructor.
|
||||
|
||||
```ts
|
||||
const arrBuffer = new ArrayBuffer(64);
|
||||
const nodeBuffer = Buffer.from(arrBuffer, 0, 16); // view first 16 bytes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
15
node_modules/bun-types/docs/guides/binary/arraybuffer-to-string.md
generated
vendored
Normal file
15
node_modules/bun-types/docs/guides/binary/arraybuffer-to-string.md
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Convert an ArrayBuffer to a string
|
||||
---
|
||||
|
||||
Bun implements the Web-standard [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) class for converting between binary data types and strings.
|
||||
|
||||
```ts
|
||||
const buf = new ArrayBuffer(64);
|
||||
const decoder = new TextDecoder();
|
||||
const str = decoder.decode(buf);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
39
node_modules/bun-types/docs/guides/binary/arraybuffer-to-typedarray.md
generated
vendored
Normal file
39
node_modules/bun-types/docs/guides/binary/arraybuffer-to-typedarray.md
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
name: Convert an ArrayBuffer to a Uint8Array
|
||||
---
|
||||
|
||||
A `Uint8Array` is a _typed array_, meaning it is a mechanism for viewing the data in an underlying `ArrayBuffer`.
|
||||
|
||||
```ts
|
||||
const buffer = new ArrayBuffer(64);
|
||||
const arr = new Uint8Array(buffer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Instances of other typed arrays can be created similarly.
|
||||
|
||||
```ts
|
||||
const buffer = new ArrayBuffer(64);
|
||||
|
||||
const arr1 = new Uint8Array(buffer);
|
||||
const arr2 = new Uint16Array(buffer);
|
||||
const arr3 = new Uint32Array(buffer);
|
||||
const arr4 = new Float32Array(buffer);
|
||||
const arr5 = new Float64Array(buffer);
|
||||
const arr6 = new BigInt64Array(buffer);
|
||||
const arr7 = new BigUint64Array(buffer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To create a typed array that only views a portion of the underlying buffer, pass the offset and length to the constructor.
|
||||
|
||||
```ts
|
||||
const buffer = new ArrayBuffer(64);
|
||||
const arr = new Uint8Array(buffer, 0, 16); // view first 16 bytes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Utils](https://bun.com/docs/api/utils) for more useful utilities.
|
||||
14
node_modules/bun-types/docs/guides/binary/blob-to-arraybuffer.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/blob-to-arraybuffer.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Blob to an ArrayBuffer
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, including `.arrayBuffer()`.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
const buf = await blob.arrayBuffer();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/blob-to-dataview.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/blob-to-dataview.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Blob to a DataView
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats. This snippets reads the contents to an `ArrayBuffer`, then creates a `DataView` from the buffer.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
const arr = new DataView(await blob.arrayBuffer());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/blob-to-stream.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/blob-to-stream.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Blob to a ReadableStream
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, including `.stream()`. This returns `Promise<ReadableStream>`.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
const stream = await blob.stream();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
15
node_modules/bun-types/docs/guides/binary/blob-to-string.md
generated
vendored
Normal file
15
node_modules/bun-types/docs/guides/binary/blob-to-string.md
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Convert a Blob to a string
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, including `.text()`.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
const str = await blob.text();
|
||||
// => "hello world"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/blob-to-typedarray.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/blob-to-typedarray.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Blob to a Uint8Array
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats. This snippets reads the contents to an `ArrayBuffer`, then creates a `Uint8Array` from the buffer.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
const arr = new Uint8Array(await blob.arrayBuffer());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/buffer-to-arraybuffer.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/buffer-to-arraybuffer.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Buffer to an ArrayBuffer
|
||||
---
|
||||
|
||||
The Node.js [`Buffer`](https://nodejs.org/api/buffer.html) class provides a way to view and manipulate data in an underlying `ArrayBuffer`, which is available via the `buffer` property.
|
||||
|
||||
```ts
|
||||
const nodeBuf = Buffer.alloc(64);
|
||||
const arrBuf = nodeBuf.buffer;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/buffer-to-blob.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/buffer-to-blob.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Buffer to a blob
|
||||
---
|
||||
|
||||
A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) can be constructed from an array of "chunks", where each chunk is a string, binary data structure (including `Buffer`), or another `Blob`.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello");
|
||||
const blob = new Blob([buf]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
41
node_modules/bun-types/docs/guides/binary/buffer-to-readablestream.md
generated
vendored
Normal file
41
node_modules/bun-types/docs/guides/binary/buffer-to-readablestream.md
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
name: Convert a Buffer to a ReadableStream
|
||||
---
|
||||
|
||||
The naive approach to creating a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) from a [`Buffer`](https://nodejs.org/api/buffer.html) is to use the `ReadableStream` constructor and enqueue the entire array as a single chunk. For a large buffer, this may be undesirable as this approach does not "streaming" the data in smaller chunks.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello world");
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(buf);
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To stream the data in smaller chunks, first create a `Blob` instance from the `Buffer`. Then use the [`Blob.stream()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream) method to create a `ReadableStream` that streams the data in chunks of a specified size.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello world");
|
||||
const blob = new Blob([buf]);
|
||||
const stream = blob.stream();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The chunk size can be set by passing a number to the `.stream()` method.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello world");
|
||||
const blob = new Blob([buf]);
|
||||
|
||||
// set chunk size of 1024 bytes
|
||||
const stream = blob.stream(1024);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
25
node_modules/bun-types/docs/guides/binary/buffer-to-string.md
generated
vendored
Normal file
25
node_modules/bun-types/docs/guides/binary/buffer-to-string.md
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: Convert a Buffer to a string
|
||||
---
|
||||
|
||||
The [`Buffer`](https://nodejs.org/api/buffer.html) class provides a built-in `.toString()` method that converts a `Buffer` to a string.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello");
|
||||
const str = buf.toString();
|
||||
// => "hello"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can optionally specify an encoding and byte range.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.from("hello world!");
|
||||
const str = buf.toString("utf8", 0, 5);
|
||||
// => "hello"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/buffer-to-typedarray.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/buffer-to-typedarray.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Buffer to a Uint8Array
|
||||
---
|
||||
|
||||
The Node.js [`Buffer`](https://nodejs.org/api/buffer.html) class extends [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), so no conversion is needed. All properties and methods on `Uint8Array` are available on `Buffer`.
|
||||
|
||||
```ts
|
||||
const buf = Buffer.alloc(64);
|
||||
buf instanceof Uint8Array; // => true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
15
node_modules/bun-types/docs/guides/binary/dataview-to-string.md
generated
vendored
Normal file
15
node_modules/bun-types/docs/guides/binary/dataview-to-string.md
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Convert a DataView to a string
|
||||
---
|
||||
|
||||
If a [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) contains ASCII-encoded text, you can convert it to a string using the [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) class.
|
||||
|
||||
```ts
|
||||
const dv: DataView = ...;
|
||||
const decoder = new TextDecoder();
|
||||
const str = decoder.decode(dv);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
25
node_modules/bun-types/docs/guides/binary/typedarray-to-arraybuffer.md
generated
vendored
Normal file
25
node_modules/bun-types/docs/guides/binary/typedarray-to-arraybuffer.md
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: Convert a Uint8Array to an ArrayBuffer
|
||||
---
|
||||
|
||||
A [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) is a _typed array_ class, meaning it is a mechanism for viewing data in an underlying `ArrayBuffer`. The underlying `ArrayBuffer` is accessible via the `buffer` property.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(64);
|
||||
arr.buffer; // => ArrayBuffer(64)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The `Uint8Array` may be a view over a _subset_ of the data in the underlying `ArrayBuffer`. In this case, the `buffer` property will return the entire buffer, and the `byteOffset` and `byteLength` properties will indicate the subset.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(64, 16, 32);
|
||||
arr.buffer; // => ArrayBuffer(64)
|
||||
arr.byteOffset; // => 16
|
||||
arr.byteLength; // => 32
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
16
node_modules/bun-types/docs/guides/binary/typedarray-to-blob.md
generated
vendored
Normal file
16
node_modules/bun-types/docs/guides/binary/typedarray-to-blob.md
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: Convert a Uint8Array to a Blob
|
||||
---
|
||||
|
||||
A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) can be constructed from an array of "chunks", where each chunk is a string, binary data structure (including `Uint8Array`), or another `Blob`.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f]);
|
||||
const blob = new Blob([arr]);
|
||||
console.log(await blob.text());
|
||||
// => "hello"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/typedarray-to-buffer.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/typedarray-to-buffer.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Uint8Array to a Buffer
|
||||
---
|
||||
|
||||
The [`Buffer`](https://nodejs.org/api/buffer.html) class extends [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) with a number of additional methods. Use `Buffer.from()` to create a `Buffer` instance from a `Uint8Array`.
|
||||
|
||||
```ts
|
||||
const arr: Uint8Array = ...
|
||||
const buf = Buffer.from(arr);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
14
node_modules/bun-types/docs/guides/binary/typedarray-to-dataview.md
generated
vendored
Normal file
14
node_modules/bun-types/docs/guides/binary/typedarray-to-dataview.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Convert a Uint8Array to a DataView
|
||||
---
|
||||
|
||||
A [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) is a _typed array_ class, meaning it is a mechanism for viewing data in an underlying `ArrayBuffer`. The following snippet creates a [`DataView`] instance over the same range of data as the `Uint8Array`.
|
||||
|
||||
```ts
|
||||
const arr: Uint8Array = ...
|
||||
const dv = new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
41
node_modules/bun-types/docs/guides/binary/typedarray-to-readablestream.md
generated
vendored
Normal file
41
node_modules/bun-types/docs/guides/binary/typedarray-to-readablestream.md
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
name: Convert a Uint8Array to a ReadableStream
|
||||
---
|
||||
|
||||
The naive approach to creating a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) from a [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) is to use the [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) constructor and enqueue the entire array as a single chunk. For larger chunks, this may be undesirable as it isn't actually "streaming" the data.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(64);
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(arr);
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To stream the data in smaller chunks, first create a `Blob` instance from the `Uint8Array`. Then use the [`Blob.stream()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream) method to create a `ReadableStream` that streams the data in chunks of a specified size.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(64);
|
||||
const blob = new Blob([arr]);
|
||||
const stream = blob.stream();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The chunk size can be set by passing a number to the `.stream()` method.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array(64);
|
||||
const blob = new Blob([arr]);
|
||||
|
||||
// set chunk size of 1024 bytes
|
||||
const stream = blob.stream(1024);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
16
node_modules/bun-types/docs/guides/binary/typedarray-to-string.md
generated
vendored
Normal file
16
node_modules/bun-types/docs/guides/binary/typedarray-to-string.md
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: Convert a Uint8Array to a string
|
||||
---
|
||||
|
||||
Bun implements the Web-standard [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) class for converting from binary data types like `Uint8Array` and strings.
|
||||
|
||||
```ts
|
||||
const arr = new Uint8Array([104, 101, 108, 108, 111]);
|
||||
const decoder = new TextDecoder();
|
||||
const str = decoder.decode(arr);
|
||||
// => "hello"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > Binary Data](https://bun.com/docs/api/binary-data#conversion) for complete documentation on manipulating binary data with Bun.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue