<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Reusable transfer confirmation UI with clear loading, success, and error states. * Neon-specific transfer flow added, guiding sign-in, account switching, or accepting transfers. * Custom integration transfer flow with streamlined confirm/check behavior. * Improved transfer sign-up redirect so users return to the correct page after auth. * **Bug Fixes** * Consistent messaging for missing/invalid/expired transfer codes. * Safer widget “Reload” handling when reset may be unavailable. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- ## Summary Redesigns the **custom integration** project-transfer confirmation page (`/integrations/custom/projects/transfer/confirm`) onto the new design-components system (`DesignCard` + `DesignAlert` + `DesignButton` + `DesignInput`). The presentational shell is extracted into a reusable `ProjectTransferConfirmView` so the route file only handles state + API calls. The legacy Neon transfer page is split out unchanged into its own client component to keep the existing Neon × Stack co-branded UI intact. --- ## Screenshots — before and after > Captured against `http://localhost:8101` at 1280×900. Dev-only overlays (outdated-version banner, console toast, DEV badge) are hidden via injected CSS for clarity. ### Custom integration — missing transfer code Visiting `/integrations/custom/projects/transfer/confirm` with no `?code=…` query param. | Before (`dev`) | After (this PR) | | --- | --- | |  |  | |  |  | Before was a raw `"Error: No transfer code provided."` line. After is a dedicated `DesignAlert` with an explanation and recovery instructions. ### Custom integration — invalid / expired code (check endpoint fails) | Before (`dev`) | After (this PR) | | --- | --- | |  |  | |  |  | Before showed the raw backend error string (`Request validation failed on POST …`). After uses a `DesignCard` with the `ArrowsLeftRightIcon`, a friendlier "This transfer can't continue" copy in an inline `DesignAlert`, the Stack Auth logomark in the actions slot, and an explicit **Close** button to dismiss. ### Neon integration — legacy UI preserved The Neon page (`/integrations/neon/projects/transfer/confirm`) was deliberately **not** redesigned — it still uses the Neon × Stack co-branded card so partner-facing copy/branding stay identical. It's now its own client component (`neon-transfer-confirm-page.tsx`) instead of sharing the redesigned one. | Before (`dev`) | After (this PR) | | --- | --- | |  |  | |  |  | Same shell on both sides — copy was tightened slightly ("Return to your Neon dashboard and start the transfer again") and the raw API error string is gone. --- ## What changed - **New** `apps/dashboard/src/components/project-transfer-confirm-view.tsx` — purely presentational `ProjectTransferConfirmView`. Owns the design-components shell, the loading spinner, the signed-in vs signed-out branches of the success state (with `DesignInput` + "Use a different account" button), and the error / missing-code alerts. - **New** `apps/dashboard/src/app/(main)/integrations/neon-transfer-confirm-page.tsx` — extraction of the legacy Neon UI (Neon logo, Stack logo, "Project transfer" header, Card / CardContent / CardFooter). Behaviour and copy match the previous `transfer-confirm-page` exactly when `type === "neon"`. - **Rewritten** `apps/dashboard/src/app/(main)/integrations/transfer-confirm-page.tsx` — now hard-coded to the `custom` integration (no more `type` prop), defers UI to `ProjectTransferConfirmView`, and exports a `TransferConfirmMissingCodeView` used by the route when `code` is absent from the URL. - **Route plumbing** - `app/(main)/integrations/custom/projects/transfer/confirm/page.tsx` — renders the redesigned flow, falls back to `TransferConfirmMissingCodeView` when `code` is missing. - `app/(main)/integrations/neon/projects/transfer/confirm/page.tsx` — points at the new dedicated Neon client component. - **New** `apps/dashboard/src/lib/stack-app-internals.ts` — consolidates the symbol-keyed `getStackAppInternals(app)` helper (and `stackAppInternalsSymbol`) into one module with a JSDoc explainer + runtime type guard, replacing scattered `as any` casts. - **New** `apps/dashboard/src/lib/transfer-utils.ts` — `buildTransferSignUpUrl()` helper so the route file + the view stay in sync on the `/handler/signup?after_auth_return_to=…` query construction. --- ## Bot review follow-ups addressed in this PR - **Fail-loud assertions for unset handlers** in the success state of `ProjectTransferConfirmView` (`StackAssertionError` instead of silent no-op). - **SSR safety:** moved every `window.location` read into client-only handlers / `useEffect`s — the page was previously evaluating it at module load. - **Friendly error fallback** when the backend `/check` endpoint throws — replaces the raw `KnownError<…>` message with "This transfer link is invalid, has expired, or has already been used. Open the original link from the partner or integrations dashboard, or start the transfer again." - **`runAsynchronouslyWithAlert`** around every async `onClick` (Transfer, Sign in, Switch account, Close) so unhandled rejections surface to the user. - **JSX entity bug fix:** `'` was a string-attribute literal, not a JSX expression — converted to a JSX expression so it renders as `'`. - **`window.close()` removal** in error state — replaced with a Close button that resets local state, so users on a fresh tab (no opener) aren't stuck. - **`getStackAppInternals` consolidated** — previously three independent copies (here + two in `projects/page-client.tsx`). Now one helper with a runtime type guard instead of `as any`, plus a comment explaining the symbol-keyed SDK escape hatch. - **Widget-playground reset:** the original change here turned out to duplicate a deliberate prior fix on `dev` (N2D4, `e68015909d "Fix lint"`). Reverted in `fe92689eb` so we don't fight that fix. --- ## Notes for reviewers - **Start with** `components/project-transfer-confirm-view.tsx`. Everything reviewer-interesting is in the props shape (`ProjectTransferConfirmUiState` union, `onPrimary` / `onCancel` / `onSwitchAccount` callbacks). The route file just wires those to the `getStackAppInternals(app).sendRequest(...)` calls. - **The Neon page was intentionally not migrated.** Partner-facing co-branding (Neon logo × Stack logo, "Neon would like to transfer…" copy) is unchanged — flag it if you think it should be brought onto design-components too, but the goal of this PR was only the custom flow. - **API surface is unchanged** — same `/integrations/custom/projects/transfer/confirm/check` and `/integrations/custom/projects/transfer/confirm` endpoints, same request bodies, same redirect to `/projects/{project_id}` on success. - **Success state isn't in the screenshots** because reproducing it locally needs a real transfer code (the `/check` endpoint validates the code against the DB). It uses the same `DesignCard` shell with either a `DesignInput` showing the receiving account + a "Use a different account" outline button (signed-in branch), or a `DesignAlert variant="info"` prompting sign-in (signed-out branch). Worth manually testing on a real transfer before merging. ## Test plan - [ ] Visit `/integrations/custom/projects/transfer/confirm` with no `code` → renders the "transfer link is incomplete" alert (screenshots above) - [ ] Visit `/integrations/custom/projects/transfer/confirm?code=invalid` → renders the redesigned card with the friendly error inside a `DesignAlert variant="error"` and a working Close button - [ ] Trigger a real custom-integration transfer end to end → loading spinner, success state, "Accept transfer" works while signed in, "Sign in" deep-links to `/handler/signup?after_auth_return_to=…` while signed out - [ ] Visit `/integrations/neon/projects/transfer/confirm?code=…` → unchanged legacy Neon × Stack co-branded card - [ ] Light + dark mode visual sanity (screenshots above are the canonical reference) --------- Co-authored-by: Aadesh Kheria <kheriaaadesh@gmail.com> Co-authored-by: aadesh18 <110230993+aadesh18@users.noreply.github.com> |
||
|---|---|---|
| .agents/skills/pr-visual-writeup | ||
| .changeset | ||
| .claude | ||
| .cursor | ||
| .devcontainer | ||
| .github | ||
| .vscode | ||
| apps | ||
| configs | ||
| docker | ||
| docs | ||
| docs-mintlify | ||
| examples | ||
| packages | ||
| patches | ||
| scripts | ||
| sdks | ||
| skills/stack-auth | ||
| .dockerignore | ||
| .gitignore | ||
| .gitmodules | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| turbo.json | ||
| vitest.shared.ts | ||
| vitest.workspace.ts | ||
📘 Docs | ☁️ Hosted Version | ✨ Demo | 🎮 Discord
Stack Auth: The open-source auth platform
Stack Auth is a managed user authentication solution. It is developer-friendly and fully open-source (licensed under MIT and AGPL).
Stack Auth gets you started in just five minutes, after which you'll be ready to use all of its features as you grow your project. Our managed service is completely optional and you can export your user data and self-host, for free, at any time.
We support Next.js, React, and JavaScript frontends, along with any backend that can use our REST API. Check out our setup guide to get started.
Table of contents
- How is this different from X?
- ✨ Features
- 📦 Installation & Setup
- 🌱 Some community projects built with Stack Auth
- 🏗 Development & Contribution
- ❤ Contributors
How is this different from X?
Ask yourself about X:
- Is
Xopen-source? - Is
Xdeveloper-friendly, well-documented, and lets you get started in minutes? - Besides authentication, does
Xalso do authorization and user management (see feature list below)?
If you answered "no" to any of these questions, then that's how Stack Auth is different from X.
✨ Features
To get notified first when we add new features, please subscribe to our newsletter.
📦 Installation & Setup
To install Stack Auth in your Next.js project (for React, JavaScript, or other frameworks, see our complete documentation):
-
Run Stack Auth's installation wizard with the following command:
npx @stackframe/stack-cli@latest init -
Then, create an account on the Stack Auth dashboard, create a new project with an API key, and copy its environment variables into the .env.local file of your Next.js project:
NEXT_PUBLIC_STACK_PROJECT_ID=<your-project-id> NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=<your-publishable-client-key> STACK_SECRET_SERVER_KEY=<your-secret-server-key> -
That's it! You can run your app with
npm run devand go to http://localhost:3000/handler/signup to see the sign-up page. You can also check out the account settings page at http://localhost:3000/handler/account-settings.
Check out the documentation for a more detailed guide.
🌱 Some community projects built with Stack Auth
Have your own? Happy to feature it if you create a PR or message us on Discord.
Templates
Examples
- Stack Auth Example by career-tokens
- Stack Auth Demo by the Stack Auth team
- Stack Auth E-Commerce Example by the Stack Auth team
🏗 Development & Contribution
This is for you if you want to contribute to the Stack Auth project or run the Stack Auth dashboard locally.
Important: Please read the contribution guidelines carefully and join our Discord if you'd like to help.
Requirements
- Node v20
- pnpm v9
- Docker
Setup
Note: 24GB+ of RAM is recommended for a smooth development experience.
In a new terminal:
pnpm install
# Build the packages and generate code. We only need to do this once, as `pnpm dev` will do this from now on
pnpm build:packages
pnpm codegen
# Start the dependencies (DB, Inbucket, etc.) as Docker containers, seeding the DB with the Prisma schema
# Make sure you have Docker (or OrbStack) installed and running
pnpm restart-deps
# Start the dev server
pnpm dev
# In a different terminal, run tests in watch mode
pnpm test # useful: --no-watch (disables watch mode) and --bail 1 (stops after the first failure)
You can now open the dev launchpad at http://localhost:8100. From there, you can navigate to the dashboard at http://localhost:8101, API on port 8102, demo on port 8103, docs on port 8104, Inbucket (e-mails) on port 8105, and Prisma Studio on port 8106. See the dev launchpad for a list of all running services.
Your IDE may show an error on all @stackframe/XYZ imports. To fix this, simply restart the TypeScript language server; for example, in VSCode you can open the command palette (Ctrl+Shift+P) and run Developer: Reload Window or TypeScript: Restart TS server.
Pre-populated .env files for the setup below are available and used by default in .env.development in each of the packages. However, if you're creating a production build (eg. with pnpm run build), you must supply the environment variables manually (see below).
Useful commands
# NOTE:
# Please see the dev launchpad (default: http://localhost:8100) for a list of all running services.
# Installation commands
pnpm install: Installs dependencies
# Types & linting commands
pnpm typecheck: Runs the TypeScript type checker. May require a build or dev server to run first.
pnpm lint: Runs the ESLint linter. Optionally, pass `--fix` to fix some of the linting errors. May require a build or dev server to run first.
# Build commands
pnpm build: Builds all projects, including apps, packages, examples, and docs. Also runs code-generation tasks. Before you can run this, you will have to copy all `.env.development` files in the folders to `.env.production.local` or set the environment variables manually.
pnpm build:packages: Builds all the npm packages.
pnpm codegen: Runs all the code-generation tasks, eg. Prisma client and OpenAPI docs generation.
# Development commands
pnpm dev: Runs the development servers of the main projects, excluding most examples. On the first run, requires the packages to be built and codegen to be run. After that, it will watch for file changes (including those in code-generation files). If you have to restart the development server for anything, that is a bug that you can report.
pnpm dev:full: Runs the development servers for all projects, including examples.
pnpm dev:basic: Runs the development servers only for the necessary services (backend and dashboard). Not recommended for most users, upgrade your machine instead.
# Environment commands
pnpm start-deps: Starts the Docker dependencies (DB, Inbucket, etc.) as Docker containers, and initializes them with the seed script & migrations. Note: The started dependencies will be visible on the dev launchpad (port 8100 by default).
pnpm stop-deps: Stops the Docker dependencies (DB, Inbucket, etc.) and deletes the data on them.
pnpm restart-deps: Stops and starts the dependencies.
# Database commands
pnpm db:migration-gen: Currently not used. Please generate Prisma migrations manually (or with AI).
pnpm db:reset: Resets the database to the initial state. Run automatically by `pnpm start-deps`.
pnpm db:init: Initializes the database with the seed script & migrations. Run automatically by `pnpm db:reset`.
pnpm db:seed: Re-seeds the database with the seed script. Run automatically by `pnpm db:init`.
pnpm db:migrate: Runs the migrations. Run automatically by `pnpm db:init`.
# Testing commands
pnpm test <file-filters>: Runs the tests. Pass `--bail 1` to make the test only run until the first failure. Pass `--no-watch` to run the tests once instead of in watch mode.
# Various commands
pnpm explain-query: Paste a SQL query to get an explanation of the query plan, helping you debug performance issues.
pnpm verify-data-integrity: Verify the integrity of the data in the database by running a bunch of integrity checks. This should never fail at any point in time (unless you messed with the DB manually).
Note: When working with AI, you should keep a terminal tab with the dev server open so the AI can run queries against it.














