Skip to content

feat: add Bun deployment adapter#196

Open
rturnq wants to merge 5 commits into
mainfrom
claude/bun-adapter
Open

feat: add Bun deployment adapter#196
rturnq wants to merge 5 commits into
mainfrom
claude/bun-adapter

Conversation

@rturnq

@rturnq rturnq commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a new adapter package, @marko/run-adapter-bun, for running and deploying Marko Run apps on Bun.

  • Bundles a self-contained server entry (dist/index.mjs) that uses Bun.serve. It targets Node (Bun is Node-compatible) with the bun export condition and noExternal: true.
  • Serves the app's routes and, when no route matches, falls back to serving static files from dist/public via Bun.file — content-type is inferred by Bun, /assets/* gets immutable caching, and a path-traversal guard is applied. Listens on the PORT environment variable (default 3000).
  • Runs with bun run dist/index.mjs.
  • Route handlers receive the Bun.serve server instance (exposing requestIP, etc.) via the exported BunPlatformInfo type.

Also adds a test fixture to the @marko/run package (bun-adapter) mirroring the existing adapter fixtures, and a changeset for the new package.

Motivation and Context

Bun is a popular, fast JavaScript runtime with a web-standard server API (Bun.serve), making it a natural target for Marko Run. This provides a zero-config, self-contained build that runs on Bun, alongside the existing Node, static, and Netlify adapters.

Screenshots (if appropriate):

Checklist:

  • I have updated/added documentation affected by my changes.
  • I have added tests to cover my changes.

Generated by Claude Code

Add @marko/run-adapter-bun for deploying Marko Run apps on Bun.

- Bundles a self-contained server entry (dist/index.mjs) that uses
  Bun.serve, targeting Node with the bun export condition
- Serves the app and falls back to serving static assets from dist/public
  via Bun.file (immutable caching for /assets, path traversal guard),
  listening on the PORT env var
- Exposes the Bun.serve server (requestIP, etc.) to handlers via
  BunPlatformInfo
- Adds a run-package test fixture (preview skipped; it needs the Bun CLI)
@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b75990a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@marko/run-adapter-bun Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e72d419-1022-49e2-aa01-e86528973a37

📥 Commits

Reviewing files that changed from the base of the PR and between c1d0491 and b75990a.

📒 Files selected for processing (1)
  • packages/adapters/bun/README.md
✅ Files skipped from review due to trivial changes (1)
  • packages/adapters/bun/README.md

Walkthrough

This PR adds a new @marko/run-adapter-bun package for running @marko/run apps on Bun. It includes Bun-specific platform types, adapter startup and preview logic, a Bun.serve entry that serves routes and static files, package/build configuration, documentation, a changeset, and a Bun adapter fixture used in tests.

Related Issues: None found
Related PRs: None found
Suggested labels: enhancement, adapter, bun
Suggested reviewers: DylanPiercey

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a Bun deployment adapter.
Description check ✅ Passed The description clearly matches the changeset and explains the Bun adapter, fixture, and documentation updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/bun-adapter

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/adapters/bun/src/index.ts (1)

46-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Non-null assertion on startDev.

