Skip to content

Fix patch application and Vite asset serving#2

Merged
rzxx merged 6 commits into
mainfrom
codex/research-adapter-and-bun-host
May 16, 2026
Merged

Fix patch application and Vite asset serving#2
rzxx merged 6 commits into
mainfrom
codex/research-adapter-and-bun-host

Conversation

@rzxx
Copy link
Copy Markdown
Owner

@rzxx rzxx commented May 16, 2026

Summary

  • require explicit React patch appliers for manifest-versioned projection patches and advance patch cursors only after a successful apply
  • serve Vite public/production assets through the Bun host with path containment checks
  • add Bun host coverage for Vite dev and production public assets

Verification

  • bun test
  • bun run check

Summary by CodeRabbit

  • New Features

    • Declarative region helpers for screen projections (replace/merge/custom).
    • Program stream React provider + hooks and React root mount utility with error-boundary and hydration support.
    • Optional Vite-based client pipeline (dev + production) and automatic region-value patching.
  • Documentation

    • Updated runtime and developer-experience docs and README to reflect Bun-hosted runtime with client pipeline integration.
  • Tests

    • Added integration tests for host+client pipeline and automatic patching behavior.
  • Chores

    • Expanded dev tooling dependencies; removed legacy projection manifest and stylesheet reference.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 395dec9c-e604-43f6-919e-f5a2278e1aa1

📥 Commits

Reviewing files that changed from the base of the PR and between 71afa64 and c358a96.

📒 Files selected for processing (2)
  • src/framework/bun-host.ts
  • tests/bun-host.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/bun-host.test.ts
  • src/framework/bun-host.ts

📝 Walkthrough

Walkthrough

Adds a pluggable Vite client pipeline to the Bun host, a declarative Region-based projection API with automatic patching, React provider/root adapters, demo migrations, ProgramBuilder immutability, and tests.

Changes

Bun-hosted runtime with Vite client and region-based projection updates

Layer / File(s) Summary
Region projection API and automatic patching
src/framework/projection.ts, src/adapters/react/projection-patch.ts, src/adapters/react/react-adapter.ts
ProjectionRegionPatchStrategy adds replace-region and merge-fields. New Region factory creates region definitions; ScreenBuilder.regions() configures regions. createProjectionPatchApplier accepts an optional manifest and routes to applyRegionValuePatchAutomatically when no manifest is provided.
React provider, hooks, and root mounting
src/adapters/react/program-provider.tsx, src/adapters/react/root.tsx, src/adapters/react/index.ts
Adds ProgramStreamProvider with projection-ready deferred promise, hooks (useProgramStreamState, useProgramProjection, useProgramActions, useProgramNavigation, useProgramErrors), mountProgramReact and ProgramRootErrorBoundary, and re-exports.
Client pipeline contract and Vite implementation
src/framework/bun-host.ts
Introduces BunClientPipeline/PreparedClient; adds non-Vite client and Vite-specific prepareViteClient (dev server with HTML transform/proxy; prod build with manifest-based asset serving and safe file handling).
Server HTML transformation and rebuild routing
src/framework/bun-host.ts
/client.js and HTML responses delegate to prepared client; client.transformHtml() used for shell and initial render with dev reload injection. Rebuilds call client.rebuild(); shutdown closes client.
Demo app screens and provider integration
src/demo/approvals/screen.tsx, src/demo/approvals/projection-manifest.ts, src/demo/approvals/client/app.tsx, src/demo/approvals/client/approval-app.tsx
Screens switch to .regions() API; approvalProjectionPatchManifest removed. App uses mountProgramReact (error fallback) and wraps UI with ProgramStreamProvider consuming useProgramStreamState.
ProgramBuilder immutability and dependencies
src/framework/program.ts, package.json, src/vite-env.d.ts, src/shell.html
ProgramBuilder now stores configuration immutably in #definition; builder methods return new instances. Dev dependencies extended for Babel/Vite React tooling. Adds declare module "*.css"; and removes stylesheet link from shell HTML.
Architecture documentation and configuration examples
docs/design/runtime.md, docs/design/developer-experience.md, README.md, src/server.ts
Docs updated to describe Bun-hosted runtime with client pipeline and React adapter helpers; examples updated to show .regions() usage and Vite client configuration.
Vite client and projection patch test coverage
tests/bun-host.test.ts, tests/client-patch.test.ts
Adds Bun host tests for Vite dev/watch and production flows and client projection-patch tests for automatic region patching and manifest-driven region-first strategies.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

