Skip to content

Bun.FileSystemRouter: expose the assetPrefix getter on the prototype - #33433

Open
robobun wants to merge 1 commit into
mainfrom
farm/1f6a4571/filesystem-router-asset-prefix
Open

Bun.FileSystemRouter: expose the assetPrefix getter on the prototype#33433
robobun wants to merge 1 commit into
mainfrom
farm/1f6a4571/filesystem-router-asset-prefix

Conversation

@robobun

@robobun robobun commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Bun.FileSystemRouter.prototype.assetPrefix does not exist at runtime. The constructor accepts assetPrefix, bun-types declares readonly assetPrefix: string, and the prefix is demonstrably applied to match(...).src, but reading it back off the router returns undefined.

Repro

import { mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";

const dir = mkdtempSync(tmpdir() + "/fsr-prefix-");
writeFileSync(`${dir}/index.tsx`, "export default 1;\n");

const router = new Bun.FileSystemRouter({
  style: "nextjs",
  dir,
  origin: "http://o.test",
  assetPrefix: "/pfx/",
});

console.log("prototype keys:", Object.keys(Object.getOwnPropertyDescriptors(Object.getPrototypeOf(router))).sort().join(","));
console.log("assetPrefix:", router.assetPrefix, "| src:", router.match("/").src);

Before:

prototype keys: constructor,match,origin,reload,routes,style
assetPrefix: undefined | src: http://o.test/pfx/index.tsx

Cause

getAssetPrefix has been implemented since Bun.FileSystemRouter was introduced in d21aee5, but it was never listed in proto in filesystem_router.classes.ts, so the codegen never emitted the accessor. The getter was unreachable dead code, and the only place a consumer can learn the prefix back off the router reported undefined.

Fix

Add assetPrefix to the class definition's proto, alongside the existing origin/style getters (same cache: true shape; reload() preserves the configured prefix, so the cached value stays correct).

The getter now reports the empty string rather than null when no prefix is configured. An omitted assetPrefix and assetPrefix: "" already collapse to the same internal state (get_truthy + is_empty() both leave it unset), and the empty string is the prefix the router actually applies to MatchedRoute.src, so this keeps the declared readonly assetPrefix: string type honest. origin keeps returning null when absent, which is unchanged.

After:

prototype keys: assetPrefix,constructor,match,origin,reload,routes,style
assetPrefix: /pfx/ | src: http://o.test/pfx/index.tsx

Verification

Two tests added to test/js/bun/util/filesystem_router.test.ts: the accessor exists on the prototype and returns the configured prefix (including across reload(), and tied to the prefix applied to src), and it is "" when unset or set to "".

Both fail on the released binary and pass with the change; the file's other 27 tests still pass.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8628b15f-e530-4265-bd4e-5278899500ce

📥 Commits

Reviewing files that changed from the base of the PR and between 48ff9eb and 3e42223.

📒 Files selected for processing (3)
  • src/runtime/api/filesystem_router.classes.ts
  • src/runtime/api/filesystem_router.rs
  • test/js/bun/util/filesystem_router.test.ts

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

@robobun

robobun commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 10:32 AM PT - Jul 6th, 2026

@robobun, your commit 3e42223 has some failures in Build #69028 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 33433

That installs a local version of the PR into your bun-33433 executable, so you can run:

bun-33433 --bun

@github-actions github-actions Bot added the claude label Jul 6, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — wires up an already-implemented getter that was missing from the prototype definition.

Extended reasoning...

Overview

This PR exposes assetPrefix as a readable prototype accessor on Bun.FileSystemRouter. The Rust getter get_asset_prefix has existed since the class was introduced but was never listed in filesystem_router.classes.ts, so codegen never emitted the accessor and the function was dead code. Three files touched: a 4-line addition to the .classes.ts proto block (identical shape to the neighboring origin/style getters), a small tweak to the getter body to return "" instead of null when unset, and two new tests.

Security risks

None. This is a read-only accessor exposing a value the user themselves passed into the constructor. No new input parsing, no allocation changes, no new codepaths reachable from untrusted data.

Level of scrutiny

Low. The .classes.ts addition is purely mechanical and follows the exact pattern of the two getters directly above it. The Rust change touches only a previously-unreachable function and mirrors the existing get_origin pattern (.leak() on a BackRef<RefString>zs_to_js). cache: true is safe because asset_prefix is set once at construction and never mutated by reload() — the added test verifies this.

Other factors

  • The null"" change is well-reasoned: packages/bun-types/bun.d.ts declares readonly assetPrefix: string (not string | null), and "" is exactly what get_script_src applies when no prefix is set, so the reported value now matches both the type and the observable behavior in MatchedRoute.src.
  • Tests are placed in the existing test file, cover the set/unset/empty-string cases, verify the accessor is on the prototype (not own), and confirm it survives reload().
  • No prior human reviews or outstanding comments; bug-hunting system found nothing.

@robobun

robobun commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Status: the diff is green. The remaining red is CI infrastructure, not this change.

Build 69028 (sha 3e42223881) finished 282 jobs passed, 1 failed, 3 expired.

The one failure is darwin 26 aarch64 - test-bun, and no tests ran on it at all — the job died downloading the prebuilt binary, before a single test file was executed:

Error: buildkite-agent artifact download timed out after 120s for step 'darwin-aarch64-build-bun'.
Refusing to continue with a partial download (would silently fall back to the wrong binary).
    at getExecPathFromBuildKite (scripts/runner.node.mjs:2182:13)

The 3 expired jobs never got an agent. There are no error annotations on the build at all, only the usual flaky warning and binary-size info.

Both symptoms point at the same thing: the macOS agent pool is currently not picking up work. Every build in the recent range (69153 through 69163, across unrelated branches) has its darwin 26 aarch64 lanes sitting in scheduled / waiting, and the lane failed the same way on 69025, 69030 and 69035.

I'm deliberately not pushing a ci: retrigger commit: a re-roll would queue into the same stalled macOS queue and fail or expire the same way.

Nothing in any annotation mentions filesystem_router or assetPrefix. The tests added here passed on every lane that ran, including the ASAN, Windows and Linux lanes, and cargo clippy / Format / Lint JavaScript are green.

Earlier red on build 68819 (resolved)

The first run of this PR was red on test/js/bun/cookie/cookie-map.test.ts, failing on every test-bun lane:

- "__Host-id=; Path=/; Expires=Fri, 1 Jan 1970 00:00:00 -0000; Secure; SameSite=Lax"
+ "__Host-id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; SameSite=Lax"

That was tree-wide rather than specific to this branch (the same annotation was on builds 68820 through 68825, six other unrelated branches). Three assertions in the delete with prefixed cookie names block had not been updated when 028f210 (#32926) changed Bun.Cookie Expires to an IMF-fixdate. #33425 has since fixed those assertions on main; this branch is rebased onto it and the diff is unchanged.

getAssetPrefix has existed since the API was introduced but was never
listed in the class definition, so the property was missing at runtime
and reads returned undefined despite bun-types declaring it.

Report the empty string when no prefix is configured: an omitted
assetPrefix and assetPrefix: "" collapse to the same internal state, and
the empty string is the prefix the router applies to MatchedRoute.src.
@robobun
robobun force-pushed the farm/1f6a4571/filesystem-router-asset-prefix branch from 5361765 to 3e42223 Compare July 6, 2026 13:47

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — wires up an already-implemented getter that was missing from the codegen proto list.

Extended reasoning...

Overview

This PR exposes Bun.FileSystemRouter.prototype.assetPrefix, a getter that has been implemented in Rust since the class was introduced but was never listed in filesystem_router.classes.ts's proto block, so codegen never emitted the accessor. The change is three parts: (1) a 4-line addition to .classes.ts mirroring the adjacent origin/style entries; (2) a small refactor of get_asset_prefix to return "" instead of null when unset, matching the declared readonly assetPrefix: string type in bun-types and the actual prefix applied to MatchedRoute.src; (3) two new tests in the existing filesystem_router.test.ts.

Security risks

None. This is a read-only accessor returning a string the user themselves passed to the constructor. No new input parsing, no allocation changes, no path handling.

Level of scrutiny

Low. The Rust change is a trivial refactor of dead code into a match expression with a different fallback (b"" vs JSValue::NULL) — no new memory management, no new JS re-entry points, and zs_to_js on an empty static slice is well-trodden. The .classes.ts addition is byte-for-byte the same shape as origin two entries above. cache: true is safe because reload() doesn't touch this.asset_prefix (only router/arena), and the added test explicitly covers the post-reload() value.

Other factors

  • The bug hunting system found no issues.
  • The new tests are placed correctly in the existing test file, follow harness conventions, and cover both the set and unset cases plus the prototype descriptor shape.
  • CI ran green for the touched test file on all lanes including ASAN and Windows; the only red is a tree-wide cookie-map.test.ts assertion mismatch unrelated to this diff (since fixed on main by #33425 per the recent-commits log).
  • No prior human or bot reviews to address.

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator Author

Note for the rebase: this branch conflicts because #35002 (merged after this PR was opened) deleted FileSystemRouter::get_asset_prefix from src/runtime/api/filesystem_router.rs as unreferenced code, since nothing in the proto table pointed at it. Rebasing this PR means adding the getter back next to get_origin/get_style rather than editing it in place; the filesystem_router.classes.ts hunk and the tests still apply as is.

The other half of the same declaration/runtime survey, MatchedRoute.scriptSrc existing at runtime but not in bun.d.ts, is #39278 and does not overlap with this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant