Please provide the environment you discovered this bug in.
Analog v3 alpha on Linux, Node 24.15.0, pnpm 10.33.0. The public reproduction uses Angular 22.1.5, Vite 8.2.2, Nitro 3.0.260903-beta, and the split analog() / angular() / nitro() integration.
Regression-only reproduction commit from the requested split of #2516. It contains the existing HTTP implementation and tests/fixtures that demonstrate the failures, on top of the separately prepared compiler, Vitest, and SSR prerequisites.
git clone https://github.com/benpsnyder/analog.git
cd analog
git checkout 0c146b877
corepack enable
pnpm install --frozen-lockfile
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx run router:test --testFile=event-handler.spec.ts,client-transport.spec.ts --skip-nx-cache
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx run analog-app-e2e:server-functions
Use the Node version pinned in .node-version. The two regression commands are expected to fail before the repair; run both independently.
Which area/package is the issue in?
router, platform
Description
A directly exported server function in a .server.ts module that no page imports is not registered by the split Nitro integration. The first /_analog/fn/:id call reaches the HTML renderer and receives HTML instead of the JSON function result. The reproduction starts a fresh built server, obtains readiness from its listening-socket announcement, and calls the function before any HTML request.
The request/response adapter also loses HTTP and JSON semantics. The Node socket regressions show validation and malformed-input errors returning 200 instead of 400, redirects returning 200 instead of 303, and cookie responses returning 200 instead of 204. Angular's client turns null into {} and sends strings as unquoted text, while raw string/null return values are not consistently encoded as JSON.
A concrete use case is an API-only caller invoking an echo function or redirect before anyone visits the site. The application should not need a page render to register that endpoint, and JSON null, empty strings, booleans, numbers, arrays, and objects should retain their meaning.
Expected behavior:
- Discover actual directly exported server functions, including configured additional directories, and register their handler on cold startup. Exclude load-only/unrelated server modules.
- Use the same canonical server application config and function IDs as the SSR/client transforms; reject ambiguous config files at build time.
- Preserve JSON input/output values, explicit response formats, error/redirect statuses, and separate cookies over real HTTP. Preserve Angular HTTP interceptors.
- Keep discovery functional when HTML SSR is disabled.
Please provide the exception or error you saw
The unit/socket baseline reports 12 failed, 15 passed. Representative failures:
expected '{}' to be 'null'
expected 'text' to be '"text"'
expected 200 to be 400
expected 200 to be 303
expected 200 to be 204
The cold built-server request fails its content-type assertion:
Expected: /application\/json/
Actual: text/html; charset=utf-8
Other information
This is workstream 4 from Brandon Roberts' request. The focused fix and runnable HTTP fixture are published in analogjs/analog#2529, targeting alpha. Current head c1af22de104cd43067c60de3852751c5b857ae5b passes the dedicated HTTP runtime workflow, main/application E2E, Windows, and preview CI. Its description records cold-start registration, JSON/status/cookie contracts, and necessary shared prerequisites. The failing reproduction above remains pinned; this issue stays open pending merge.
Related: analogjs/analog#2496 reports over-broad discovery in the legacy vite-plugin-nitro integration. This issue covers missing cold registration and transport semantics in the split v3 integration; it does not close the separate legacy report. Request-injector disposal, cancellation, hydration, and Query cache ownership belong to the next workstream.
I would be willing to submit a PR to fix this issue
Please provide the environment you discovered this bug in.
Analog v3 alpha on Linux, Node 24.15.0, pnpm 10.33.0. The public reproduction uses Angular 22.1.5, Vite 8.2.2, Nitro 3.0.260903-beta, and the split
analog()/angular()/nitro()integration.Regression-only reproduction commit from the requested split of #2516. It contains the existing HTTP implementation and tests/fixtures that demonstrate the failures, on top of the separately prepared compiler, Vitest, and SSR prerequisites.
Use the Node version pinned in
.node-version. The two regression commands are expected to fail before the repair; run both independently.Which area/package is the issue in?
router, platform
Description
A directly exported server function in a
.server.tsmodule that no page imports is not registered by the split Nitro integration. The first/_analog/fn/:idcall reaches the HTML renderer and receives HTML instead of the JSON function result. The reproduction starts a fresh built server, obtains readiness from its listening-socket announcement, and calls the function before any HTML request.The request/response adapter also loses HTTP and JSON semantics. The Node socket regressions show validation and malformed-input errors returning 200 instead of 400, redirects returning 200 instead of 303, and cookie responses returning 200 instead of 204. Angular's client turns
nullinto{}and sends strings as unquoted text, while raw string/null return values are not consistently encoded as JSON.A concrete use case is an API-only caller invoking an echo function or redirect before anyone visits the site. The application should not need a page render to register that endpoint, and JSON
null, empty strings, booleans, numbers, arrays, and objects should retain their meaning.Expected behavior:
Please provide the exception or error you saw
The unit/socket baseline reports 12 failed, 15 passed. Representative failures:
The cold built-server request fails its content-type assertion:
Other information
This is workstream 4 from Brandon Roberts' request. The focused fix and runnable HTTP fixture are published in analogjs/analog#2529, targeting
alpha. Current headc1af22de104cd43067c60de3852751c5b857ae5bpasses the dedicated HTTP runtime workflow, main/application E2E, Windows, and preview CI. Its description records cold-start registration, JSON/status/cookie contracts, and necessary shared prerequisites. The failing reproduction above remains pinned; this issue stays open pending merge.Related: analogjs/analog#2496 reports over-broad discovery in the legacy
vite-plugin-nitrointegration. This issue covers missing cold registration and transport semantics in the split v3 integration; it does not close the separate legacy report. Request-injector disposal, cancellation, hydration, and Query cache ownership belong to the next workstream.I would be willing to submit a PR to fix this issue