"🐰
A Vite client leaps swift and free,
Regions patch with clarity,
Providers wrap the stream so bright,
ProgramBuilder holds its light—
Framework flows without a fight!"

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix patch application and Vite asset serving' directly aligns with the main objectives: improving patch application logic and adding Vite asset serving through the Bun host.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/research-adapter-and-bun-host

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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)
src/vite-env.d.ts (1)

1-1: 💤 Low value

Consider providing typed exports for CSS Module imports.

The current declaration allows CSS imports but provides no typing for CSS Module exports. If the project uses CSS Modules (e.g., import styles from './App.module.css'), consider providing typed class name exports:

declare module "*.css" {
  const classes: Record<string, string>;
  export default classes;
}

If the project only performs side-effect CSS imports (import './styles.css'), the current declaration is sufficient.

🤖 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 `@src/vite-env.d.ts` at line 1, Update the module declaration for "*.css" to
provide typed exports for CSS Modules: replace the current bare "declare module
\"*.css\";" with a module block that declares and exports a default const (e.g.,
classes) typed as Record<string, string> so imports like "import styles from
'./App.module.css'" are typed; if you intentionally only use side-effect
imports, leave the existing declaration as-is.
tests/bun-host.test.ts (1)

202-291: ⚡ Quick win

Add a negative traversal test for public asset containment.

These new tests cover happy-path asset serving well, but they don’t assert that path traversal attempts are rejected. Adding one request like /../favicon.svg (or equivalent) with expected 403/404 would lock in the security guarantee introduced in this PR.

