Skip to content

feat: seamless add, for an existing Express, Fastify or React project - #255

Merged
Bccorb merged 1 commit into
mainfrom
feat/seamless-add
Oct 8, 2026
Merged

Bccorb merged 1 commit into
mainfrom
feat/seamless-add

Conversation

@Bccorb

@Bccorb Bccorb commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Closes #210. Part of fells-code/seamless-auth-api#371. Depends on #254, which pins the auth server at v0.18.0.

seamless add adds Seamless Auth to a project you already have. seamless init only starts new ones.

seamless add --local [email protected]   # an auth server on this machine, in seamless/
seamless add --app <id>                        # or a managed application

It never edits the project's source files. It:

  1. Detects an Express or Fastify backend and a React web app (Vite or Create React App). It looks at the root and in api/, server/, backend/, web/, client/, frontend/, apps/* and packages/*, and records each one's language, entry file and package manager (npm, pnpm, yarn or bun, read from the nearest lock file up to the repo root). Go, Rust, Python, Angular, Vue, Svelte and Next.js are reported as not wired yet (feat(add): add Seamless Auth to existing Go, Rust, Python, Angular, Vue and Svelte projects #248).
  2. Connects an auth server, as init does. --local writes seamless/docker-compose.yml (the auth server on 127.0.0.1:5312, and Postgres with no published port, because the project may already run its own) and seamless/.env, which holds the secrets and is gitignored. APP_ORIGINS and ORIGINS come from the project's real origins. --app connects a managed application with init's own helpers, now in core/managedConnect.ts. Under --yes you must pass --local or --app, and replacing a stack or rotating a token needs --force, as in init.
  3. Writes env files. The backend .env gets the auth server URL and issuer, service token and key id, and keeps the existing cookie secret, UI_ORIGINS and every other line or comment. A new merge writer (core/envFile.ts) does this, because writeEnv rewrites the whole file. The web app's .env.local gets its API URL. add warns if the backend .env is not gitignored.
  4. Installs the adapter (plus cookie-parser and cors for Express, @fastify/cors for Fastify) and @seamless-auth/react with the project's package manager. --skip-install prints the commands instead.
  5. Prints the code for the server and for the React root, in TypeScript or JavaScript to match the project. It follows the conformance reference apps: /auth, credentialed CORS for the web origin, a protected /api/me, the /console mount when enabled, development-only logging of one-time codes (the auth server does not send them in development), and the req.user typing for TypeScript Express.

Verified end to end

I built a fresh Express 5 + TypeScript API and a stock Vite react-ts app (npm create vite), then ran seamless add --local. I pasted the printed code in as a user would. Both halves pass their own tsc. I started the stack (auth image at v0.18.0, as #254 sets it) and drove the backend over HTTP:

  • its own / route still answers
  • /console serves the dashboard
  • cookie email-OTP sign-in, with the code read from the printed dev logging
  • /api/me, bearer sign-in, and logout

I then did the same for a plain JavaScript Fastify app (--admin=none), and checked that its printed code passes node --check.

The first run caught three bugs, all fixed here:

  • req.user did not typecheck in a TypeScript Express app.
  • The printed steps did not say how to load .env into an app that does not already.
  • runCommand triggered Node 24's DEP0190 warning.

Other changes

  • runCommand uses a shell only on Windows. Every caller passes plain argument arrays, so this is safe, and it stops paths with spaces being re-split.
  • resolveOwnerEmail is exported so add asks for the owner as init does.

Tests: 1222 pass, plus 45 new ones (detect, envFile, authStack, snippets, and add for local, managed, interactive and edge cases). tsc --noEmit and build pass, and coverage is above the thresholds.

Detects the backend and web app, connects a local auth server (written to
seamless/, secrets gitignored) or a managed application, writes the backend's
.env and the web app's API URL without touching existing values or comments,
installs the adapter and SDK with the project's package manager, and prints the
code to add in TypeScript or JavaScript. It never edits source files.

To share the managed connection with init, resolveJwksKid, issueServiceToken,
requireInstanceUrl and connectable move into core/managedConnect. runCommand
uses a shell only on Windows, where npm is a .cmd script; elsewhere arguments
reach the program as given, so a path with spaces is not re-split and Node 24
no longer warns (DEP0190).

Refs #210
@Bccorb
Bccorb merged commit fee2a40 into main Oct 8, 2026
5 checks 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.

feat: add Seamless Auth to an existing app

1 participant