From cf6662d48ff288feb35c90f98d6d0716e17a3ad7 Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 13 Nov 2025 05:47:30 +1100 Subject: [PATCH 01/14] types: document configVersion in BunLockFile (#24641) --- packages/bun-types/bun.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 6d66e097c5..c4daec79ac 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -6430,6 +6430,16 @@ declare module "bun" { /** @see https://bun.com/docs/install/catalogs */ catalogs?: Record>; + /** + * `0` / `undefined` for projects created before v1.3.2, `1` for projects created after. + * + * --- + * Right now this only changes the default [install linker strategy](https://bun.com/docs/pm/cli/install#isolated-installs): + * - With `0`, the linker is hoisted. + * - With `1`, the linker is isolated for workspaces and hoisted for single-package projects. + */ + configVersion?: 0 | 1; + /** * ``` * INFO = { prod/dev/optional/peer dependencies, os, cpu, libc (TODO), bin, binDir } From d1fa27acce3b3492191baef98af349c337eba581 Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 13 Nov 2025 05:48:03 +1100 Subject: [PATCH 02/14] docs: document more loaders (#24616) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- docs/bundler/index.mdx | 20 ++++++- docs/bundler/loaders.mdx | 116 ++++++++++++++++++++++++++++++++---- docs/bundler/plugins.mdx | 16 ++++- docs/runtime/plugins.mdx | 16 ++++- packages/bun-types/bun.d.ts | 16 ++++- 5 files changed, 169 insertions(+), 15 deletions(-) diff --git a/docs/bundler/index.mdx b/docs/bundler/index.mdx index 66696f0151..6204c42bca 100644 --- a/docs/bundler/index.mdx +++ b/docs/bundler/index.mdx @@ -160,8 +160,12 @@ Like the Bun runtime, the bundler supports an array of file types out of the box | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `.js` `.jsx` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` | Uses Bun's built-in transpiler to parse the file and transpile TypeScript/JSX syntax to vanilla JavaScript. The bundler executes a set of default transforms including dead code elimination and tree shaking. At the moment Bun does not attempt to down-convert syntax; if you use recently ECMAScript syntax, that will be reflected in the bundled code. | | `.json` | JSON files are parsed and inlined into the bundle as a JavaScript object.

`js
import pkg from "./package.json";
pkg.name; // => "my-package"
` | +| `.jsonc` | JSON with comments. Files are parsed and inlined into the bundle as a JavaScript object.

`js
import config from "./config.jsonc";
config.name; // => "my-config"
` | | `.toml` | TOML files are parsed and inlined into the bundle as a JavaScript object.

`js
import config from "./bunfig.toml";
config.logLevel; // => "debug"
` | +| `.yaml` `.yml` | YAML files are parsed and inlined into the bundle as a JavaScript object.

`js
import config from "./config.yaml";
config.name; // => "my-app"
` | | `.txt` | The contents of the text file are read and inlined into the bundle as a string.

`js
import contents from "./file.txt";
console.log(contents); // => "Hello, world!"
` | +| `.html` | HTML files are processed and any referenced assets (scripts, stylesheets, images) are bundled. | +| `.css` | CSS files are bundled together into a single `.css` file in the output directory. | | `.node` `.wasm` | These files are supported by the Bun runtime, but during bundling they are treated as assets. | ### Assets @@ -1462,7 +1466,21 @@ interface BuildArtifact extends Blob { sourcemap: BuildArtifact | null; } -type Loader = "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "file" | "napi" | "wasm" | "text"; +type Loader = + | "js" + | "jsx" + | "ts" + | "tsx" + | "css" + | "json" + | "jsonc" + | "toml" + | "yaml" + | "text" + | "file" + | "napi" + | "wasm" + | "html"; interface BuildOutput { outputs: BuildArtifact[]; diff --git a/docs/bundler/loaders.mdx b/docs/bundler/loaders.mdx index a610186f58..89e8824679 100644 --- a/docs/bundler/loaders.mdx +++ b/docs/bundler/loaders.mdx @@ -7,7 +7,7 @@ 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` +`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.css` `.json` `.jsonc` `.toml` `.yaml` `.yml` `.txt` `.wasm` `.node` `.html` `.sh` 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 that extend Bun with custom loaders. @@ -85,7 +85,7 @@ If a `.json` file is passed as an entrypoint to the bundler, it will be converte } ``` -```ts Output +```js Output export default { name: "John Doe", age: 35, @@ -97,7 +97,33 @@ export default { --- -### toml +### `jsonc` + +**JSON with Comments loader.** Default for `.jsonc`. + +JSONC (JSON with Comments) files can be directly imported. Bun will parse them, stripping out comments and trailing commas. + +```js +import config from "./config.jsonc"; +console.log(config); +``` + +During bundling, the parsed JSONC is inlined into the bundle as a JavaScript object, identical to the `json` loader. + +```js +var config = { + option: "value", +}; +``` + + + Bun automatically uses the `jsonc` loader for `tsconfig.json`, `jsconfig.json`, `package.json`, and `bun.lock` files, + allowing comments and trailing commas in these files. + + +--- + +### `toml` **TOML loader.** Default for `.toml`. @@ -131,7 +157,7 @@ age = 35 email = "johndoe@example.com" ``` -```ts Output +```js Output export default { name: "John Doe", age: 35, @@ -143,7 +169,53 @@ export default { --- -### text +### `yaml` + +**YAML loader.** Default for `.yaml` and `.yml`. + +YAML files can be directly imported. Bun will parse them with its fast native YAML parser. + +```js +import config from "./config.yaml"; +console.log(config); + +// via import attribute: +import data from "./data.txt" with { type: "yaml" }; +``` + +During bundling, the parsed YAML is inlined into the bundle as a JavaScript object. + +```js +var config = { + name: "my-app", + version: "1.0.0", + // ...other fields +}; +``` + +If a `.yaml` or `.yml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object. + + + +```yaml Input +name: John Doe +age: 35 +email: johndoe@example.com +``` + +```js Output +export default { + name: "John Doe", + age: 35, + email: "johndoe@example.com", +}; +``` + + + +--- + +### `text` **Text loader.** Default for `.txt`. @@ -173,7 +245,7 @@ If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` mod Hello, world! ``` -```ts Output +```js Output export default "Hello, world!"; ``` @@ -181,7 +253,7 @@ export default "Hello, world!"; --- -### napi +### `napi` **Native addon loader.** Default for `.node`. @@ -196,7 +268,7 @@ console.log(addon); --- -### sqlite +### `sqlite` **SQLite loader.** Requires `with { "type": "sqlite" }` import attribute. @@ -226,7 +298,9 @@ Otherwise, the database to embed is copied into the `outdir` with a hashed filen --- -### html +### `html` + +**HTML loader.** Default for `.html`. The `html` loader processes HTML files and bundles any referenced assets. It will: @@ -301,7 +375,27 @@ The `html` loader behaves differently depending on how it's used: --- -### sh +### `css` + +**CSS loader.** Default for `.css`. + +CSS files can be directly imported. The bundler will parse and bundle CSS files, handling `@import` statements and `url()` references. + +```js +import "./styles.css"; +``` + +During bundling, all imported CSS files are bundled together into a single `.css` file in the output directory. + +```css +.my-class { + background: url("./image.png"); +} +``` + +--- + +### `sh` **Bun Shell loader.** Default for `.sh` files. @@ -313,7 +407,7 @@ bun run ./script.sh --- -### file +### `file` **File loader.** Default for all unrecognized file types. diff --git a/docs/bundler/plugins.mdx b/docs/bundler/plugins.mdx index 49caa67bae..58908e352f 100644 --- a/docs/bundler/plugins.mdx +++ b/docs/bundler/plugins.mdx @@ -42,7 +42,21 @@ type PluginBuilder = { config: BuildConfig; }; -type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml"; +type Loader = + | "js" + | "jsx" + | "ts" + | "tsx" + | "json" + | "jsonc" + | "toml" + | "yaml" + | "file" + | "napi" + | "wasm" + | "text" + | "css" + | "html"; ``` ## Usage diff --git a/docs/runtime/plugins.mdx b/docs/runtime/plugins.mdx index a64af263a6..aff34d67a5 100644 --- a/docs/runtime/plugins.mdx +++ b/docs/runtime/plugins.mdx @@ -42,7 +42,21 @@ type PluginBuilder = { config: BuildConfig; }; -type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml"; +type Loader = + | "js" + | "jsx" + | "ts" + | "tsx" + | "json" + | "jsonc" + | "toml" + | "yaml" + | "file" + | "napi" + | "wasm" + | "text" + | "css" + | "html"; ``` ## Usage diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index c4daec79ac..a4d84f4352 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -4041,7 +4041,21 @@ declare module "bun" { | "browser"; /** https://bun.com/docs/bundler/loaders */ - type Loader = "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "file" | "napi" | "wasm" | "text" | "css" | "html"; + type Loader = + | "js" + | "jsx" + | "ts" + | "tsx" + | "json" + | "jsonc" + | "toml" + | "yaml" + | "file" + | "napi" + | "wasm" + | "text" + | "css" + | "html"; interface PluginConstraints { /** From 98a01e5d2ab0e75d26bcb14f32d93a80e7a0f0b2 Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 13 Nov 2025 06:00:05 +1100 Subject: [PATCH 03/14] docs: fix some pages (#24632) --- docs/bundler/css.mdx | 4 +- docs/bundler/esbuild.mdx | 60 ++++++++++++++++++--- docs/guides/deployment/google-cloud-run.mdx | 7 +-- docs/guides/test/snapshot.mdx | 4 +- docs/pm/cli/pm.mdx | 2 +- docs/pm/workspaces.mdx | 3 +- docs/runtime/bunfig.mdx | 1 + docs/runtime/s3.mdx | 2 +- 8 files changed, 62 insertions(+), 21 deletions(-) diff --git a/docs/bundler/css.mdx b/docs/bundler/css.mdx index 628a9fa4b8..730332f173 100644 --- a/docs/bundler/css.mdx +++ b/docs/bundler/css.mdx @@ -34,7 +34,7 @@ By default, Bun's CSS bundler targets the following browsers: The CSS Nesting specification allows you to write more concise and intuitive stylesheets by nesting selectors inside one another. Instead of repeating parent selectors across your CSS file, you can write child styles directly within their parent blocks. -```css title="styles.css" icon="file-code" +```scss title="styles.css" icon="file-code" /* With nesting */ .card { background: white; @@ -100,7 +100,7 @@ This compiles to: The `color-mix()` function gives you an easy way to blend two colors together according to a specified ratio in a chosen color space. This powerful feature lets you create color variations without manually calculating the resulting values. -```css title="styles.css" icon="file-code" +```scss title="styles.css" icon="file-code" .button { /* Mix blue and red in the RGB color space with a 30/70 proportion */ background-color: color-mix(in srgb, blue 30%, red); diff --git a/docs/bundler/esbuild.mdx b/docs/bundler/esbuild.mdx index d9cd38efd7..10d6ae7591 100644 --- a/docs/bundler/esbuild.mdx +++ b/docs/bundler/esbuild.mdx @@ -231,23 +231,67 @@ const myPlugin: BunPlugin = { ### onResolve - - 🟒 `filter` - 🟒 `namespace` + + + - 🟒 `filter` + - 🟒 `namespace` + + - - 🟒 `path` - 🟒 `importer` - πŸ”΄ `namespace` - πŸ”΄ `resolveDir` - πŸ”΄ `kind` - πŸ”΄ `pluginData` + + - 🟒 `path` + - 🟒 `importer` + - πŸ”΄ `namespace` + - πŸ”΄ `resolveDir` + - πŸ”΄ `kind` + - πŸ”΄ `pluginData` + - - 🟒 `namespace` - 🟒 `path` - πŸ”΄ `errors` - πŸ”΄ `external` - πŸ”΄ `pluginData` - πŸ”΄ `pluginName` - πŸ”΄ `sideEffects` - - πŸ”΄ `suffix` - πŸ”΄ `warnings` - πŸ”΄ `watchDirs` - πŸ”΄ `watchFiles` + + - 🟒 `namespace` + - 🟒 `path` + - πŸ”΄ `errors` + - πŸ”΄ `external` + - πŸ”΄ `pluginData` + - πŸ”΄ `pluginName` + - πŸ”΄ `sideEffects` + - πŸ”΄ `suffix` + - πŸ”΄ `warnings` + - πŸ”΄ `watchDirs` + - πŸ”΄ `watchFiles` + ### onLoad - - 🟒 `filter` - 🟒 `namespace` - - 🟒 `path` - πŸ”΄ `namespace` - πŸ”΄ `suffix` - πŸ”΄ `pluginData` + + + - 🟒 `filter` + - 🟒 `namespace` + + + + + - 🟒 `path` + - πŸ”΄ `namespace` + - πŸ”΄ `suffix` + - πŸ”΄ `pluginData` + + - - 🟒 `contents` - 🟒 `loader` - πŸ”΄ `errors` - πŸ”΄ `pluginData` - πŸ”΄ `pluginName` - πŸ”΄ `resolveDir` - πŸ”΄ `warnings` - - πŸ”΄ `watchDirs` - πŸ”΄ `watchFiles` + + - 🟒 `contents` + - 🟒 `loader` + - πŸ”΄ `errors` + - πŸ”΄ `pluginData` + - πŸ”΄ `pluginName` + - πŸ”΄ `resolveDir` + - πŸ”΄ `warnings` + - πŸ”΄ `watchDirs` + - πŸ”΄ `watchFiles` + diff --git a/docs/guides/deployment/google-cloud-run.mdx b/docs/guides/deployment/google-cloud-run.mdx index 153f61fc69..4e6aac5182 100644 --- a/docs/guides/deployment/google-cloud-run.mdx +++ b/docs/guides/deployment/google-cloud-run.mdx @@ -132,9 +132,7 @@ CMD ["bun", "index.ts"] Make sure that the start command corresponds to your application's entry point. This can also be `CMD ["bun", "run", "start"]` if you have a start script in your `package.json`. - This image installs dependencies and runs your app with Bun inside a container. If your app doesn't have dependencies, you can omit the `RUN bun install --production --frozen-lockfile` line. - - This image installs dependencies and runs your app with Bun inside a container. If your app doesn't have dependencies, you can omit the `RUN bun install --production --frozen-lockfile` line. +This image installs dependencies and runs your app with Bun inside a container. If your app doesn't have dependencies, you can omit the `RUN bun install --production --frozen-lockfile` line. @@ -159,8 +157,7 @@ Make sure you're in the directory containing your `Dockerfile`, then deploy dire Update the `--region` flag to your preferred region. You can also omit this flag to get an interactive prompt to - select a region. Update the `--region` flag to your preferred region. You can also omit this flag to get an - interactive prompt to select a region. + select a region. ```bash terminal icon="terminal" diff --git a/docs/guides/test/snapshot.mdx b/docs/guides/test/snapshot.mdx index 1141c42f21..df16c0f73d 100644 --- a/docs/guides/test/snapshot.mdx +++ b/docs/guides/test/snapshot.mdx @@ -64,10 +64,10 @@ Later, when this test file is executed again, Bun will read the snapshot file an ```sh terminal icon="terminal" bun test -bun test v1.3.2 (9c68abdb) ``` ```txt +bun test v1.3.2 (9c68abdb) test/snap.test.ts: βœ“ snapshot [1.05ms] @@ -83,10 +83,10 @@ To update snapshots, use the `--update-snapshots` flag. ```sh terminal icon="terminal" bun test --update-snapshots -bun test v1.3.2 (9c68abdb) ``` ```txt +bun test v1.3.2 (9c68abdb) test/snap.test.ts: βœ“ snapshot [0.86ms] diff --git a/docs/pm/cli/pm.mdx b/docs/pm/cli/pm.mdx index b5683f8c52..d2f1cca971 100644 --- a/docs/pm/cli/pm.mdx +++ b/docs/pm/cli/pm.mdx @@ -303,7 +303,7 @@ scripts[test:watch] # bracket for special chars Examples: ```bash terminal icon="terminal" -# set +# get bun pm pkg get name # single property bun pm pkg get name version # multiple properties bun pm pkg get # entire package.json diff --git a/docs/pm/workspaces.mdx b/docs/pm/workspaces.mdx index 3d220aa1e7..6570597dd4 100644 --- a/docs/pm/workspaces.mdx +++ b/docs/pm/workspaces.mdx @@ -7,8 +7,7 @@ Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v It's common for a monorepo to have the following structure: -``` -tree +```txt File Tree icon="folder-tree" β”œβ”€β”€ README.md β”œβ”€β”€ bun.lock diff --git a/docs/runtime/bunfig.mdx b/docs/runtime/bunfig.mdx index fef0c10d19..57fb1805f0 100644 --- a/docs/runtime/bunfig.mdx +++ b/docs/runtime/bunfig.mdx @@ -401,6 +401,7 @@ Environment variable: `BUN_INSTALL_BIN` ```toml title="bunfig.toml" icon="settings" # where globally-installed package bins are linked +[install] globalBinDir = "~/.bun/bin" ``` diff --git a/docs/runtime/s3.mdx b/docs/runtime/s3.mdx index 992293f85e..e4831efc7b 100644 --- a/docs/runtime/s3.mdx +++ b/docs/runtime/s3.mdx @@ -697,7 +697,7 @@ To list some or all (up to 1,000) objects in a bucket, you can use the `S3Client ```ts s3.ts icon="/icons/typescript.svg" highlight={12, 15-20, 24-29} import { S3Client } from "bun"; -const credentials = { ... } +const credentials = { accessKeyId: "your-access-key", secretAccessKey: "your-secret-key", bucket: "my-bucket", From 7f8dff64c4b89e1122c628851acd0a31b7dd272c Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 13 Nov 2025 06:01:25 +1100 Subject: [PATCH 04/14] docs: revert minifier doc's format (#24639) --- .prettierignore | 3 + docs/bundler/minifier.mdx | 702 ++++++++++++++++++-------------------- 2 files changed, 344 insertions(+), 361 deletions(-) diff --git a/.prettierignore b/.prettierignore index 040f49fb17..548265d59b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,3 +9,6 @@ test/snippets test/js/node/test test/napi/node-napi-tests bun.lock + +# the output codeblocks need to stay minified +docs/bundler/minifier.mdx diff --git a/docs/bundler/minifier.mdx b/docs/bundler/minifier.mdx index 56a004e295..2cf4866030 100644 --- a/docs/bundler/minifier.mdx +++ b/docs/bundler/minifier.mdx @@ -103,13 +103,13 @@ Renames local variables and function names to shorter identifiers using frequenc Converts boolean literals to shorter expressions. ```ts Input -true; -false; +true +false ``` -```ts Output -!0; -!1; +```js Output +!0 +!1 ``` ### Boolean algebra optimizations @@ -119,21 +119,21 @@ false; Simplifies boolean expressions using logical rules. ```ts Input -!!x; -x === true; -x && true; -x || false; -!true; -!false; +!!x +x === true +x && true +x || false +!true +!false ``` -```ts Output -x; -x; -x; -x; -!1; -!0; +```js Output +x +x +x +x +!1 +!0 ``` ### Undefined shortening @@ -143,13 +143,13 @@ x; Replaces `undefined` with shorter equivalent. ```ts Input -undefined; +undefined let x = undefined; ``` -```ts Output -void 0; -let x = void 0; +```js Output +void 0 +let x=void 0; ``` ### Undefined equality optimization @@ -159,13 +159,13 @@ let x = void 0; Optimizes loose equality checks with undefined. ```ts Input -x == undefined; -x != undefined; +x == undefined +x != undefined ``` -```ts Output -x == null; -x != null; +```js Output +x == null +x != null ``` ### Infinity shortening @@ -175,11 +175,13 @@ x != null; Converts Infinity to mathematical expressions. ```ts Input -Infinity - Infinity; +Infinity +-Infinity ``` -```ts Output -1 / 0 - 1 / 0; +```js Output +1/0 +-1/0 ``` ### Typeof optimizations @@ -189,25 +191,25 @@ Infinity - Infinity; Optimizes typeof comparisons and evaluates constant typeof expressions. ```ts Input -typeof x === "undefined"; -typeof x !== "undefined"; -typeof require; -typeof null; -typeof true; -typeof 123; -typeof "str"; -typeof 123n; +typeof x === 'undefined' +typeof x !== 'undefined' +typeof require +typeof null +typeof true +typeof 123 +typeof "str" +typeof 123n ``` -```ts Output -typeof x > "u"; -typeof x < "u"; -("function"); -("object"); -("boolean"); -("number"); -("string"); -("bigint"); +```js Output +typeof x>'u' +typeof x<'u' +"function" +"object" +"boolean" +"number" +"string" +"bigint" ``` ### Number formatting @@ -217,17 +219,19 @@ typeof x < "u"; Formats numbers in the most compact representation. ```ts Input -10000; -100000; -1000000; -1.0 - 42.0; +10000 +100000 +1000000 +1.0 +-42.0 ``` -```ts Output -1e4; -1e5; -1e6; -1 - 42; +```js Output +1e4 +1e5 +1e6 +1 +-42 ``` ### Arithmetic constant folding @@ -237,21 +241,21 @@ Formats numbers in the most compact representation. Evaluates arithmetic operations at compile time. ```ts Input -1 + 2; -10 - 5; -3 * 4; -10 / 2; -10 % 3; -2 ** 3; +1 + 2 +10 - 5 +3 * 4 +10 / 2 +10 % 3 +2 ** 3 ``` -```ts Output -3; -5; -12; -5; -1; -8; +```js Output +3 +5 +12 +5 +1 +8 ``` ### Bitwise constant folding @@ -261,20 +265,21 @@ Evaluates arithmetic operations at compile time. Evaluates bitwise operations at compile time. ```ts Input -5 & 3; -5 | 3; -5 ^ 3; -8 << 2; -32 >> 2; -~5; +5 & 3 +5 | 3 +5 ^ 3 +8 << 2 +32 >> 2 +~5 ``` -```ts Output -1; -7; -6; -32; -8 - 6; +```js Output +1 +7 +6 +32 +8 +-6 ``` ### String concatenation @@ -284,15 +289,15 @@ Evaluates bitwise operations at compile time. Combines string literals at compile time. ```ts Input -"a" + "b"; -"x" + 123; -"foo" + "bar" + "baz"; +"a" + "b" +"x" + 123 +"foo" + "bar" + "baz" ``` -```ts Output -"ab"; -"x123"; -"foobarbaz"; +```js Output +"ab" +"x123" +"foobarbaz" ``` ### String indexing @@ -302,13 +307,13 @@ Combines string literals at compile time. Evaluates string character access at compile time. ```ts Input -"foo"[2]; -"hello"[0]; +"foo"[2] +"hello"[0] ``` -```ts Output -"o"; -"h"; +```js Output +"o" +"h" ``` ### Template literal folding @@ -318,12 +323,13 @@ Evaluates string character access at compile time. Evaluates template literals with constant expressions. ```ts Input -`a${123}b``result: ${5 + 10}`; +`a${123}b` +`result: ${5 + 10}` ``` -```ts Output -"a123b"; -"result: 15"; +```js Output +"a123b" +"result: 15" ``` ### Template literal to string conversion @@ -333,13 +339,14 @@ Evaluates template literals with constant expressions. Converts simple template literals to regular strings. ```ts Input -`Hello World``Line 1 -Line 2`; +`Hello World` +`Line 1 +Line 2` ``` -```ts Output -"Hello World"; -"Line 1\nLine 2"; +```js Output +"Hello World" +"Line 1\nLine 2" ``` ### String quote optimization @@ -349,14 +356,15 @@ Line 2`; Chooses the optimal quote character to minimize escapes. ```ts Input -"It's a string"; -'He said "hello"'`Simple string`; +"It's a string" +'He said "hello"' +`Simple string` ``` -```ts Output -"It's a string"; -'He said "hello"'; -"Simple string"; +```js Output +"It's a string" +'He said "hello"' +"Simple string" ``` ### Array spread inlining @@ -370,8 +378,9 @@ Inlines array spread operations with constant arrays. [...[a, b]] ``` -```ts Output -[1, 2, 3, 4][(a, b)]; +```js Output +[1,2,3,4] +[a,b] ``` ### Array indexing @@ -386,10 +395,10 @@ Evaluates constant array access at compile time. ['a', , 'c'][1] ``` -```ts Output -x; -("b"); -void 0; +```js Output +x +'b' +void 0 ``` ### Property access optimization @@ -399,17 +408,17 @@ void 0; Converts bracket notation to dot notation when possible. ```ts Input -obj["property"]; -obj["validName"]; -obj["123"]; -obj["invalid-name"]; +obj["property"] +obj["validName"] +obj["123"] +obj["invalid-name"] ``` -```ts Output -obj.property; -obj.validName; -obj["123"]; -obj["invalid-name"]; +```js Output +obj.property +obj.validName +obj["123"] +obj["invalid-name"] ``` ### Comparison folding @@ -419,19 +428,19 @@ obj["invalid-name"]; Evaluates constant comparisons at compile time. ```ts Input -3 < 5; -5 > 3; -3 <= 3; -5 >= 6; -"a" < "b"; +3 < 5 +5 > 3 +3 <= 3 +5 >= 6 +"a" < "b" ``` -```ts Output -!0; -!0; -!0; -!1; -!0; +```js Output +!0 +!0 +!0 +!1 +!0 ``` ### Logical operation folding @@ -441,17 +450,17 @@ Evaluates constant comparisons at compile time. Simplifies logical operations with constant values. ```ts Input -true && x; -false && x; -true || x; -false || x; +true && x +false && x +true || x +false || x ``` -```ts Output -x; -!1; -!0; -x; +```js Output +x +!1 +!0 +x ``` ### Nullish coalescing folding @@ -461,15 +470,15 @@ x; Evaluates nullish coalescing with known values. ```ts Input -null ?? x; -undefined ?? x; -42 ?? x; +null ?? x +undefined ?? x +42 ?? x ``` -```ts Output -x; -x; -42; +```js Output +x +x +42 ``` ### Comma expression simplification @@ -479,12 +488,13 @@ x; Removes side-effect-free expressions from comma sequences. ```ts Input -(0, x)(123, "str", x); +(0, x) +(123, "str", x) ``` -```ts Output -x; -x; +```js Output +x +x ``` ### Ternary conditional folding @@ -494,17 +504,17 @@ x; Evaluates conditional expressions with constant conditions. ```ts Input -true ? a : b; -false ? a : b; -x ? true : false; -x ? false : true; +true ? a : b +false ? a : b +x ? true : false +x ? false : true ``` -```ts Output -a; -b; -x; -!x; +```js Output +a +b +x ? !0 : !1 +x ? !1 : !0 ``` ### Unary expression folding @@ -514,17 +524,22 @@ x; Simplifies unary operations. ```ts Input -+123 + "123" - -x; -~~x; -!!x; ++123 ++"123" +-(-x) +~~x +!!x ``` -```ts Output -123; -123; -x; -x; -x; +```js Output +123 +123 +123 +123 +x +~~x +!!x +x ``` ### Double negation removal @@ -534,13 +549,13 @@ x; Removes unnecessary double negations. ```ts Input -!!x; -!!!x; +!!x +!!!x ``` -```ts Output -x; -!x; +```js Output +x +!x ``` ### If statement optimization @@ -552,18 +567,15 @@ Optimizes if statements with constant conditions. ```ts Input if (true) x; if (false) x; -if (x) { - a; -} -if (x) { -} else y; +if (x) { a; } +if (x) {} else y; ``` -```ts Output +```js Output x; // removed -if (x) a; -if (!x) y; +if(x)a; +if(!x)y; ``` ### Dead code elimination @@ -582,10 +594,8 @@ function foo() { } ``` -```ts Output -function foo() { - return x; -} +```js Output +function foo(){return x} ``` ### Unreachable branch removal @@ -600,7 +610,7 @@ while (false) { } ``` -```ts Output +```js Output // removed entirely ``` @@ -611,13 +621,12 @@ while (false) { Removes empty blocks and unnecessary braces. ```ts Input -{ -} -if (x) { -} +{ } +if (x) { } ``` -```ts Output +```js Output +; // removed ``` @@ -633,8 +642,8 @@ if (condition) { } ``` -```ts Output -if (condition) doSomething(); +```js Output +if(condition)doSomething(); ``` ### TypeScript enum inlining @@ -644,16 +653,12 @@ if (condition) doSomething(); Inlines TypeScript enum values at compile time. ```ts Input -enum Color { - Red, - Green, - Blue, -} +enum Color { Red, Green, Blue } const x = Color.Red; ``` -```ts Output -const x = 0; +```js Output +const x=0; ``` ### Pure annotation support @@ -667,7 +672,7 @@ const x = /*@__PURE__*/ expensive(); // If x is unused... ``` -```ts Output +```js Output // removed entirely ``` @@ -684,11 +689,8 @@ function calculateSum(firstNumber, secondNumber) { } ``` -```ts Output -function a(b, c) { - const d = b + c; - return d; -} +```js Output +function a(b,c){const d=b+c;return d} ``` **Naming strategy:** @@ -713,16 +715,13 @@ Removes all unnecessary whitespace. ```ts Input function add(a, b) { - return a + b; + return a + b; } let x = 10; ``` -```ts Output -function add(a, b) { - return a + b; -} -let x = 10; +```js Output +function add(a,b){return a+b;}let x=10; ``` ### Semicolon optimization @@ -737,10 +736,8 @@ let b = 2; return a + b; ``` -```ts Output -let a = 1; -let b = 2; -return a + b; +```js Output +let a=1;let b=2;return a+b ``` ### Operator spacing removal @@ -750,15 +747,15 @@ return a + b; Removes spaces around operators. ```ts Input -a + b; -x = y * z; -(foo && bar) || baz; +a + b +x = y * z +foo && bar || baz ``` -```ts Output -a + b; -x = y * z; -(foo && bar) || baz; +```js Output +a+b +x=y*z +foo&&bar||baz ``` ### Comment removal @@ -771,14 +768,12 @@ Removes comments except important license comments. // This comment is removed /* So is this */ /*! But this license comment is kept */ -function test() { - /* inline comment */ -} +function test() { /* inline comment */ } ``` -```ts Output +```js Output /*! But this license comment is kept */ -function test() {} +function test(){} ``` ### Object and array formatting @@ -789,15 +784,14 @@ Removes whitespace in object and array literals. ```ts Input const obj = { - name: "John", - age: 30, + name: "John", + age: 30 }; const arr = [1, 2, 3]; ``` -```ts Output -const obj = { name: "John", age: 30 }; -const arr = [1, 2, 3]; +```js Output +const obj={name:"John",age:30};const arr=[1,2,3]; ``` ### Control flow formatting @@ -808,16 +802,15 @@ Removes whitespace in control structures. ```ts Input if (condition) { - doSomething(); + doSomething(); } for (let i = 0; i < 10; i++) { - console.log(i); + console.log(i); } ``` -```ts Output -if (condition) doSomething(); -for (let i = 0; i < 10; i++) console.log(i); +```js Output +if(condition)doSomething();for(let i=0;i<10;i++)console.log(i); ``` ### Function formatting @@ -828,16 +821,13 @@ Removes whitespace in function declarations. ```ts Input function myFunction(param1, param2) { - return param1 + param2; + return param1 + param2; } const arrow = (a, b) => a + b; ``` -```ts Output -function myFunction(a, b) { - return a + b; -} -const arrow = (a, b) => a + b; +```js Output +function myFunction(a,b){return a+b}const arrow=(a,b)=>a+b; ``` ### Parentheses minimization @@ -847,14 +837,15 @@ const arrow = (a, b) => a + b; Only adds parentheses when necessary for operator precedence. ```ts Input -(a + b) * c; -a + (b * c)(x); +(a + b) * c +a + (b * c) +((x)) ``` -```ts Output -(a + b) * c; -a + b * c; -x; +```js Output +(a+b)*c +a+b*c +x ``` ### Property mangling @@ -863,12 +854,12 @@ x; Renames object properties to shorter names when configured. -```ts#input.ts (with property mangling enabled) +```ts Input obj.longPropertyName ``` -```ts Output -obj.a; +```js Output (with property mangling enabled) +obj.a ``` ### Template literal value folding @@ -878,15 +869,19 @@ obj.a; Converts non-string interpolated values to strings and folds them into the template. ```ts Input -`hello ${123}``value: ${true}``result: ${null}``status: ${undefined}``big: ${10n}`; +`hello ${123}` +`value: ${true}` +`result: ${null}` +`status: ${undefined}` +`big: ${10n}` ``` -```ts Output -"hello 123"; -"value: true"; -"result: null"; -"status: undefined"; -"big: 10"; +```js Output +"hello 123" +"value: true" +"result: null" +"status: undefined" +"big: 10" ``` ### String length constant folding @@ -896,13 +891,13 @@ Converts non-string interpolated values to strings and folds them into the templ Evaluates `.length` property on string literals at compile time. ```ts Input -"hello world".length; -"test".length; +"hello world".length +"test".length ``` -```ts Output -11; -4; +```js Output +11 +4 ``` ### Constructor call simplification @@ -912,22 +907,19 @@ Evaluates `.length` property on string literals at compile time. Simplifies constructor calls for built-in types. ```ts Input -new Object(); -new Object(null); -new Object({ a: 1 }); -new Array(); -new Array(x, y); +new Object() +new Object(null) +new Object({a: 1}) +new Array() +new Array(x, y) ``` -```ts Output -{ -} -{ -} -{ - a: 1; -} -[][(x, y)]; +```js Output +{} +{} +{a:1} +[] +[x,y] ``` ### Single property object inlining @@ -937,11 +929,11 @@ new Array(x, y); Inlines property access for objects with a single property. ```ts Input -({ fn: () => console.log("hi") }).fn(); +({fn: () => console.log('hi')}).fn() ``` -```ts Output -(() => console.log("hi"))(); +```js Output +(() => console.log('hi'))() ``` ### String charCodeAt constant folding @@ -951,13 +943,13 @@ Inlines property access for objects with a single property. Evaluates `charCodeAt()` on string literals for ASCII characters. ```ts Input -"hello".charCodeAt(1); -"A".charCodeAt(0); +"hello".charCodeAt(1) +"A".charCodeAt(0) ``` -```ts Output -101; -65; +```js Output +101 +65 ``` ### Void 0 equality to null equality @@ -967,13 +959,13 @@ Evaluates `charCodeAt()` on string literals for ASCII characters. Converts loose equality checks with `void 0` to `null` since they're equivalent. ```ts Input -x == void 0; -x != void 0; +x == void 0 +x != void 0 ``` -```ts Output -x == null; -x != null; +```js Output +x == null +x != null ``` ### Negation operator optimization @@ -983,12 +975,13 @@ x != null; Moves negation operator through comma expressions. ```ts Input --(a, b) - (x, y, z); +-(a, b) +-(x, y, z) ``` -```ts Output -(a, -b); -(x, y, -z); +```js Output +a,-b +x,y,-z ``` ### Import.meta property inlining @@ -998,17 +991,17 @@ Moves negation operator through comma expressions. Inlines `import.meta` properties at build time when values are known. ```ts Input -import.meta.dir; -import.meta.file; -import.meta.path; -import.meta.url; +import.meta.dir +import.meta.file +import.meta.path +import.meta.url ``` -```ts Output -"/path/to/directory"; -"filename.js"; -"/full/path/to/file.js"; -"file:///full/path/to/file.js"; +```js Output +"/path/to/directory" +"filename.js" +"/full/path/to/file.js" +"file:///full/path/to/file.js" ``` ### Variable declaration merging @@ -1024,11 +1017,9 @@ const c = 3; const d = 4; ``` -```ts Output -let a = 1, - b = 2; -const c = 3, - d = 4; +```js Output +let a=1,b=2; +const c=3,d=4; ``` ### Expression statement merging @@ -1043,8 +1034,8 @@ console.log(2); console.log(3); ``` -```ts Output -(console.log(1), console.log(2), console.log(3)); +```js Output +console.log(1),console.log(2),console.log(3); ``` ### Return statement merging @@ -1058,8 +1049,8 @@ console.log(x); return y; ``` -```ts Output -return (console.log(x), y); +```js Output +return console.log(x),y; ``` ### Throw statement merging @@ -1073,8 +1064,8 @@ console.log(x); throw new Error(); ``` -```ts Output -throw (console.log(x), new Error()); +```js Output +throw(console.log(x),new Error()); ``` ### TypeScript enum cross-module inlining @@ -1083,7 +1074,8 @@ throw (console.log(x), new Error()); Inlines enum values across module boundaries. -```ts#input.ts (lib.ts) +```ts Input +// lib.ts export enum Color { Red, Green, Blue } // Input (main.ts) @@ -1091,8 +1083,8 @@ import { Color } from './lib'; const x = Color.Red; ``` -```ts Output -const x = 0; +```js Output +const x=0; ``` ### Computed property enum inlining @@ -1102,14 +1094,12 @@ const x = 0; Inlines enum values used as computed object properties. ```ts Input -enum Keys { - FOO = "foo", -} -const obj = { [Keys.FOO]: value }; +enum Keys { FOO = 'foo' } +const obj = { [Keys.FOO]: value } ``` -```ts Output -const obj = { foo: value }; +```js Output +const obj={foo:value} ``` ### String number to numeric index @@ -1119,13 +1109,13 @@ const obj = { foo: value }; Converts string numeric property access to numeric index. ```ts Input -obj["0"]; -arr["5"]; +obj["0"] +arr["5"] ``` -```ts Output -obj[0]; -arr[5]; +```js Output +obj[0] +arr[5] ``` ### Arrow function body shortening @@ -1135,17 +1125,13 @@ arr[5]; Uses expression body syntax when an arrow function only returns a value. ```ts Input -() => { - return x; -}; -a => { - return a + 1; -}; +() => { return x; } +(a) => { return a + 1; } ``` -```ts Output -() => x; -a => a + 1; +```js Output +() => x +a => a + 1 ``` ### Object property shorthand @@ -1159,13 +1145,9 @@ Uses shorthand syntax when property name and value identifier match. { name: name, age: age } ``` -```ts Output -{ - (x, y); -} -{ - (name, age); -} +```js Output +{ x, y } +{ name, age } ``` ### Method shorthand @@ -1181,7 +1163,7 @@ Uses method shorthand syntax in object literals. } ``` -```ts Output +```js Output { foo() {}, async bar() {} @@ -1201,10 +1183,8 @@ function test() { } ``` -```ts Output -function test() { - return x; -} +```js Output +function test(){return x} ``` ### Drop console calls @@ -1219,10 +1199,10 @@ console.warn("warning"); x = console.error("error"); ``` -```ts Output +```js Output void 0; void 0; -x = void 0; +x=void 0; ``` ### Drop custom function calls @@ -1231,12 +1211,12 @@ x = void 0; Removes calls to specified global functions or methods. -```ts#input.ts with --drop=assert +```ts Input assert(condition); obj.assert(test); ``` -```ts Output +```js Output with --drop=assert void 0; void 0; ``` @@ -1268,7 +1248,7 @@ This preserves the `.name` property on functions and classes while still minifyi Using all three minification modes together: -```ts#input.ts (158 bytes) +```ts input.ts (158 bytes) const myVariable = 42; const myFunction = () => { @@ -1280,7 +1260,7 @@ const myFunction = () => { const output = myFunction(); ``` -```ts#output.ts +```js output.js // Output with --minify (49 bytes, 69% reduction) const a=42,b=()=>{const c=!0,d=void 0;return c?a:d},e=b(); ``` From fa099336dac14b40c4cb17ebff53112e8de3e73d Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 13 Nov 2025 06:02:12 +1100 Subject: [PATCH 05/14] docs: node does support "import path re-mapping" (#17133) fixes #4545 --- docs/runtime/module-resolution.mdx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/runtime/module-resolution.mdx b/docs/runtime/module-resolution.mdx index 2dcd123621..a43843eec6 100644 --- a/docs/runtime/module-resolution.mdx +++ b/docs/runtime/module-resolution.mdx @@ -276,7 +276,7 @@ await Bun.build({ ## Path re-mapping -In the spirit of treating TypeScript as a first-class citizen, the Bun runtime will re-map import paths according to the [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) field in `tsconfig.json`. This is a major divergence from Node.js, which doesn't support any form of import path re-mapping. +Bun supports import path re-mapping through TypeScript's [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in `tsconfig.json`, which works well with editors. If you aren't a TypeScript user, you can achieve the same behavior by using a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root. ```json tsconfig.json icon="file-json" { @@ -289,7 +289,16 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w } ``` -If you aren't a TypeScript user, you can create a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root to achieve the same behavior. +Bun also supports [Node.js-style subpath imports](https://nodejs.org/api/packages.html#subpath-imports) in `package.json`, where mapped paths must start with `#`. This approach doesn’t work as well with editors, but both options can be used together. + +```json package.json icon="file-json" +{ + "imports": { + "#config": "./config.ts", // map specifier to file + "#components/*": "./components/*" // wildcard matching + } +} +``` From f67bec90c544f13bbdd4338f83d2f864d87bcd08 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 11:02:39 -0800 Subject: [PATCH 06/14] refactor(us_socket_t.zig) safer use of intCast (#24622) ### What does this PR do? make sure to always safe intCast in us_socket_t ### How did you verify your code works? Compiles --- src/deps/uws/us_socket_t.zig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/deps/uws/us_socket_t.zig b/src/deps/uws/us_socket_t.zig index a67efb9286..7261178814 100644 --- a/src/deps/uws/us_socket_t.zig +++ b/src/deps/uws/us_socket_t.zig @@ -18,7 +18,7 @@ pub const us_socket_t = opaque { if (ip_addr) |ip| { bun.assert(ip.len < max_i32); - _ = c.us_socket_open(ssl, this, @intFromBool(is_client), ip.ptr, @intCast(ip.len)); + _ = c.us_socket_open(ssl, this, @intFromBool(is_client), ip.ptr, @intCast(@min(ip.len, std.math.maxInt(i32)))); } else { _ = c.us_socket_open(ssl, this, @intFromBool(is_client), null, 0); } @@ -66,7 +66,7 @@ pub const us_socket_t = opaque { /// Returned slice is a view into `buf`. pub fn localAddress(this: *us_socket_t, ssl: bool, buf: []u8) ![]const u8 { - var length: i32 = @intCast(buf.len); + var length: i32 = @intCast(@min(buf.len, std.math.maxInt(i32))); c.us_socket_local_address(@intFromBool(ssl), this, buf.ptr, &length); if (length < 0) { @@ -81,7 +81,7 @@ pub const us_socket_t = opaque { /// Returned slice is a view into `buf`. On error, `errno` should be set pub fn remoteAddress(this: *us_socket_t, ssl: bool, buf: []u8) ![]const u8 { - var length: i32 = @intCast(buf.len); + var length: i32 = @intCast(@min(buf.len, std.math.maxInt(i32))); c.us_socket_remote_address(@intFromBool(ssl), this, buf.ptr, &length); if (length < 0) { @@ -95,11 +95,11 @@ pub const us_socket_t = opaque { } pub fn setTimeout(this: *us_socket_t, ssl: bool, seconds: u32) void { - c.us_socket_timeout(@intFromBool(ssl), this, @intCast(seconds)); + c.us_socket_timeout(@intFromBool(ssl), this, seconds); } pub fn setLongTimeout(this: *us_socket_t, ssl: bool, minutes: u32) void { - c.us_socket_long_timeout(@intFromBool(ssl), this, @intCast(minutes)); + c.us_socket_long_timeout(@intFromBool(ssl), this, minutes); } pub fn setNodelay(this: *us_socket_t, enabled: bool) void { @@ -109,7 +109,7 @@ pub const us_socket_t = opaque { /// Returns error code. `0` on success. error codes depend on platform an /// configured event loop. pub fn setKeepalive(this: *us_socket_t, enabled: bool, delay: u32) i32 { - return c.us_socket_keepalive(this, @intFromBool(enabled), @intCast(delay)); + return c.us_socket_keepalive(this, @intFromBool(enabled), delay); } pub fn getNativeHandle(this: *us_socket_t, ssl: bool) ?*anyopaque { @@ -127,14 +127,14 @@ pub const us_socket_t = opaque { } pub fn write(this: *us_socket_t, ssl: bool, data: []const u8) i32 { - const rc = c.us_socket_write(@intFromBool(ssl), this, data.ptr, @intCast(data.len)); + const rc = c.us_socket_write(@intFromBool(ssl), this, data.ptr, @intCast(@min(data.len, std.math.maxInt(i32)))); debug("us_socket_write({p}, {d}) = {d}", .{ this, data.len, rc }); return rc; } pub fn writeFd(this: *us_socket_t, data: []const u8, file_descriptor: bun.FD) i32 { if (bun.Environment.isWindows) @compileError("TODO: implement writeFd on Windows"); - const rc = c.us_socket_ipc_write_fd(this, data.ptr, @intCast(data.len), file_descriptor.native()); + const rc = c.us_socket_ipc_write_fd(this, data.ptr, @intCast(@min(data.len, std.math.maxInt(i32))), file_descriptor.native()); debug("us_socket_ipc_write_fd({p}, {d}, {d}) = {d}", .{ this, data.len, file_descriptor.native(), rc }); return rc; } @@ -147,7 +147,7 @@ pub const us_socket_t = opaque { pub fn rawWrite(this: *us_socket_t, ssl: bool, data: []const u8) i32 { debug("us_socket_raw_write({p}, {d})", .{ this, data.len }); - return c.us_socket_raw_write(@intFromBool(ssl), this, data.ptr, @intCast(data.len)); + return c.us_socket_raw_write(@intFromBool(ssl), this, data.ptr, @intCast(@min(data.len, std.math.maxInt(i32)))); } pub fn flush(this: *us_socket_t, ssl: bool) void { From df4e42bf1c61895604c80a4b4841a5ace5300f15 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 12:28:17 -0800 Subject: [PATCH 07/14] fix(DevServer) remove panic in case of source type none (#24634) ### What does this PR do? Remove panic in case of source type none, so we can handle it more gracefully, we can discuss if this is the best solution but looks sensible for me. This is really hard to repro but can happen when deleting files referred by dynamic imports. Fixes https://linear.app/oven/issue/ENG-21513/panic-missing-internal-precomputed-line-count-in-renderjson-on Fixes https://github.com/oven-sh/bun/issues/21714 ### How did you verify your code works? CI --------- Co-authored-by: taylor.fish --- src/bake/DevServer/SourceMapStore.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bake/DevServer/SourceMapStore.zig b/src/bake/DevServer/SourceMapStore.zig index ea65007624..26a41954e1 100644 --- a/src/bake/DevServer/SourceMapStore.zig +++ b/src/bake/DevServer/SourceMapStore.zig @@ -273,7 +273,11 @@ pub const Entry = struct { .none => { // NOTE: It is too late to compute the line count since the bundled text may // have been freed already. For example, a HMR chunk is never persisted. - @panic("Missing internal precomputed line count."); + // We could return an error here but what would be a better behavior for renderJSON and renderMappings? + // This is a dev server, crashing is not a good DX, we could fail the request but that's not a good DX either. + if (bun.Environment.enable_logs) { + mapLog("Skipping source map entry with missing line count at index {d}", .{i}); + } }, }; } From 8912957aa5621534a0d27c13163ba7db1713d082 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 12:28:55 -0800 Subject: [PATCH 08/14] compatibility(node:net) _handle.fd property (#24575) ### What does this PR do? Expose fd property in _handle for node:net/node:tls Fixes https://linear.app/oven/issue/ENG-21507/expose-fd-in-nodenetnodetls ### How did you verify your code works? Test --------- Co-authored-by: Claude Bot Co-authored-by: Claude Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/bun.js/api/bun/socket.zig | 4 + src/bun.js/api/bun/socket/Listener.zig | 13 ++ src/bun.js/api/sockets.classes.ts | 8 +- src/deps/uws/ListenSocket.zig | 3 + src/deps/uws/socket.zig | 31 +++-- src/fd.zig | 21 ++++ test/regression/issue/24575.test.ts | 166 +++++++++++++++++++++++++ 7 files changed, 236 insertions(+), 10 deletions(-) create mode 100644 test/regression/issue/24575.test.ts diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index e5746333bc..b766a6f7a1 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -1357,6 +1357,10 @@ pub fn NewSocket(comptime ssl: bool) type { return .js_undefined; } + pub fn getFD(this: *This, _: *jsc.JSGlobalObject) JSValue { + return this.socket.fd().toJSWithoutMakingLibUVOwned(); + } + pub fn getBytesWritten(this: *This, _: *jsc.JSGlobalObject) JSValue { return jsc.JSValue.jsNumber(this.bytes_written + this.buffered_data_for_node_net.len); } diff --git a/src/bun.js/api/bun/socket/Listener.zig b/src/bun.js/api/bun/socket/Listener.zig index fbb6c69c5e..420347cb38 100644 --- a/src/bun.js/api/bun/socket/Listener.zig +++ b/src/bun.js/api/bun/socket/Listener.zig @@ -523,6 +523,19 @@ pub fn getPort(this: *Listener, _: *jsc.JSGlobalObject) JSValue { return JSValue.jsNumber(this.connection.host.port); } +pub fn getFD(this: *Listener, _: *jsc.JSGlobalObject) JSValue { + switch (this.listener) { + .uws => |uws_listener| { + switch (this.ssl) { + inline else => |ssl| { + return uws_listener.socket(ssl).fd().toJSWithoutMakingLibUVOwned(); + }, + } + }, + else => return JSValue.jsNumber(-1), + } +} + pub fn ref(this: *Listener, globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!JSValue { const this_value = callframe.this(); if (this.listener == .none) return .js_undefined; diff --git a/src/bun.js/api/sockets.classes.ts b/src/bun.js/api/sockets.classes.ts index 13d89453ff..ef001397c7 100644 --- a/src/bun.js/api/sockets.classes.ts +++ b/src/bun.js/api/sockets.classes.ts @@ -21,6 +21,7 @@ function generate(ssl) { fn: "pauseFromJS", length: 0, }, + getTLSFinishedMessage: { fn: "getTLSFinishedMessage", length: 0, @@ -91,6 +92,9 @@ function generate(ssl) { bytesWritten: { getter: "getBytesWritten", }, + fd: { + getter: "getFD", + }, setNoDelay: { fn: "setNoDelay", length: 1, @@ -263,7 +267,9 @@ export default [ fn: "unref", length: 0, }, - + fd: { + getter: "getFD", + }, port: { getter: "getPort", }, diff --git a/src/deps/uws/ListenSocket.zig b/src/deps/uws/ListenSocket.zig index 334bc98e6c..98f93d6977 100644 --- a/src/deps/uws/ListenSocket.zig +++ b/src/deps/uws/ListenSocket.zig @@ -11,6 +11,9 @@ pub const ListenSocket = opaque { pub fn getSocket(this: *ListenSocket) *uws.us_socket_t { return @ptrCast(this); } + pub fn socket(this: *ListenSocket, comptime is_ssl: bool) uws.NewSocketHandler(is_ssl) { + return uws.NewSocketHandler(is_ssl).from(this.getSocket()); + } }; const c = struct { diff --git a/src/deps/uws/socket.zig b/src/deps/uws/socket.zig index 971f08c495..61e378da82 100644 --- a/src/deps/uws/socket.zig +++ b/src/deps/uws/socket.zig @@ -295,16 +295,29 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { } pub inline fn fd(this: ThisSocket) bun.FileDescriptor { - if (comptime is_ssl) { - @compileError("SSL sockets do not have a file descriptor accessible this way"); - } const socket = this.socket.get() orelse return bun.invalid_fd; - - // on windows uSockets exposes SOCKET - return if (comptime Environment.isWindows) - .fromNative(@ptrCast(socket.getNativeHandle(is_ssl).?)) - else - .fromNative(@intCast(@intFromPtr(socket.getNativeHandle(is_ssl)))); + if (comptime is_ssl) { + if (socket.getNativeHandle(is_ssl)) |handle| { + const ssl_ptr: *BoringSSL.SSL = @as(*BoringSSL.SSL, @ptrCast(handle)); + const fd_value = BoringSSL.SSL_get_fd(ssl_ptr); + if (fd_value == -1) { + return bun.invalid_fd; + } + return if (Environment.isWindows) + .fromNative(@ptrFromInt(@as(usize, @intCast(fd_value)))) + else + .fromNative(fd_value); + } + return bun.invalid_fd; + } + if (socket.getNativeHandle(is_ssl)) |handle| { + // on windows uSockets exposes SOCKET + return if (comptime Environment.isWindows) + .fromNative(@ptrCast(handle)) + else + .fromNative(@intCast(@intFromPtr(handle))); + } + return bun.invalid_fd; } pub fn markNeedsMoreForSendfile(this: ThisSocket) void { diff --git a/src/fd.zig b/src/fd.zig index ea11cedbd6..75eab577cf 100644 --- a/src/fd.zig +++ b/src/fd.zig @@ -346,6 +346,9 @@ pub const FD = packed struct(backing_int) { /// After calling, the input file descriptor is no longer valid and must not be used. /// If an error is thrown, the file descriptor is cleaned up for you. pub fn toJS(any_fd: FD, global: *jsc.JSGlobalObject) JSValue { + if (!any_fd.isValid()) { + return JSValue.jsNumberFromInt32(-1); + } const uv_owned_fd = any_fd.makeLibUVOwned() catch { any_fd.close(); return global.throwValue((jsc.SystemError{ @@ -356,6 +359,24 @@ pub const FD = packed struct(backing_int) { return JSValue.jsNumberFromInt32(uv_owned_fd.uv()); } + /// Convert an FD to a JavaScript number without transferring ownership to libuv. + /// Unlike toJS(), this does not call makeLibUVOwned() on Windows, so the caller + /// retains ownership and must close the FD themselves. + /// Returns -1 for invalid file descriptors. + /// On Windows: returns Uint64 for system handles, Int32 for uv file descriptors. + pub fn toJSWithoutMakingLibUVOwned(any_fd: FD) JSValue { + if (!any_fd.isValid()) { + return JSValue.jsNumberFromInt32(-1); + } + if (Environment.isWindows) { + return switch (any_fd.kind) { + .system => JSValue.jsNumberFromUint64(@intCast(any_fd.value.as_system)), + .uv => JSValue.jsNumberFromInt32(any_fd.value.as_uv), + }; + } + return JSValue.jsNumberFromInt32(any_fd.value.as_system); + } + pub const Stdio = enum(u8) { std_in = 0, std_out = 1, diff --git a/test/regression/issue/24575.test.ts b/test/regression/issue/24575.test.ts new file mode 100644 index 0000000000..005de73ed0 --- /dev/null +++ b/test/regression/issue/24575.test.ts @@ -0,0 +1,166 @@ +// https://github.com/oven-sh/bun/pull/24575 +// Tests that socket._handle.fd property is available +import { expect, test } from "bun:test"; +import net from "node:net"; +import tls from "node:tls"; + +test("socket._handle.fd should be accessible on TCP sockets", async () => { + const { promise, resolve, reject } = Promise.withResolvers(); + + let serverFd: number | undefined; + let clientFd: number | undefined; + + const server = net.createServer(socket => { + // Server-side socket should have _handle.fd + expect(socket._handle).toBeDefined(); + expect(socket._handle.fd).toBeTypeOf("number"); + expect(socket._handle.fd).toBeGreaterThan(0); + serverFd = socket._handle.fd; + + socket.end(`server fd: ${socket._handle.fd}`); + }); + + server.listen(0, "127.0.0.1", () => { + const client = net.connect({ + host: "127.0.0.1", + port: (server.address() as any).port, + }); + + client.on("connect", () => { + // Client-side socket should have _handle.fd + expect(client._handle).toBeDefined(); + expect(client._handle.fd).toBeTypeOf("number"); + expect(client._handle.fd).toBeGreaterThan(0); + clientFd = client._handle.fd; + }); + + client.on("data", data => { + const response = data.toString(); + expect(response).toStartWith("server fd: "); + + // Verify we got valid fds + expect(serverFd).toBeTypeOf("number"); + expect(clientFd).toBeTypeOf("number"); + expect(serverFd).toBeGreaterThan(0); + expect(clientFd).toBeGreaterThan(0); + + // Server and client should have different fds + expect(serverFd).not.toBe(clientFd); + + server.close(); + resolve(); + }); + + client.on("error", reject); + }); + + server.on("error", reject); + + await promise; +}); + +test("socket._handle.fd should remain consistent during connection lifetime", async () => { + const { promise, resolve, reject } = Promise.withResolvers(); + + const server = net.createServer(socket => { + const initialFd = socket._handle.fd; + + // Send multiple messages to ensure fd doesn't change + socket.write("message1\n"); + expect(socket._handle.fd).toBe(initialFd); + + socket.write("message2\n"); + expect(socket._handle.fd).toBe(initialFd); + + socket.end("message3\n"); + expect(socket._handle.fd).toBe(initialFd); + }); + + server.listen(0, "127.0.0.1", () => { + const client = net.connect({ + host: "127.0.0.1", + port: (server.address() as any).port, + }); + + let initialClientFd: number; + let buffer = ""; + + client.on("connect", () => { + initialClientFd = client._handle.fd; + expect(initialClientFd).toBeGreaterThan(0); + }); + + client.on("data", data => { + buffer += data.toString(); + // Fd should remain consistent across multiple data events + expect(client._handle.fd).toBe(initialClientFd); + }); + + client.on("end", () => { + // Verify we received all messages + expect(buffer).toBe("message1\nmessage2\nmessage3\n"); + server.close(); + resolve(); + }); + + client.on("error", reject); + }); + + server.on("error", reject); + + await promise; +}); + +test("socket._handle.fd should be accessible on TLS sockets", async () => { + const { tls: tlsCert } = await import("harness"); + const { promise, resolve, reject } = Promise.withResolvers(); + + let serverFd: number | undefined; + let clientFd: number | undefined; + + const server = tls.createServer(tlsCert, socket => { + // Server-side TLS socket should have _handle.fd + expect(socket._handle).toBeDefined(); + expect(socket._handle.fd).toBeTypeOf("number"); + // TLS sockets should have a valid fd (may be -1 on some platforms/states) + expect(typeof socket._handle.fd).toBe("number"); + serverFd = socket._handle.fd; + + socket.end(`server fd: ${socket._handle.fd}`); + }); + + server.listen(0, "127.0.0.1", () => { + const client = tls.connect({ + host: "127.0.0.1", + port: (server.address() as any).port, + rejectUnauthorized: false, + }); + + client.on("secureConnect", () => { + // Client-side TLS socket should have _handle.fd + expect(client._handle).toBeDefined(); + expect(client._handle.fd).toBeTypeOf("number"); + // TLS sockets should have a valid fd (may be -1 on some platforms/states) + expect(typeof client._handle.fd).toBe("number"); + clientFd = client._handle.fd; + }); + + client.on("data", data => { + const response = data.toString(); + expect(response).toMatch(/server fd: -?\d+/); + + // Verify we got valid fds (number type, even if -1) + expect(serverFd).toBeTypeOf("number"); + expect(clientFd).toBeTypeOf("number"); + + server.close(); + resolve(); + }); + + client.on("error", reject); + }); + + server.on("error", reject); + + await promise; +}); From ab32a2fc4ae03b38dec445850c8628fc96bac168 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 12:41:47 -0800 Subject: [PATCH 09/14] fix(bun getcompletes) add windows support and remove TODO panic (#24620) ### What does this PR do? Fixes https://linear.app/oven/issue/ENG-21509/panic-todo-in-completions ### How did you verify your code works? Test --- src/cli/run_command.zig | 3 --- src/sys.zig | 38 ++++++++++++++++---------------------- src/windows.zig | 2 +- test/cli/bun.test.ts | 11 ++++++++++- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index 2d099b25dd..956dd9f851 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -1053,9 +1053,6 @@ pub const RunCommand = struct { bun.copy(u8, path_buf[dir_slice.len..], base); path_buf[dir_slice.len + base.len] = 0; const slice = path_buf[0 .. dir_slice.len + base.len :0]; - if (Environment.isWindows) { - @panic("TODO"); - } if (!(bun.sys.isExecutableFilePath(slice))) continue; // we need to dupe because the string pay point to a pointer that only exists in the current scope _ = try results.getOrPut(this_transpiler.fs.filename_store.append(@TypeOf(base), base) catch continue); diff --git a/src/sys.zig b/src/sys.zig index c9aff7d40d..a2b860fed3 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -3430,29 +3430,23 @@ pub fn isExecutableFileOSPath(path: bun.OSPathSliceZ) bool { if (comptime Environment.isWindows) { // Rationale: `GetBinaryTypeW` does not work on .cmd files. - // Windows does not have executable permission like posix does, instead we - // can just look at the file extension to determine executable status. - @compileError("Do not use isExecutableFilePath on Windows"); + // SaferiIsExecutableFileType works on .cmd files. + // The following file name extensions are examples of executable file types. This is not a complete list. + // .bat + // .cmd + // .com + // .exe + // .js + // .lnk + // .pif + // .pl + // .shs + // .url + // .vbs + // The security policy Microsoft Management Console (MMC) snap-in (Secpol.msc) controls which extensions are considered executable file types. - // var out: windows.DWORD = 0; - // const rc = kernel32.GetBinaryTypeW(path, &out); - - // const result = if (rc == windows.FALSE) - // false - // else switch (out) { - // kernel32.SCS_32BIT_BINARY, - // kernel32.SCS_64BIT_BINARY, - // kernel32.SCS_DOS_BINARY, - // kernel32.SCS_OS216_BINARY, - // kernel32.SCS_PIF_BINARY, - // kernel32.SCS_POSIX_BINARY, - // => true, - // else => false, - // }; - - // log("GetBinaryTypeW({f}) = {d}. isExecutable={}", .{ bun.fmt.utf16(path), out, result }); - - // return result; + // we pass false to include .exe files (see https://learn.microsoft.com/en-us/windows/win32/api/winsafer/nf-winsafer-saferiisexecutablefiletype) + return bun.windows.SaferiIsExecutableFileType(path, w.FALSE) != w.FALSE; } @compileError("TODO: isExecutablePath"); diff --git a/src/windows.zig b/src/windows.zig index d358b7a5ad..a909b11858 100644 --- a/src/windows.zig +++ b/src/windows.zig @@ -150,7 +150,7 @@ pub extern "kernel32" fn SetCurrentDirectoryW( ) callconv(.winapi) win32.BOOL; pub const SetCurrentDirectory = SetCurrentDirectoryW; pub extern "ntdll" fn RtlNtStatusToDosError(win32.NTSTATUS) callconv(.winapi) Win32Error; - +pub extern "advapi32" fn SaferiIsExecutableFileType(szFullPathname: win32.LPCWSTR, bFromShellExecute: win32.BOOLEAN) callconv(.winapi) win32.BOOL; // This was originally copied from Zig's standard library /// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d pub const Win32Error = enum(u16) { diff --git a/test/cli/bun.test.ts b/test/cli/bun.test.ts index c6dd62858f..cf2b66794c 100644 --- a/test/cli/bun.test.ts +++ b/test/cli/bun.test.ts @@ -59,7 +59,16 @@ describe("bun", () => { ); }); }); - + describe("getcompletes", () => { + test("getcompletes should not panic and should not be empty", () => { + const { stdout, exitCode } = spawnSync({ + cmd: [bunExe(), "getcompletes"], + env: bunEnv, + }); + expect(exitCode).toBe(0); + expect(stdout.toString()).not.toBeEmpty(); + }); + }); describe("test command line arguments", () => { test("test --config, issue #4128", () => { const path = `${tmpdir()}/bunfig-${Date.now()}.toml`; From 1f0c885e91f20d748086accc4dae9ea5b56d0748 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 12:42:06 -0800 Subject: [PATCH 10/14] proper handle on_data if we receive null (#24624) ### What does this PR do? If for some reason data is null we should handle as empty Fixes https://linear.app/oven/issue/ENG-21511/panic-attempt-to-use-null-value-in-socket-on-data ### How did you verify your code works? Ci --- packages/bun-usockets/src/crypto/openssl.c | 2 +- src/deps/uws/socket.zig | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/bun-usockets/src/crypto/openssl.c b/packages/bun-usockets/src/crypto/openssl.c index 60e1900da5..348819d0e8 100644 --- a/packages/bun-usockets/src/crypto/openssl.c +++ b/packages/bun-usockets/src/crypto/openssl.c @@ -635,7 +635,7 @@ ssl_on_writable(struct us_internal_ssl_socket_t *s) { (struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s); // if this one fails to write data, it sets ssl_read_wants_write again - s = (struct us_internal_ssl_socket_t *)context->sc.on_data(&s->s, 0, + s = (struct us_internal_ssl_socket_t *)context->sc.on_data(&s->s, "", 0); // cast here! } // Do not call on_writable if the socket is closed. diff --git a/src/deps/uws/socket.zig b/src/deps/uws/socket.zig index 61e378da82..bab59f189c 100644 --- a/src/deps/uws/socket.zig +++ b/src/deps/uws/socket.zig @@ -183,7 +183,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { const res = Fields.onData( getValue(socket), TLSSocket.from(socket), - buf.?[0..@as(usize, @intCast(len))], + if (buf) |data_ptr| data_ptr[0..@as(usize, @intCast(len))] else "", ); if (@TypeOf(res) != void) res catch |err| switch (err) { error.JSTerminated => return null, // TODO: declare throw scope @@ -744,7 +744,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { const res = Fields.onData( getValue(socket), SocketHandlerType.from(socket), - buf.?[0..@as(usize, @intCast(len))], + if (buf) |data_ptr| data_ptr[0..@as(usize, @intCast(len))] else "", ); if (@TypeOf(res) != void) res catch |err| switch (err) { error.JSTerminated => return null, // TODO: declare throw scope @@ -910,7 +910,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { const res = Fields.onData( getValue(socket), ThisSocket.from(socket), - buf.?[0..@as(usize, @intCast(len))], + if (buf) |data_ptr| data_ptr[0..@as(usize, @intCast(len))] else "", ); if (@TypeOf(res) != void) res catch |err| switch (err) { error.JSTerminated => return null, // TODO: declare throw scope From 4e1d9a2cbcd14e67f4f9f5bbc65aacd99c008e69 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 12 Nov 2025 13:39:36 -0800 Subject: [PATCH 11/14] remove dead code in src/bake/DevServer/SerializedFailure.zig (#24635) ### What does this PR do? remove dead code in src/bake/DevServer/SerializedFailure.zig ### How did you verify your code works? It builds --- src/bake/DevServer/SerializedFailure.zig | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/bake/DevServer/SerializedFailure.zig b/src/bake/DevServer/SerializedFailure.zig index d14af1c133..9ee733aa89 100644 --- a/src/bake/DevServer/SerializedFailure.zig +++ b/src/bake/DevServer/SerializedFailure.zig @@ -104,29 +104,6 @@ pub const ErrorKind = enum(u8) { js_aggregate, }; -pub fn initFromJs(dev: *DevServer, owner: Owner, value: JSValue) !SerializedFailure { - { - _ = value; - @panic("TODO"); - } - // Avoid small re-allocations without requesting so much from the heap - var sfb = std.heap.stackFallback(65536, dev.allocator()); - var payload = std.array_list.Managed(u8).initCapacity(sfb.get(), 65536) catch - unreachable; // enough space - const w = payload.writer(); - - try w.writeInt(u32, @bitCast(owner.encode()), .little); - // try writeJsValue(value); - - // Avoid-recloning if it is was moved to the hap - const data = if (payload.items.ptr == &sfb.buffer) - try dev.allocator().dupe(u8, payload.items) - else - payload.items; - - return .{ .data = data }; -} - pub fn initFromLog( dev: *DevServer, owner: Owner, From fff47f026749b97f66081023dc8321a5dab1592f Mon Sep 17 00:00:00 2001 From: Caio Borghi Date: Wed, 12 Nov 2025 19:18:59 -0300 Subject: [PATCH 12/14] docs: update EdgeDB references to Gel rebrand (#24487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary EdgeDB has rebranded to Gel. This PR comprehensively updates all documentation to reflect the rebrand. ## Changes Made ### Documentation & Branding - **Guide title**: "Use EdgeDB with Bun" β†’ "Use Gel with Bun" - **File renamed**: `docs/guides/ecosystem/edgedb.mdx` β†’ `gel.mdx` - **Description**: Added "(formerly EdgeDB)" note - **All path references**: Updated from `/guides/ecosystem/edgedb` to `/guides/ecosystem/gel` ### CLI Commands - `edgedb project init` β†’ `gel project init` - `edgedb` β†’ `gel` (REPL) - `edgedb migration create` β†’ `gel migration create` - `edgedb migrate` β†’ `gel migrate` ### npm Packages - `edgedb` β†’ `gel` - `@edgedb/generate` β†’ `@gel/generate` ### Installation & Documentation URLs - Installation link: `docs.geldata.com/learn/installation` (functional) - Documentation reference: `docs.geldata.com/` (operational) - Installation scripts: Verified working (`https://www.geldata.com/sh` and `ps1`) - Added Homebrew option: `brew install geldata/tap/gel-cli` ### Code Examples - Updated all imports: `import { createClient } from "gel"` - Updated codegen commands: `bunx @gel/generate` ## Verified All commands verified against official Gel documentation at https://docs.geldata.com/ Fixes #17721 --------- Co-authored-by: Lydia Hallie --- README.md | 2 +- docs/docs.json | 2 +- docs/guides/ecosystem/{edgedb.mdx => gel.mdx} | 80 ++++++++++--------- docs/snippets/guides.jsx | 2 +- 4 files changed, 45 insertions(+), 41 deletions(-) rename docs/guides/ecosystem/{edgedb.mdx => gel.mdx} (63%) diff --git a/README.md b/README.md index 61733ac8e8..3c845722d1 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ bun upgrade --canary - Ecosystem - [Use React and JSX](https://bun.com/guides/ecosystem/react) - - [Use EdgeDB with Bun](https://bun.com/guides/ecosystem/edgedb) + - [Use Gel with Bun](https://bun.com/guides/ecosystem/gel) - [Use Prisma with Bun](https://bun.com/guides/ecosystem/prisma) - [Add Sentry to a Bun app](https://bun.com/guides/ecosystem/sentry) - [Create a Discord bot](https://bun.com/guides/ecosystem/discordjs) diff --git a/docs/docs.json b/docs/docs.json index 38fd681f92..cfb3924cc3 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -354,7 +354,7 @@ "/guides/ecosystem/discordjs", "/guides/ecosystem/docker", "/guides/ecosystem/drizzle", - "/guides/ecosystem/edgedb", + "/guides/ecosystem/gel", "/guides/ecosystem/elysia", "/guides/ecosystem/express", "/guides/ecosystem/hono", diff --git a/docs/guides/ecosystem/edgedb.mdx b/docs/guides/ecosystem/gel.mdx similarity index 63% rename from docs/guides/ecosystem/edgedb.mdx rename to docs/guides/ecosystem/gel.mdx index 6b621f9139..c26a6bfa64 100644 --- a/docs/guides/ecosystem/edgedb.mdx +++ b/docs/guides/ecosystem/gel.mdx @@ -1,23 +1,27 @@ --- -title: Use EdgeDB with Bun -sidebarTitle: EdgeDB with Bun +title: Use Gel with Bun +sidebarTitle: Gel with Bun mode: center --- -EdgeDB is a graph-relational database powered by Postgres under the hood. It provides a declarative schema language, migrations system, and object-oriented query language, in addition to supporting raw SQL queries. It solves the object-relational mapping problem at the database layer, eliminating the need for an ORM library in your application code. +Gel (formerly EdgeDB) is a graph-relational database powered by Postgres under the hood. It provides a declarative schema language, migrations system, and object-oriented query language, in addition to supporting raw SQL queries. It solves the object-relational mapping problem at the database layer, eliminating the need for an ORM library in your application code. --- -First, [install EdgeDB](https://www.edgedb.com/install) if you haven't already. +First, [install Gel](https://docs.geldata.com/learn/installation) if you haven't already. ```sh Linux/macOS terminal icon="terminal" -curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh +curl https://www.geldata.com/sh --proto "=https" -sSf1 | sh ``` ```sh Windows terminal icon="windows" -iwr https://ps1.edgedb.com -useb | iex +irm https://www.geldata.com/ps1 | iex +``` + +```sh Homebrew terminal icon="terminal" +brew install geldata/tap/gel-cli ``` @@ -34,35 +38,35 @@ bun init -y --- -We'll use the EdgeDB CLI to initialize an EdgeDB instance for our project. This creates an `edgedb.toml` file in our project root. +We'll use the Gel CLI to initialize a Gel instance for our project. This creates a `gel.toml` file in our project root. ```sh terminal icon="terminal" -edgedb project init +gel project init ``` ```txt -No `edgedb.toml` found in `/Users/colinmcd94/Documents/bun/fun/examples/my-edgedb-app` or above +No `gel.toml` found in `/Users/colinmcd94/Documents/bun/fun/examples/my-gel-app` or above Do you want to initialize a new project? [Y/n] > Y -Specify the name of EdgeDB instance to use with this project [default: my_edgedb_app]: -> my_edgedb_app -Checking EdgeDB versions... -Specify the version of EdgeDB to use with this project [default: x.y]: +Specify the name of Gel instance to use with this project [default: my_gel_app]: +> my_gel_app +Checking Gel versions... +Specify the version of Gel to use with this project [default: x.y]: > x.y -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Project directory β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-edgedb-app β”‚ -β”‚ Project config β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-edgedb-app/edgedb.toml β”‚ -β”‚ Schema dir (empty) β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-edgedb-app/dbschema β”‚ -β”‚ Installation method β”‚ portable package β”‚ -β”‚ Version β”‚ x.y+6d5921b β”‚ -β”‚ Instance name β”‚ my_edgedb_app β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Project directory β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app β”‚ +β”‚ Project config β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/gel.tomlβ”‚ +β”‚ Schema dir (empty) β”‚ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/dbschemaβ”‚ +β”‚ Installation method β”‚ portable package β”‚ +β”‚ Version β”‚ x.y+6d5921b β”‚ +β”‚ Instance name β”‚ my_gel_app β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Version x.y+6d5921b is already downloaded -Initializing EdgeDB instance... +Initializing Gel instance... Applying migrations... Everything is up to date. Revision initial Project initialized. -To connect to my_edgedb_app, run `edgedb` +To connect to my_gel_app, run `gel` ``` --- @@ -70,8 +74,8 @@ To connect to my_edgedb_app, run `edgedb` To see if the database is running, let's open a REPL and run a simple query. ```sh terminal icon="terminal" -edgedb -edgedb> select 1 + 1; +gel +gel> select 1 + 1; ``` ```txt @@ -81,12 +85,12 @@ edgedb> select 1 + 1; Then run `\quit` to exit the REPL. ```sh terminal icon="terminal" -edgedb> \quit +gel> \quit ``` --- -With the project initialized, we can define a schema. The `edgedb project init` command already created a `dbschema/default.esdl` file to contain our schema. +With the project initialized, we can define a schema. The `gel project init` command already created a `dbschema/default.esdl` file to contain our schema. ```txt File Tree icon="folder-tree" dbschema @@ -112,15 +116,15 @@ module default { Then generate and apply an initial migration. ```sh terminal icon="terminal" -edgedb migration create +gel migration create ``` ```txt -Created /Users/colinmcd94/Documents/bun/fun/examples/my-edgedb-app/dbschema/migrations/00001.edgeql, id: m1uwekrn4ni4qs7ul7hfar4xemm5kkxlpswolcoyqj3xdhweomwjrq +Created /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/dbschema/migrations/00001.edgeql, id: m1uwekrn4ni4qs7ul7hfar4xemm5kkxlpswolcoyqj3xdhweomwjrq ``` ```sh terminal icon="terminal" -edgedb migrate +gel migrate ``` ```txt @@ -129,11 +133,11 @@ Applied m1uwekrn4ni4qs7ul7hfar4xemm5kkxlpswolcoyqj3xdhweomwjrq (00001.edgeql) --- -With our schema applied, let's execute some queries using EdgeDB's JavaScript client library. We'll install the client library and EdgeDB's codegen CLI, and create a `seed.ts`.file. +With our schema applied, let's execute some queries using Gel's JavaScript client library. We'll install the client library and Gel's codegen CLI, and create a `seed.ts`.file. ```sh terminal icon="terminal" -bun add edgedb -bun add -D @edgedb/generate +bun add gel +bun add -D @gel/generate touch seed.ts ``` @@ -144,7 +148,7 @@ Paste the following code into `seed.ts`. The client auto-connects to the database. We insert a couple movies using the `.execute()` method. We will use EdgeQL's `for` expression to turn this bulk insert into a single optimized query. ```ts seed.ts icon="/icons/typescript.svg" -import { createClient } from "edgedb"; +import { createClient } from "gel"; const client = createClient(); @@ -184,10 +188,10 @@ Seeding complete. --- -EdgeDB implements a number of code generation tools for TypeScript. To query our newly seeded database in a typesafe way, we'll use `@edgedb/generate` to code-generate the EdgeQL query builder. +Gel implements a number of code generation tools for TypeScript. To query our newly seeded database in a typesafe way, we'll use `@gel/generate` to code-generate the EdgeQL query builder. ```sh terminal icon="terminal" -bunx @edgedb/generate edgeql-js +bunx @gel/generate edgeql-js ``` ```txt @@ -213,7 +217,7 @@ the query builder directory? The following line will be added: In `index.ts`, we can import the generated query builder from `./dbschema/edgeql-js` and write a simple select query. ```ts index.ts icon="/icons/typescript.svg" -import { createClient } from "edgedb"; +import { createClient } from "gel"; import e from "./dbschema/edgeql-js"; const client = createClient(); @@ -254,4 +258,4 @@ bun run index.ts --- -For complete documentation, refer to the [EdgeDB docs](https://www.edgedb.com/docs). +For complete documentation, refer to the [Gel docs](https://docs.geldata.com/). diff --git a/docs/snippets/guides.jsx b/docs/snippets/guides.jsx index ce3c7a7f8a..248814ef79 100644 --- a/docs/snippets/guides.jsx +++ b/docs/snippets/guides.jsx @@ -123,7 +123,7 @@ export const GuidesList = () => { title: "Ecosystem", icon: "puzzle", items: [ - { title: "Use EdgeDB with Bun", href: "/guides/ecosystem/edgedb" }, + { title: "Use Gel with Bun", href: "/guides/ecosystem/gel" }, { title: "Use Prisma ORM with Bun", href: "/guides/ecosystem/prisma" }, { title: "Use Prisma Postgres with Bun", href: "/guides/ecosystem/prisma-postgres" }, { title: "Create a Discord bot", href: "/guides/ecosystem/discordjs" }, From e03d3bee100bab4ac4cf6e093b507211987245eb Mon Sep 17 00:00:00 2001 From: Marko Vejnovic Date: Wed, 12 Nov 2025 14:40:12 -0800 Subject: [PATCH 13/14] ci(ENG-21502): Fix sccache not working inside Docker (#24597) --- .buildkite/Dockerfile | 14 ++++++++++++++ scripts/bootstrap.sh | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/.buildkite/Dockerfile b/.buildkite/Dockerfile index 55e45ccdff..033aec633d 100644 --- a/.buildkite/Dockerfile +++ b/.buildkite/Dockerfile @@ -133,6 +133,20 @@ RUN ARCH=$(if [ "$TARGETARCH" = "arm64" ]; then echo "arm64"; else echo "amd64"; RUN mkdir -p /var/cache/buildkite-agent /var/log/buildkite-agent /var/run/buildkite-agent /etc/buildkite-agent /var/lib/buildkite-agent/cache/bun +# The following is necessary to configure buildkite to use a stable +# checkout directory. sccache hashes absolute paths into its cache keys, +# so if buildkite uses a different checkout path each time (which it does +# by default), sccache will be useless. +RUN mkdir -p -m 755 /var/lib/buildkite-agent/hooks && \ + cat <<'EOF' > /var/lib/buildkite-agent/hooks/environment +#!/bin/sh +set -efu + +export BUILDKITE_BUILD_CHECKOUT_PATH=/var/lib/buildkite-agent/build +EOF + +RUN chmod 744 /var/lib/buildkite-agent/hooks/environment + COPY ../*/agent.mjs /var/bun/scripts/ ENV BUN_INSTALL_CACHE=/var/lib/buildkite-agent/cache/bun diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index ead3de99c8..7bc2a53ad6 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -1392,6 +1392,10 @@ create_buildkite_user() { create_file "$file" done + # The following is necessary to configure buildkite to use a stable + # checkout directory. sccache hashes absolute paths into its cache keys, + # so if buildkite uses a different checkout path each time (which it does + # by default), sccache will be useless. local opts=$- set -ef From 6d2ce3892bf738338086224b6672352b8e95c59a Mon Sep 17 00:00:00 2001 From: Marko Vejnovic Date: Wed, 12 Nov 2025 14:51:08 -0800 Subject: [PATCH 14/14] build(ENG-21514): Fix sccache invocation (#24651) ### What does this PR do? Fixes some miswritten `cmake` steps so that `sccache` actually works ### How did you verify your code works? --- cmake/tools/SetupSccache.cmake | 44 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/cmake/tools/SetupSccache.cmake b/cmake/tools/SetupSccache.cmake index 6736f0706e..cb4b5aa750 100644 --- a/cmake/tools/SetupSccache.cmake +++ b/cmake/tools/SetupSccache.cmake @@ -10,12 +10,8 @@ set(SCCACHE_SHARED_CACHE_BUCKET "bun-build-sccache-store") function(check_aws_credentials OUT_VAR) # Install dependencies first execute_process( - COMMAND - ${BUN_EXECUTABLE} - install - --frozen-lockfile - WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/scripts/build-cache + COMMAND ${BUN_EXECUTABLE} install --frozen-lockfile + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/scripts/build-cache RESULT_VARIABLE INSTALL_EXIT_CODE OUTPUT_VARIABLE INSTALL_OUTPUT ERROR_VARIABLE INSTALL_ERROR @@ -106,26 +102,22 @@ function(sccache_configure_environment_developer) endif() endfunction() -function(sccache_configure) - find_command(VARIABLE SCCACHE_PROGRAM COMMAND sccache REQUIRED ${CI}) - if(NOT SCCACHE_PROGRAM) - message(WARNING "sccache not found. Your builds will be slower.") - return() - endif() +find_command(VARIABLE SCCACHE_PROGRAM COMMAND sccache REQUIRED ${CI}) +if(NOT SCCACHE_PROGRAM) + message(WARNING "sccache not found. Your builds will be slower.") + return() +endif() - set(SCCACHE_ARGS CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER) - foreach(arg ${SCCACHE_ARGS}) - setx(${arg} ${SCCACHE_PROGRAM}) - list(APPEND CMAKE_ARGS -D${arg}=${${arg}}) - endforeach() +set(SCCACHE_ARGS CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER) +foreach(arg ${SCCACHE_ARGS}) + setx(${arg} ${SCCACHE_PROGRAM}) + list(APPEND CMAKE_ARGS -D${arg}=${${arg}}) +endforeach() - setenv(SCCACHE_LOG "info") +setenv(SCCACHE_LOG "info") - if (CI) - sccache_configure_environment_ci() - else() - sccache_configure_environment_developer() - endif() -endfunction() - -sccache_configure() +if (CI) + sccache_configure_environment_ci() +else() + sccache_configure_environment_developer() +endif()