feat: serve the /api surface from an Express app embedded in the daemon (migration step 1) - #247
Draft
oxedom wants to merge 12 commits into
Draft
feat: serve the /api surface from an Express app embedded in the daemon (migration step 1)#247oxedom wants to merge 12 commits into
oxedom wants to merge 12 commits into
Conversation
…on design spec Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Node's pipe() unpipes on destination close but never destroys the source, so an early client disconnect left long-lived handlers (e.g. SSE routes mounted through this adapter) producing forever. Destroy the Readable on res "close" when it hasn't ended, which propagates to the underlying web ReadableStream's cancel(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Covers the cloudGateActive() -> verifyCloudToken() branch of the Express auth gate: valid cabinet_jwt cookie injects the verified subject, missing cookie 401s, a token signed by a key outside the JWKS 401s, and a spoofed x-cabinet-user header is overridden by the verified subject. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Assembles buildApiApp() from the route manifest, adapter, and auth gate (Tasks 1-3), and wires it into the daemon: /api/* requests are delegated to the embedded Express app before the daemon's own bearer-token gate runs, boot now ensures the auth salt and .env-sourced auth vars are in place before the first request, and the one next/headers route (auth/check) is rewritten to read cookies off NextRequest so it works under both Next and the adapter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The initWhatsAppGateway/shutdownWhatsAppGateway calls were swept into 669db68 from a concurrent working tree, but server/whatsapp/ itself was never committed on this branch, leaving the daemon importing a module that doesn't exist in git. The connector lands properly via feat/whatsapp-connector (PR #245). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…er token Instead of replicating a logged-in browser's kb-auth cookie, cron-scheduler triggers now hit the daemon's own embedded Express /api with the daemon's Authorization: Bearer token, since the daemon hosts the entire /api surface itself (Task 4) and its auth gate accepts that bearer token (Task 3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-backend-extraction
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.
Summary
Step 1 of the Next.js → Express → TanStack migration (design:
docs/superpowers/specs/2026-07-14-nextjs-to-express-tanstack-migration.md, plan:docs/superpowers/plans/2026-07-14-express-backend-extraction.md).The daemon's HTTP server gains an embedded Express 5 app that serves all 148 Next.js API route handlers verbatim — no per-route rewrites:
server/http/route-manifest.ts, checked in;npm run api:manifest[:check]) mappingsrc/app/api/**/route.ts→ Express paths ([id]→:id,[...path]→*path), ordered so literals beat params beat wildcards.server/http/next-route-adapter.ts): Node req →NextRequest(streamed bodies,duplex: half), handlerResponse→ Node res (streamed, multiSet-Cookie, source cancelled on client disconnect for SSE).server/http/auth-gate.ts): mirrorssrc/proxy.tssemantics (KB_PASSWORD cookie / Cabinet Cloud ES256 JWT withx-cabinet-userinjection + spoof-stripping / health & login carve-outs) plus daemon-bearer-token acceptance. Cloud path covered by tests against a real local JWKS./apiwith the bearer token — the kb-auth cookie-replication hack (ensureAuthEnvFromDotEnvinsideputJson) is gone from the trigger path.Status — draft while remaining tasks land
buildApiApp()+ daemon wiring (live-verified on an isolated port/data dir)CABINET_API_VIA_DAEMONcutover rewrite insrc/proxy.ts(opt-in)Note for reviewers
Commit 669db68 ("feat: add managed CLIProxyAPI connector") is an unrelated feature that a concurrent session committed onto this branch mid-flight. Pending a decision: rebase it out to its own branch (requires regenerating the route manifest to drop its route) or keep it. Every task-review diff range on this branch excluded it.
Each task was implemented by a fresh subagent, reviewed (spec + quality) by an independent reviewer, and fixed/re-reviewed where findings came back (stream-cancellation leak, cloud-JWT coverage). Full unit suite green at every commit; 8 new tests files-worth of coverage added along the way.
🤖 Generated with Claude Code