🤖 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 `@tests/bun-host.test.ts` around lines 202 - 291, Add a negative traversal
request to the existing Vite tests: after fetching the regular favicon in each
test (inside the try block of the "Vite client pipeline serves dev modules while
Bun owns the stream runtime" and "Vite client pipeline serves production
manifest and public assets" tests), issue an extra fetch to "/../favicon.svg"
(or similar traversal path) against the same server.port using fetch, and assert
the response does not succeed (e.g., expect(response.status).not.toBe(200) or
expect(response.status).toBeGreaterThanOrEqual(400) &&
expect(response.status).toBeLessThan(600)). This uses the same
serveBunProgram/TestMessage/TestProjection/TestTrace setup and server variable
already present in those tests.
🤖 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 `@src/adapters/react/root.tsx`:
- Around line 24-26: The hydration gate currently treats options.bootstrap by
truthiness which misroutes valid falsy values; change the condition in the block
that decides between hydrateRoot and createRoot to explicitly test for undefined
(e.g., options.bootstrap !== undefined or typeof options.bootstrap !==
"undefined") together with options.root.hasChildNodes(), so hydrateRoot is used
only when bootstrap was explicitly provided and the root has child nodes; leave
the createRoot fallback for when options.bootstrap is undefined.

In `@src/demo/approvals/client/app.tsx`:
- Around line 20-24: The errorFallback JSX in app.tsx currently renders
error.message directly (in the errorFallback prop), which can leak internals;
update the errorFallback handler (the errorFallback arrow function) to display a
generic user-facing message (e.g., "An unexpected error occurred") unless
running in development, in which case include the actual error.message for
debugging; locate the errorFallback prop in the component and replace the direct
error.message usage with a conditional that checks process.env.NODE_ENV ===
'development' before exposing error.message.

---

Nitpick comments:
In `@src/vite-env.d.ts`:
- Line 1: Update the module declaration for "*.css" to provide typed exports for
CSS Modules: replace the current bare "declare module \"*.css\";" with a module
block that declares and exports a default const (e.g., classes) typed as
Record<string, string> so imports like "import styles from './App.module.css'"
are typed; if you intentionally only use side-effect imports, leave the existing
declaration as-is.

In `@tests/bun-host.test.ts`:
- Around line 202-291: Add a negative traversal request to the existing Vite
tests: after fetching the regular favicon in each test (inside the try block of
the "Vite client pipeline serves dev modules while Bun owns the stream runtime"
and "Vite client pipeline serves production manifest and public assets" tests),
issue an extra fetch to "/../favicon.svg" (or similar traversal path) against
the same server.port using fetch, and assert the response does not succeed
(e.g., expect(response.status).not.toBe(200) or
expect(response.status).toBeGreaterThanOrEqual(400) &&
expect(response.status).toBeLessThan(600)). This uses the same
serveBunProgram/TestMessage/TestProjection/TestTrace setup and server variable
already present in those tests.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6459ad31-0954-47f0-bbee-50241eda1dac

📥 Commits

Reviewing files that changed from the base of the PR and between eebada3 and d43f6ab.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • README.md
  • docs/design/developer-experience.md
  • docs/design/runtime.md
  • package.json
  • src/adapters/react/index.ts
  • src/adapters/react/program-provider.tsx
  • src/adapters/react/projection-patch.ts
  • src/adapters/react/react-adapter.ts
  • src/adapters/react/root.tsx
  • src/demo/approvals/client/app.tsx
  • src/demo/approvals/client/approval-app.tsx
  • src/demo/approvals/projection-manifest.ts
  • src/demo/approvals/screen.tsx
  • src/framework/bun-host.ts
  • src/framework/program.ts
  • src/framework/projection.ts
  • src/server.ts
  • src/shell.html
  • src/vite-env.d.ts
  • tests/bun-host.test.ts
  • tests/client-patch.test.ts
💤 Files with no reviewable changes (2)
  • src/demo/approvals/projection-manifest.ts
  • src/shell.html

Comment thread src/adapters/react/root.tsx Outdated
Comment thread src/demo/approvals/client/app.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/framework/bun-host.ts (1)

122-134: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Let host-managed CSS routes win before the Vite proxy.

client.serve() now runs before assets.byRoute, and isViteAssetPath() claims every .css request. In Vite dev mode that means a configured Bun style asset like /assets/demo.css gets proxied to Vite instead of the host style builder, so enabling client.kind: "vite" breaks options.assets.styles.

Suggested fix
-      const clientResponse = await client.serve(request);
-
-      if (clientResponse) {
-        return clientResponse;
-      }
-
       const asset = assets.byRoute.get(url.pathname);
 
       if (asset) {
         return new Response(Bun.file(asset.output), {
           headers: { "Content-Type": "text/css; charset=utf-8" },
         });
       }
+
+      const clientResponse = await client.serve(request);
+
+      if (clientResponse) {
+        return clientResponse;
+      }

Also applies to: 472-483, 732-750

🤖 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 `@src/framework/bun-host.ts` around lines 122 - 134, Reorder the host asset
check so host-managed CSS routes are served before proxying to Vite: before
calling client.serve(), check assets.byRoute.get(url.pathname) (and/or
isViteAssetPath()) and if an asset exists return the Bun.file Response for that
asset; alternatively, make client.serve() skip proxying when assets.byRoute
contains the pathname. Apply this change to the occurrences around client.serve
/ assets.byRoute (the shown block plus the other spots mentioned at ~472-483 and
~732-750) so host style assets win over the Vite proxy.
🤖 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 `@src/framework/bun-host.ts`:
- Around line 574-581: The serveVitePublicAsset function currently restricts
serving to `${root}/public` and only files matching isStaticAssetPath; instead,
change it to use Vite's resolved publicDir and stop filtering by extension:
locate serveVitePublicAsset and replace the hardcoded join(root, "public") +
isStaticAssetPath check with logic that reads Vite's resolved publicDir (from
the Vite config/resolved config passed into your host or obtained via
resolveConfig) and call serveViteFile against that directory for any matching
URL path under publicDir (including extensionless files and .well-known,
.webmanifest, etc.), ensuring you preserve path normalization/security checks
already in serveViteFile.
- Around line 525-533: injectViteProductionAssets currently only uses entry.css
and entry.file so CSS from imported chunks is omitted; update the function
(injectViteProductionAssets) to accept the full Vite manifest (e.g., manifest:
Record<string, ViteManifestEntry>), then recursively traverse entry.imports to
collect css from each referenced manifest entry (follow imports depth-first,
deduplicate files using a Set) and include those CSS links along with entry.css
and the entry.file script when building tags; finally inject the combined,
deduped CSS links + script into the HTML as before.

---

Outside diff comments:
In `@src/framework/bun-host.ts`:
- Around line 122-134: Reorder the host asset check so host-managed CSS routes
are served before proxying to Vite: before calling client.serve(), check
assets.byRoute.get(url.pathname) (and/or isViteAssetPath()) and if an asset
exists return the Bun.file Response for that asset; alternatively, make
client.serve() skip proxying when assets.byRoute contains the pathname. Apply
this change to the occurrences around client.serve / assets.byRoute (the shown
block plus the other spots mentioned at ~472-483 and ~732-750) so host style
assets win over the Vite proxy.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 24869886-0096-46d0-9d02-ced759eb0003

📥 Commits

Reviewing files that changed from the base of the PR and between d43f6ab and 71afa64.

📒 Files selected for processing (4)
  • src/adapters/react/root.tsx
  • src/demo/approvals/client/app.tsx
  • src/framework/bun-host.ts
  • tests/bun-host.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/demo/approvals/client/app.tsx
  • src/adapters/react/root.tsx

Comment thread src/framework/bun-host.ts Outdated
Comment thread src/framework/bun-host.ts Outdated
@rzxx rzxx merged commit fd018f0 into main May 16, 2026
1 check passed
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