Skip to content

fix(void): ignore type-only exports when detecting route methods and SSR render - #221

Merged
Brooooooklyn merged 2 commits into
mainfrom
fix/ignore-type-only-exports
Jun 30, 2026
Merged

Brooooooklyn merged 2 commits into
mainfrom
fix/ignore-type-only-exports

Conversation

@hyfdev

@hyfdev hyfdev commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Route files and SSR entries that re-export a handler type no longer register a phantom runtime route or pass entry validation — the scanners now ignore type-only exports.

The bug

Two AST walkers that detect runtime exports never checked exportKind:

  • detectHttpExports (router/detect-exports.ts) — export type { GET } or export { type GET } in a route file made the scanner register a GET route. The export is erased at build time, so at request time the handler is undefined → a 500 instead of a 404/405.
  • validateServerRenderExport (ssr/entry.ts) — export type { render } made an SSR entry pass the "has a render export" check with no real render function.

Expected-correct behavior

A type-only export carries no runtime value, so it must not be treated as a route handler / render export. Verified against void's parser (vite parseSync): export type { X } carries exportKind: "type" at the statement level; export { type X } carries it at the specifier level — so both levels must be guarded.

Minimal repro

A route file routes/hello.ts containing type GET = () => Response; export type { GET }; produced detectHttpExports() === ['GET'] (should be []).

The fix

Skip exports whose exportKind === 'type' — at both the statement level (export type { ... }) and the specifier level (export { type X }) — in both detectors. Add exportKind to the shared AST specifier/declaration types. (As a bonus this also stops export declare const GET ambient declarations being mistaken for routes.)

Tests

Regression tests added: 2 in detect-exports.test.ts (statement-level type export → []; inline export { POST, type GET } → ['POST']) and 1 in ssr-entry.test.ts (export type { render } → throws the missing-render error). All fail on origin/main and pass after. Local gate: the two test files 19/19; full --project unit zero-collateral vs a clean origin/main baseline (identical pre-existing adapter/init-migration failures, unrelated); packages/void typecheck + lint + fmt clean.

I checked that these are the only two sites that infer a runtime export from named-export specifiers (the page loader/actions, websocket, and queue scanners use regexes/default-exports that are structurally immune), so the bug class is fully covered.

Prepared with AI assistance.

@netlify

netlify Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

❌ Deploy Preview for staging-void-cloud failed.

Name Link
🔨 Latest commit 7d65d8e
🔍 Latest deploy log https://app.netlify.com/projects/staging-void-cloud/deploys/6a3418584bcd9e0008df8f9f

@hyfdev
hyfdev marked this pull request as ready for review June 18, 2026 13:01
…SSR render

Both the route HTTP-method scanner (detect-exports) and the SSR entry
validator walked named-export specifiers without checking exportKind, so
a type-only export was mistaken for a runtime value. `export type { GET }`
or `export { type GET }` in a route file made the scanner register a GET
route whose handler is undefined at runtime (a 500 instead of a 404/405);
`export type { render }` made an SSR entry pass validation with no real
render function.

Skip exports whose exportKind is "type" (both the statement-level
`export type { ... }` and inline `export { type X }` specifiers) in both
detectors. Add exportKind to the shared AST specifier/declaration types.
@hyfdev
hyfdev force-pushed the fix/ignore-type-only-exports branch from e11c5c1 to 7d65d8e Compare June 18, 2026 16:09
@Brooooooklyn
Brooooooklyn merged commit 0287ae9 into main Jun 30, 2026
6 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/ignore-type-only-exports branch June 30, 2026 03:18
cpojer pushed a commit that referenced this pull request Sep 11, 2026
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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.

2 participants