Repository navigation
fix(check): diagnose CommonJS app roots instead of reporting 0 routes - #701
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
blove
temporarily deployed
to
vercel-preview
September 17, 2026 06:05 — with
GitHub Actions
Inactive
blove
enabled auto-merge (squash)
September 17, 2026 16:29
blove
force-pushed
the
blove/check-commonjs-app-root
branch
from
September 17, 2026 16:40
835a4b9 to
0210d14
Compare
`b4 check` reported a clean `0 routes discovered` for an app whose
package.json lacked `"type": "module"`: tsx compiled every route as
CommonJS, `import()` handed back the `{ default: { __esModule, default } }`
interop wrapper, `inferRouteKind` returned null, and the route was silently
dropped (#685).
- `findB4App` now rejects an app root whose package.json does not set
`"type": "module"` (B4_E1006), naming the file and the fix.
- Route discovery now fails (B4_E1007) when a route index.ts has no
recognisable export, naming the file, the exports it found, and — when the
namespace has the CommonJS interop shape — the nearest package.json as the
likely cause. Non-route directories belong behind a `_` prefix.
- New `B4AppError` in @b4run/core carries the registry code so `b4 check`
renders the `[B4_Exxxx] See <docs>` footer.
- Tests: pure unit tests for the interop-shape explanation, discovery tests
for both codes, and a built-CLI test that exercises the real tsx path
(vitest routes imports through vite-node, which never produces the shape).
- Fixtures that wrote a bare `{}` package.json now declare `"type": "module"`.
- Docs: `b4 check` bullets, regenerated error-code table, `B4AppError` on
the core API page; the generator's intro wording is aligned with the
committed page.
Closes #685
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ange Self-review follow-ups on the #685 fix. - Node's own package.json reader tolerates a UTF-8 BOM, but `JSON.parse` rejects it, so the new app-root check turned a manifest Node loads happily into "package.json is not valid JSON" and failed every command. Strip a leading BOM before parsing, with a regression test that fails without it. - Document the transition in upgrading.mdx: B4_E1006 also breaks apps that worked, because Node's CommonJS lexer hoists `export const workflow` into a named export, so route discovery succeeded while b4.config.ts was silently read through the interop wrapper and every setting on it ignored. - Refresh the SEO lastmod manifest for the edited page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blove
force-pushed
the
blove/check-commonjs-app-root
branch
from
September 17, 2026 16:43
0210d14 to
c103fa9
Compare
blove
temporarily deployed
to
vercel-preview
September 17, 2026 16:54 — with
GitHub Actions
Inactive
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #685.
Problem
When an app root's
package.jsonlacks"type": "module",b4 checkreportedB4.run app is valid: 0 routes discovered.and exited 0. The tsx loader compiles each routeindex.tsas CommonJS, soimport()returns the ESM/CommonJS interop wrapper ({ default: { __esModule: true, default: <agent> } }),inferRouteKindreturnsnull, and the route is silently dropped. Routes using a namedexport const workflowstill worked, so the failure only hit the scaffoldedexport default agent(...)shape. The same wrapper also madeb4.config.tsload as{ __esModule, default }, silently ignoring the author's config.Fix
B4_E1006App root package.json is not an ES module.findB4Appreads the app root'spackage.jsonand rejects it unless"type": "module"is set, naming the file, what it found, and the fix. This runs before config loading, so every command that discovers routes (check,dev,build,verify,routes,typegen, the testing harness) fails early instead of misbehaving. An unparseablepackage.jsonis also reported instead of being passed to tsx.B4_E1007Route entry has no recognisable export. A route directory whoseindex.tsexports nothing B4.run recognises is now an error naming the file and the exports it found. When the namespace has the CommonJS interop shape ("module.exports"key ordefault.__esModule === true), the message names the nearestpackage.jsonas the likely cause. A directory that is not a route should carry a_prefix, and the message says so. This replaces the previous "skip silently" behaviour indiscoverRoutes.B4AppError(new,@b4run/core) carries a registry code sob4 checkrenders the[B4_Exxxx] See <docs>footer through the existingCliErrorpath.Tests
@b4run/sdk: registry entries for both codes.@b4run/core: discovery rejects a missing /"commonjs"/ malformedpackage.jsonwithB4_E1006; anindex.tswith no recognisable export throwsB4_E1007naming the file; pure unit tests for the interop-shape explanation (explainUnrecognisedRouteExports).@b4run/cli:b4 checkemits both codes with docs links in-process, plus a built-CLI subprocess test that reproduces the issue exactly (app root without"type", default-export agent) and the nested-package.jsonvariant. The subprocess test is necessary: under vitest the route import goes through vite-node, which compiles TypeScript regardless ofpackage.jsontype, so the interop shape is only reachable through the real tsx loader.{}package.json(about 140 lines across the CLI tests plus the four committedtest/fixtures/contracts/*apps) now declare"type": "module", which is what a real app must have.Docs
b4 checkbullets for both codes on/docs/cli.errors.mdxregenerated. The generator's intro said "B4 failure" while the committed page said "B4.run failure"; the generator now matches the page so regeneration is reproducible.B4AppErroron the core API page (docs completeness check).Verification
Local:
pnpm lint,pnpm typecheck,pnpm test(the only failures in the full run were a workspace 64 MiB timeout and a Docker-smoke fake-marker timeout, both of which pass in isolation and were CPU contention from concurrent sessions),node scripts/check-docs.mjs,node scripts/check-changesets.mjs,pnpm test:release-integrity.Manual, with the built CLI against the issue's repro:
Not released; changeset is
patchfor@b4run/sdk,@b4run/core,@b4run/cli.🤖 Generated with Claude Code