startDev! assumes the base adapter always returns startDev, which holds per the base-adapter snippet, but the assertion silently masks a contract change if the base adapter ever makes it optional/undefined.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/adapters/bun/src/index.ts` around lines 46 - 51, The `startDev`
wrapper in `index.ts` uses a non-null assertion on `startDev`, which hides a
potential contract change from the base adapter. Update the `startDev(event)`
implementation to avoid `startDev!` by either validating the function exists
before calling it or by structuring the adapter types so the contract is
enforced without assertion, keeping the existing `event.entry` normalization
intact.
packages/adapters/bun/package.json (1)

1-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No devDependencies declared despite build script needing tsx, esbuild, and typescript.

The build script (tsc -b && tsx scripts/build.ts) relies on typescript, tsx, and esbuild, none of which are declared as dependencies of this package. In a strict workspace (e.g. pnpm with hoisting disabled), this could cause pnpm --filter @marko/run-adapter-bun build to fail due to phantom dependency resolution.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/adapters/bun/package.json` around lines 1 - 33, The package manifest
for `@marko/run-adapter-bun` is missing the build-time tooling it uses. Update the
package.json for this adapter to declare the required devDependencies for the
build script in the same place as the existing scripts and metadata, so `build`
can resolve `tsc`, `tsx`, and `esbuild` without relying on workspace hoisting.
Keep the change scoped to the Bun adapter package manifest and ensure the
dependency declarations match the tools referenced by the `build` script.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/adapters/bun/src/index.ts`:
- Around line 59-77: The spawned child process in the Bun adapter lacks an error
listener, so a failed launch can surface as an unhandled event and crash the
parent. Update the `spawn("bun", ...)` flow in the `create...` helper to attach
an `on("error", ...)` handler on `proc` and handle launch failures gracefully.
Make sure the fix is localized around the `proc` returned from `spawn` and
preserves the existing stdout/stderr piping and `close()` behavior.
- Around line 59-63: The Bun launcher in spawnBun currently invokes spawn("bun",
["run", entryFile], { shell: true }), which lets the shell reinterpret the
computed entryFile and cwd values. Update this path to avoid shell parsing
entirely by removing shell: true and using a direct spawn/execFile-style
invocation in spawnBun, while keeping the same bun run behavior and validating
the computed entryFile before execution if needed.

---

Nitpick comments:
In `@packages/adapters/bun/package.json`:
- Around line 1-33: The package manifest for `@marko/run-adapter-bun` is missing
the build-time tooling it uses. Update the package.json for this adapter to
declare the required devDependencies for the build script in the same place as
the existing scripts and metadata, so `build` can resolve `tsc`, `tsx`, and
`esbuild` without relying on workspace hoisting. Keep the change scoped to the
Bun adapter package manifest and ensure the dependency declarations match the
tools referenced by the `build` script.

In `@packages/adapters/bun/src/index.ts`:
- Around line 46-51: The `startDev` wrapper in `index.ts` uses a non-null
assertion on `startDev`, which hides a potential contract change from the base
adapter. Update the `startDev(event)` implementation to avoid `startDev!` by
either validating the function exists before calling it or by structuring the
adapter types so the contract is enforced without assertion, keeping the
existing `event.entry` normalization intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b4e7d72a-2de0-49d4-8aa4-2fa113853abb

📥 Commits

Reviewing files that changed from the base of the PR and between 779776f and dcd9078.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json and included by **
  • packages/run/src/__tests__/fixtures/bun-adapter/__snapshots__/dev.expected.md is excluded by !**/__snapshots__/** and included by **
📒 Files selected for processing (17)
  • .changeset/bun-adapter.md
  • packages/adapters/bun/README.md
  • packages/adapters/bun/package.json
  • packages/adapters/bun/scripts/build.ts
  • packages/adapters/bun/scripts/importMetaURL.js
  • packages/adapters/bun/src/default-entry.ts
  • packages/adapters/bun/src/index.ts
  • packages/adapters/bun/src/types.ts
  • packages/adapters/bun/tsconfig.json
  • packages/run/src/__tests__/fixtures/bun-adapter/.gitignore
  • packages/run/src/__tests__/fixtures/bun-adapter/.marko-run/routes.d.ts
  • packages/run/src/__tests__/fixtures/bun-adapter/package.json
  • packages/run/src/__tests__/fixtures/bun-adapter/src/components/counter.marko
  • packages/run/src/__tests__/fixtures/bun-adapter/src/routes/+page.marko
  • packages/run/src/__tests__/fixtures/bun-adapter/test.config.ts
  • packages/run/src/__tests__/fixtures/bun-adapter/tsconfig.json
  • packages/run/src/__tests__/fixtures/bun-adapter/vite.config.ts

Comment thread packages/adapters/bun/src/index.ts
Comment thread packages/adapters/bun/src/index.ts
rturnq added 2 commits July 1, 2026 03:37
The runtime's fetch returns a 404 response (not undefined) for unmatched
paths, so the entry must fall back to serving static assets on a 404
rather than only when fetch returns nothing. Otherwise requests for
static files (eg. /assets/*.js) returned 404 and the client bundle never
loaded. Verified end-to-end under Bun.
- Add package.toggle.json so publish points exports/types at dist/ (the
  pkg-toggle release step skips packages without it)
- Make the injected import.meta.url shim a string (.href) so the CJS
  build's path.dirname(import.meta.url) works
- Fix the README platform example to read from context.platform (handlers
  receive (context, next), not a platform destructure)
- Preserve an explicit PORT=0 (free port) instead of falling back to 3000
- Attach an error handler to the preview child process and throw instead
  of exiting the process when the Bun CLI is missing

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/adapters/bun/src/index.ts (1)

59-63: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

shell: true with computed entryFile/cwd remains unresolved.

This still spawns via shell: true with entryFile derived from dir/entry. On POSIX, args are joined into a single string parsed by /bin/sh -c, so shell metacharacters or spaces in entryFile/cwd can be mis-parsed or enable injection if those values are ever influenced by less-trusted config. This diff only adds the error handler; the underlying shell: true risk previously flagged is still present.

🔒 Suggested fix: avoid shell interpretation
-      const proc = spawn("bun", ["run", entryFile], {
-        cwd,
-        env: { ...process.env, PORT: port.toString() },
-        shell: true,
-      });
+      const proc = spawn(process.platform === "win32" ? "bun.cmd" : "bun", ["run", entryFile], {
+        cwd,
+        env: { ...process.env, PORT: port.toString() },
+      });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/adapters/bun/src/index.ts` around lines 59 - 63, The spawn call in
the bun adapter still uses shell: true with a computed entryFile, which leaves
the command subject to shell parsing and potential misinterpretation. Update the
process launch in the bun adapter’s spawn call to avoid shell interpretation
entirely, and pass the executable/arguments in a way that preserves the computed
entryFile and cwd safely without invoking a shell.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/adapters/bun/src/index.ts`:
- Around line 59-63: The spawn call in the bun adapter still uses shell: true
with a computed entryFile, which leaves the command subject to shell parsing and
potential misinterpretation. Update the process launch in the bun adapter’s
spawn call to avoid shell interpretation entirely, and pass the
executable/arguments in a way that preserves the computed entryFile and cwd
safely without invoking a shell.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea0c8ba8-46ba-4fbd-ae47-63e3bebb9954

📥 Commits

Reviewing files that changed from the base of the PR and between ec6e462 and d6099c1.

📒 Files selected for processing (5)
  • packages/adapters/bun/README.md
  • packages/adapters/bun/package.toggle.json
  • packages/adapters/bun/scripts/importMetaURL.js
  • packages/adapters/bun/src/default-entry.ts
  • packages/adapters/bun/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/adapters/bun/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/adapters/bun/scripts/importMetaURL.js
  • packages/adapters/bun/src/default-entry.ts

rturnq added 2 commits July 1, 2026 16:08
Use `shell: true` only on Windows (where `bun` may be a `.cmd` shim). On
POSIX the CLI is spawned directly, so `close()` kills Bun itself instead
of an orphaned shell wrapper and argument values are no longer re-parsed
by the shell. Verified end-to-end under Bun: the child receives SIGTERM
directly on close.
Clarify that Marko Run automatically uses an installed adapter with no
Vite config, and put the `npm run build` + `bun run dist/index.mjs` steps
in a Running section right after installation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant