Commit Graph

3369 Commits

Author SHA1 Message Date
Bilal Godil
e78ec78471 Fix local-emulator e2e: use canonical HEXCLAVE_ var to avoid dual-read conflict
The dashboard build inlines both NEXT_PUBLIC_HEXCLAVE_* and NEXT_PUBLIC_STACK_*
spellings and throws when they're set to different non-empty values. The job set
the legacy NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=true while the dashboard commits
NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=false in .env.development, so every build
crashed on the conflict check.

Set the canonical NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=true instead: the
job-level value overrides the committed default (process.env wins over dotenv)
and leaves no conflicting STACK_ twin.
2026-06-16 18:12:36 -07:00
Bilal Godil
1ede37281f Don't ship env-var conflict-throw in generated customer SDK
The generated env.ts getters ship inside @hexclave/stack / @hexclave/react
and are read on a hot, side-effect-free path by SDK consumers. The
conflict-detection helper added with the HEXCLAVE_* rename made those getters
throw when both a HEXCLAVE_* and STACK_* spelling were set to different values
— a breaking change to env-var reading for SDK users.

Revert the generated getters to a plain || dual-read chain (prefer HEXCLAVE_*,
fall back to legacy STACK_*, empty-as-unset), with no throw. Conflict detection
stays in our own non-shipped infra only (packages/shared getEnvVariable/
getProcessEnv, dashboard inline env, CLI auth, docker entrypoint).

Order-preserving dedup of the candidate list is kept so HEXCLAVE_API_URL no
longer emits its STACK_URL aliases twice.
2026-06-16 17:56:47 -07:00
BilalG1
c9602352df
Merge branch 'dev' into rename-env-vars-hexclave 2026-06-16 17:46:50 -07:00
Konsti Wohlwend
c50f1e64ed
Add 6/12/26 changelog entry (#1589) 2026-06-16 16:44:03 -07:00
Aman Ganapathy
d3667fec19
[Chore]: Fix broken build due to absent key (#1614)
### Summary of Changes
Added clickmap to the app-card



<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixed a build error by adding the missing `clickmaps` key to `APP_ICONS`
in the docs app-card and importing `MousePointerClick` from
`lucide-react`. This restores the docs build and shows the Clickmaps
icon in app cards.

<sup>Written for commit 0c5d3331ac.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1614?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-16 16:41:32 -07:00
Konsti Wohlwend
4546615713
feat: add custom OIDC provider support (team plan+ only) (#1594) 2026-06-16 16:35:11 -07:00
Konsti Wohlwend
010c114c49
fix: disable source maps in RDE dashboard build (#1611) 2026-06-16 16:29:15 -07:00
BilalG1
9ad92b9e4e Fix dashboard build crash: preserve empty/sentinel passthrough in inline env resolver
resolveInlineRenamedEnvVar collapsed empty-string and unreplaced-sentinel
values to `undefined` via its `|| ... || undefined` tail. The pre-rename inline
(`process.env.HEXCLAVE ?? process.env.STACK`) returned the raw value, so an
unset NEXT_PUBLIC_* var (which Next inlines as "") came through as "" and
downstream `getPublicEnvVar(...) ?? throwErr(...)` readers were satisfied.

Returning `undefined` instead made those `?? throwErr` checks fire during
`next build` page-data collection (e.g. the AI companion widget's
NEXT_PUBLIC_BROWSER_STACK_API_URL read), crashing the dashboard build in the
check-prisma-migrations job (which builds the dashboard via the CLI's
rde-standalone bundle).

Restore the `??` passthrough for the raw fallback so empty/sentinel values are
preserved, while keeping conflict detection and the empty-as-unset shadowing
protection (a real STACK value is still returned over an empty HEXCLAVE one).
Verified: dashboard `next build` collects page data without throwing.
2026-06-16 12:53:51 -07:00
github-actions[bot]
7955ef2450 chore: update package versions 2026-06-16 19:32:53 +00:00
Konstantin Wohlwend
c1e8d412fc Clearer local dev environment 2026-06-16 12:26:32 -07:00
github-actions[bot]
13e901f1bd chore: update package versions 2026-06-16 18:55:24 +00:00
Konstantin Wohlwend
fbb84b9e62 Update reminders to tell AI to prefer /ask endpoint 2026-06-16 11:41:56 -07:00
BilalG1
b270c0f2ef Fix env-rename gaps from PR review: prod-build conflict, dual-read holes
Addresses correctness/coverage issues found reviewing the STACK_*->HEXCLAVE_*
rename, including a confirmed production-breaking dashboard build failure.

- dashboard/.env: empty out non-empty committed NEXT_PUBLIC_HEXCLAVE_* values
  (ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS, HEAD_TAGS) that collided with the
  platform-set legacy NEXT_PUBLIC_STACK_* values at build time and threw in the
  inline conflict check; move the local-dev default to .env.development.
- backend polyfill: expand the ${PORT_PREFIX} sentinel for HEXCLAVE_/
  NEXT_PUBLIC_HEXCLAVE_ keys too (renamed DB/Svix/S3 URLs were being skipped).
- codegen-prisma: set only HEXCLAVE_DATABASE_CONNECTION_STRING (prefer existing
  HEXCLAVE/STACK, else placeholder) so it never diverges from a real STACK value
  and trips prisma.config.ts's conflict check.
- backend DB tests: centralize a dual-read resolveTestDatabaseConnectionString()
  and use it in bulldozer/payments suites (were legacy-STACK_-only).
- dashboard next.config: dual-read NEXT_PUBLIC_HEXCLAVE_IS_PREVIEW for the
  X-Frame-Options gate.
- RDE manager: inject canonical HEXCLAVE_* names alongside legacy STACK_* ones.
- vite examples: restore VITE_HEXCLAVE_* || VITE_STACK_* fallback.
- cli auth: dual-read HEXCLAVE_API_URL / HEXCLAVE_DASHBOARD_URL.
- shared env: make getEnvVarWithHexclaveFallback two-way so canonical callers
  also fall back to the legacy name; add tests.
- convex example: replace non-null assertion with ?? throwErr(...).
2026-06-16 11:39:46 -07:00
BilalG1
59547ef4ec
Detect conflicting Hexclave and Stack env vars (#1604)
Summary: Detects conflicting non-empty HEXCLAVE_* and STACK_* values
across shared env helpers, dashboard public envs, generated SDK env
access, Docker scripts, CLI/docs/examples, and related tests.
Verification: pnpm test run packages/shared/src/utils/env.test.tsx
apps/dashboard/src/lib/env.test.tsx packages/cli/src/lib/auth.test.ts;
targeted lint/typecheck across touched workspaces; bash -n/node --check
for changed scripts; node
docker/local-emulator/generate-env-development.mjs --check.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Detects and blocks conflicting `HEXCLAVE_*` and `STACK_*` env vars
across the monorepo. Prefers `HEXCLAVE_*`, falls back to `STACK_*` when
empty, and fails fast when both are set to different values.

- **New Features**
- Added conflict-aware env resolvers used across apps, CLI, docs,
examples, and Docker (build/runtime).
- Validates critical vars (e.g., database connection, API/dashboard
URLs, emulator flags, tokens) and ignores post-build sentinel values.
- Prisma, Next.js, and Docker startup now error on mismatched values;
CLI enforces project ID/key conflicts; tests added.

- **Migration**
- If both names are set with different values, builds/tests/scripts will
error. Set only `HEXCLAVE_*` or make both equal.
- Update `.env`, CI secrets, and Docker envs to use `HEXCLAVE_*`. Keep
`STACK_*` only as a temporary fallback.

<sup>Written for commit 4d63fa3bad.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1604?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-16 10:57:59 -07:00
Konsti Wohlwend
7b824526fd
fix: silently disable EventTracker and SessionRecorder when analytics app is not enabled (#1599) 2026-06-16 10:42:57 -07:00
Konstantin Wohlwend
689b05fdaa Make it clear there are more SDK packages 2026-06-16 10:37:58 -07:00
Armaan Jain
c7ef9e9461
Dashboard Bar chart UI fix (#1602)
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
DB migration compat / Check if migrations changed (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests (Local Emulator) / E2E Tests (Local Emulator, Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Runs E2E Fallback Tests / E2E Fallback Tests (Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Lint & build / lint_and_build (24) (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / No migration changes (skipped) (push) Has been cancelled
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/hexclave/blob/dev/CONTRIBUTING.md

-->


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the page views bar hover highlight in the analytics chart by
replacing the clip-path overlay with per-bar `Cell` opacity. This
removes flicker and highlights only the hovered bar.

- **Bug Fixes**
  - Removed `page-views-highlight-clip` and the extra hover `Bar`.
- Use `Cell` per bar to set `fillOpacity` (0.5 on hover, 0.18 otherwise;
0 when hidden).
- Keeps a single `Bar`, reducing DOM and avoiding clipping/offset
issues.

<sup>Written for commit f3e659bb50.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1602?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Improved the rendering mechanism for analytics chart interactions in
the dashboard.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-15 19:37:01 -07:00
Armaan Jain
cf6a49d89c
Dashboard sidebar animation fix (#1601)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/hexclave/blob/dev/CONTRIBUTING.md

-->


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the project sidebar animation flicker by always applying
overflow-hidden to the animated container and only toggling h-0 when
collapsed. Expanding and collapsing sections now animate smoothly
without content popping.

<sup>Written for commit 7af633b1e7.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1601?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved the visual clipping behavior of nested sidebar items during
expand/collapse transitions for smoother animations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-15 18:36:16 -07:00
Armaan Jain
f97d3f5af9
Devtool tab transition fix (#1600)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/hexclave/blob/dev/CONTRIBUTING.md

-->


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes devtool tab switching so hidden panes don’t intercept clicks and
active panes render without flicker.

- **Bug Fixes**
- Replace visibility/animation with display: none/block, plus opacity
and z-index, so only the active pane is interactive.
- Add pane background and remove fade-in animation to prevent overlap
and iframe flicker.

<sup>Written for commit ec80835045.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1600?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
* Refined dev tool tab pane display behavior for improved visual
rendering and interaction handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-15 18:35:56 -07:00
Konstantin Wohlwend
2eabf33612 Don't disable analytics in the setup step 2026-06-15 18:16:47 -07:00
Konstantin Wohlwend
ef27c98492 Fix Apple OAuth behavior 2026-06-15 17:59:17 -07:00
github-actions[bot]
eabbc05a49 chore: update package versions
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests (Local Emulator) / E2E Tests (Local Emulator, Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Runs E2E Fallback Tests / E2E Fallback Tests (Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Lint & build / lint_and_build (24) (push) Has been cancelled
Publish npm packages / publish (push) Has been cancelled
Publish Swift SDK to prerelease repo / publish (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
2026-06-15 23:49:50 +00:00
Mantra
ed02186f62
Fix/npm-pkg-shared-backend (#1598)
<!--

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 description by cubic. -->
---
## Summary by cubic
Prepares `@hexclave/shared-backend` for npm publishing with a proper
build, dual ESM/CJS exports, and bundled types. Also simplifies an
import parsing helper for safer matching.

- New Features
- Configure build with `tsdown`; output CJS/ESM and `.d.ts` to `dist/`
and `dist/esm/`.
- Add export map for `.` and `./config-agent` with `require` and
`default` entries plus types.
- Update publish settings: set `main`/`types` to built files, include
only `dist`, exclude tests, and add `build`, `dev`, `clean` scripts.
  - Add repository field and `tsdown.config.ts`.

- Bug Fixes
- Simplified import specifier parsing in `src/index.ts` to push matches
directly and remove unnecessary error throwing.

<sup>Written for commit 9f18bc019a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1598?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-15 16:32:09 -07:00
Konstantin Wohlwend
f04a396650 Use Hexclave whenever possible 2026-06-15 16:31:56 -07:00
Konstantin Wohlwend
eeccf877e5 Use Hexclave whenever possible 2026-06-15 16:31:41 -07:00
github-actions[bot]
47b9a3a431 chore: update package versions 2026-06-15 22:30:42 +00:00
Konsti Wohlwend
5be2160021
fix: clearer error when changing email to one already used for auth (#1569) 2026-06-15 13:55:26 -07:00
Konsti Wohlwend
72456d3748
Update Next.js to latest minor/patch versions (#1592) 2026-06-15 13:45:43 -07:00
github-actions[bot]
e07c509f81 chore: update package versions 2026-06-15 19:57:58 +00:00
Konsti Wohlwend
f5c078c46d
Generate custom llms.txt for docs-mintlify (#1593) 2026-06-15 12:33:27 -07:00
Mantra
e93b7520c4
feat(analytics): add route analytics heatmaps (#1520)
## Summary

Adds route analytics heatmaps, stacked on top of
`codex/analytics-overview-filters` (#1496).

- Heatmap API routes (`/analytics/heatmap`, internal heatmap +
heatmap-token endpoints)
- Signed heatmap token signing/verification lib + tests
- Dashboard heatmaps page (client + route)
- Dev-tool + event-tracker support for heatmap capture
- ClickHouse migration support

## Demo


https://app.devin.ai/attachments/49cd6a96-8962-46d9-b8fb-145746cc6dee/rec-c80ec66f-21a3-49fb-bfae-19195ce7b930-edited.mp4

## Notes
Base branch is `codex/analytics-overview-filters` so the diff shows only
the heatmap changes. Will retarget to `dev` once the base PR lands.

Link to Devin session:
https://app.devin.ai/sessions/16f8adac29b948b38280c85418617fea
Requested by: @mantrakp04

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added clickmap overlay to analytics dashboard, enabling visual click
heatmap analysis on live websites.
* Enhanced analytics metrics with hourly breakdowns, bounce rates, and
top regions/browsers/devices filtering.

* **Bug Fixes**
  * Improved click event tracking accuracy and dead-click detection.
  * Fixed overlay z-index stacking for better visibility.

* **Style**
* Updated dashboard card padding and navigation button styling for
consistency.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: mantra <mantra@stack-auth.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 12:06:16 -07:00
Mantra
f38c9d85e7
Replace writeConfigObject with AI-aware updateConfigObject (#1537)
## Summary

Replaces `writeConfigObject` (destructive overwrite) with
`updateConfigObject` — an async, AI-aware updater that preserves
user-authored config structure (imports, external file references,
helpers).

**Dual-path approach:**
- **Fast path** (deterministic, no AI): plain static literal configs →
`override()` + in-memory validation + atomic write
- **Agent path** (custom structure): configs with `import x from
"./file.txt" with { type: "text" }` etc. → Claude agent edits the
external files in place, then validates

**Safety guarantees:**
- Snapshot/restore: config + all relative imports are captured before
the agent runs; rolled back on any failure
- In-memory validation on fast path (never write unvalidated bytes)
- Semantic check when config is evaluable; no-op detection + structural
check when it isn't
- Path traversal guard on imports (rejects `../` escapes)
- Agent isolation: `settingSources: []`, `strictMcpConfig: true`,
`CLAUDE_CODE_DISABLE_AUTO_MEMORY`, no Bash tool
- `scheduleSync` only fires after a successful update
- Bounded 120s timeout on agent runs (configurable via env var)

CI failures are preexisting on `dev`
(`ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` from overrides move without
lockfile regen); this branch has zero lockfile changes vs dev.

Link to Devin session:
https://app.devin.ai/sessions/cc7409a357bc472ea19fbed065f1229f
Requested by: @mantrakp04

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Introduced partial configuration update functionality with validation
and automatic rollback on failures.
* Enhanced configuration management with support for more complex file
structures and external references.

* **Chores**
* Added Claude Agent SDK dependency for configuration update operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

## Documentation

Docs for this feature were added in this branch:

- **New page**
`docs-mintlify/guides/going-further/local-development.mdx` — covers
`stack dev`, the development-environment flow, and how dashboard edits
are written back to the local config file (structure-preserving fast
path vs. assistant path, external `import … with { type: "text" }`
templates, validation + rollback). Added to `docs.json` nav; also fixes
the previously-broken `/guides/going-further/local-development` links
from `index.mdx` and `self-host.mdx`.
- **`docs-mintlify/guides/going-further/cli.mdx`** — added a `stack dev`
("Run a development environment") section.
- **Skill-site AI prompts** — filled in the `config-docs` and
`dashboard-instructions` placeholders under
`packages/stack-shared/src/ai/unified-prompts/skill-site-prompt-parts/`,
and added a structure-preserving note to the setup prompt.
- **`CHANGELOG.md`** — user-facing entry.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: mantra <mantra@stack-auth.com>
2026-06-15 12:00:24 -07:00
Armaan Jain
3c89bb8c19
Hosted components redesigned (#1573)
## Summary

Redesigns the hosted components app (`apps/hosted-components`) with a
new Tailwind-based UI: rebuilt auth pages (sign-in, sign-up, magic link,
forgot/reset password, MFA, email verification, team invitation, CLI
auth confirm) and a full hosted Account Settings suite (profile, emails
&amp; auth, notifications, active sessions, API keys, payments, teams),
with dark mode support.

Also fixes found along the way: form error clearing in
forgot-password/password-reset, `runAsynchronouslyWithAlert` for the
notifications switch, a `CopyButton` DOM prop leak, a bogus
mobile-session icon check, and imports the app stylesheet in the root
route so the app's Tailwind styles actually apply.

## Before / after screenshots

Captured on the local dev setup (`internal` project). Onboarding is not
shown since it redirects without standalone UI in this setup.

<details>
<summary><b>Sign in</b></summary>

| | Before | After |
|---|---|---|
| Light | ![sign-in before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2VmMDljMzE3LTIzN2QtNGYzOC05ZDczLWI5ZmRiMGVmMWZjOSIsImlhdCI6MTc4MTEzNzkxMCwiZXhwIjoxNzgxNzQyNzEwLCJmaWxlbmFtZSI6InNpZ24taW4tYmVmb3JlLWxpZ2h0LnBuZyJ9.IMnk1DN0rLl_iW2Fgy99rVMeazQeii-DUTM0bXQsNfo)
| ![sign-in after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2FjZDQ4OTJlLTFkM2YtNGM1Ni1iMmYxLTZjNTAwMDBkNzAwYSIsImlhdCI6MTc4MTEzNzkxMCwiZXhwIjoxNzgxNzQyNzEwLCJmaWxlbmFtZSI6InNpZ24taW4tYWZ0ZXItbGlnaHQucG5nIn0.KdtHe6KxQQ3aY-J5Q2tTCDaUQIsJg1WI0J-Knp1zKMg)
|
| Dark | ![sign-in before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzZkNTFkY2E5LTUzNTAtNDExMC04ZjYzLTNlZDA3MjUyMTJiMCIsImlhdCI6MTc4MTEzNzkxMCwiZXhwIjoxNzgxNzQyNzEwLCJmaWxlbmFtZSI6InNpZ24taW4tYmVmb3JlLWRhcmsucG5nIn0.SLd1PJv0lj__533lN6YUElnAO5vtKeyokwv4EbngQHw)
| ![sign-in after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2E2ODkyZTUzLTU1YmEtNGRkNi1iYzQ4LTgzMmI0YzVmZDk2MyIsImlhdCI6MTc4MTEzNzkxMCwiZXhwIjoxNzgxNzQyNzEwLCJmaWxlbmFtZSI6InNpZ24taW4tYWZ0ZXItZGFyay5wbmcifQ.7MA8WAeZI6pgErTZ52wvkNvRBMhJUKf0SFoIenWLSLk)
|

</details>

<details>
<summary><b>Sign up</b></summary>

| | Before | After |
|---|---|---|
| Light | ![sign-up before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzlhMGU4YTYwLWNkNDAtNDAwZi1hNjAxLTZlOTBhMzc4ODAzNyIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InNpZ24tdXAtYmVmb3JlLWxpZ2h0LnBuZyJ9._LcowDPO6d2FrWOBIAtSMha2QnoyV1pAp6O58ufrJ_M)
| ![sign-up after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzgzNjMyZmZkLTg5ZWUtNDU2Yy05YjMzLWZjYTc3NThhZDM3MSIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InNpZ24tdXAtYWZ0ZXItbGlnaHQucG5nIn0.Tpa1eJ_I09lRhEfG1-kbZIGHenGKTo6vomTKsbjSRwg)
|
| Dark | ![sign-up before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzkyYzc3ODYzLWNmOTItNDNiZC1hZjNkLWE5ZDYyYzMyYTAxYiIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InNpZ24tdXAtYmVmb3JlLWRhcmsucG5nIn0.QYYKXyNHQr83EFIHcttgweFWrPe_9BeEuNtlnJLlgYU)
| ![sign-up after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2UyY2U3ZTI5LTRlOGQtNGI0Mi1iYjI2LTllNDU2MjA3NGU2ZCIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InNpZ24tdXAtYWZ0ZXItZGFyay5wbmcifQ.rO5HQURSI1MWI5gDYqQj40gNR4UXCajbzw3K8ns6S6o)
|

</details>

<details>
<summary><b>Forgot password</b></summary>

| | Before | After |
|---|---|---|
| Light | ![forgot-password before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzdkZmM5MjkwLWU1MDgtNGMyOS04MWRlLTRiY2RiMTY2M2EyYiIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6ImZvcmdvdC1wYXNzd29yZC1iZWZvcmUtbGlnaHQucG5nIn0.DYyid0bzNTRW6RTdXJlP9Wfxuc_cR9BTlC0iFK5aitA)
| ![forgot-password after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzQyYTQzZWMxLTVhYWMtNDQ5ZS04YzgyLWE2M2UwYjk4MjVhYSIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6ImZvcmdvdC1wYXNzd29yZC1hZnRlci1saWdodC5wbmcifQ.ZwFKelHXn-8wq_uY5nrpIg811b_plgXgA0BdBJifUSs)
|
| Dark | ![forgot-password before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzU5MDY3ZDkzLWJjMjEtNDZhYy1hZDkzLTNjYzQyNGFhMDI2MiIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6ImZvcmdvdC1wYXNzd29yZC1iZWZvcmUtZGFyay5wbmcifQ.lOHX4XqjhCExM7dL86O4BngKiSXYNaAvC0LH-AXHhlg)
| ![forgot-password after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzkxYTBkODk5LTk2OWUtNGU2Ni04ODE1LWU4NDA1ODhlYmQzNyIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6ImZvcmdvdC1wYXNzd29yZC1hZnRlci1kYXJrLnBuZyJ9.hvhoTYUq_cx3y9BrI03kyqA28MkXE46mv-hxSpeDuOg)
|

</details>

<details>
<summary><b>Password reset</b></summary>

| | Before | After |
|---|---|---|
| Light | ![password-reset before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2Q1MDk3ZGUzLTM5MGItNDMwNS1hM2YzLTgzMDU2Yzg4NDNlZiIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InBhc3N3b3JkLXJlc2V0LWJlZm9yZS1saWdodC5wbmcifQ.PX_M155ZtvVqq7lVyL7LidY1GAoZkOd-6u508R0xvqU)
| ![password-reset after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzZhOWU5YTE2LTFlODEtNDRjZC1hNDY5LTc3NTg4ZGM0MDlmNCIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InBhc3N3b3JkLXJlc2V0LWFmdGVyLWxpZ2h0LnBuZyJ9.Pg7t4tmTGIs5sZLnR69460qpaAajpfUnp7IyrxYS7TI)
|
| Dark | ![password-reset before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzFiODMwYjQwLTZkMjEtNDdkYy1iNmIzLWE4YmU5MmE5NmYxMyIsImlhdCI6MTc4MTEzNzkxMSwiZXhwIjoxNzgxNzQyNzExLCJmaWxlbmFtZSI6InBhc3N3b3JkLXJlc2V0LWJlZm9yZS1kYXJrLnBuZyJ9.DHpL8T-8OCF3UY9GObvqXPIqtShwSftgtjopKGzulww)
| ![password-reset after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzU4MTI3Y2ZkLTc3MGYtNGQzNS1hZTQ0LTEwMWVkYWVjNjM2NyIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6InBhc3N3b3JkLXJlc2V0LWFmdGVyLWRhcmsucG5nIn0.USTT-ErYoVs_ua7y6i6YyvMZD3r-WI3Ag1OPxXfijHM)
|

</details>

<details>
<summary><b>Email verification</b></summary>

| | Before | After |
|---|---|---|
| Light | ![email-verification before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzczMDlhNDM0LTZjZDItNGI0OS1hYTQ5LTM4NmY1YWZjZDMxOCIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6ImVtYWlsLXZlcmlmaWNhdGlvbi1iZWZvcmUtbGlnaHQucG5nIn0.kcRSuETM4LLSH0RWJWbXmA8_5tFstGTcIZqwudyWvQs)
| ![email-verification after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzhkMTdlMjNjLTkzNTItNGJiOS1iODMxLWM2ZDhmMzUxNDMwMiIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6ImVtYWlsLXZlcmlmaWNhdGlvbi1hZnRlci1saWdodC5wbmcifQ.WeUG_VTG4P2fsMNwXPrXn1VdNCAJfA-kM92mix2F8M0)
|
| Dark | ![email-verification before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2M2YWQzODAzLTgzMTUtNGE0NS05MzAxLWI2N2JkYzAwMmQ1NSIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6ImVtYWlsLXZlcmlmaWNhdGlvbi1iZWZvcmUtZGFyay5wbmcifQ.Xouj4wlz7IvNPPSb-c6owaC0orbtDG3N4lOe0899qZI)
| ![email-verification after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzI3OTIzYWM0LTMxMDAtNDEzYi05OTNkLWZmN2IwMGI5ZDliYyIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6ImVtYWlsLXZlcmlmaWNhdGlvbi1hZnRlci1kYXJrLnBuZyJ9.c9B6VWiHpZ2odb13_td4jc6lnXXvsjx9J3e4dqIwtkI)
|

</details>

<details>
<summary><b>MFA</b></summary>

| | Before | After |
|---|---|---|
| Light | ![mfa before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzIxY2Q2NjUzLTgwM2EtNDJmMi1hN2M3LWIyOGEwYWU4NTY2YyIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6Im1mYS1iZWZvcmUtbGlnaHQucG5nIn0.5IumrPBua_uTQq5gtUozGDkxuEM1dHjPV9mBUoWYKaM)
| ![mfa after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2Y4NWJkMzc1LWQ5NjEtNDBjOS04NzZmLTNlZmUxMWQ5YjdiOSIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6Im1mYS1hZnRlci1saWdodC5wbmcifQ.2yPq0cX2FkFgwAWm7iJ7PragpDSCEIITLcHceTKCriY)
|
| Dark | ![mfa before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2M4NmJmMTI1LWNhNzMtNDEwNi1hOGY2LTVjOTY3OTViZDUwNyIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6Im1mYS1iZWZvcmUtZGFyay5wbmcifQ.nmbD5lOLRjf-G4cnxByrwpymVNVGEIlVpYkbvSz9nB0)
| ![mfa after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzA3MzMwNzIwLTI3YmUtNGRlNy1hMDA1LWJiOGY1NzI3NmY2NSIsImlhdCI6MTc4MTEzNzkxMiwiZXhwIjoxNzgxNzQyNzEyLCJmaWxlbmFtZSI6Im1mYS1hZnRlci1kYXJrLnBuZyJ9.zcxkCgWPnOqqv0v17JqF0eFlkpBMu_skiAq9cQAJNXY)
|

</details>

<details>
<summary><b>Error</b></summary>

| | Before | After |
|---|---|---|
| Light | ![error before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzAyY2Q5MWUzLWI0YzktNDRmNi1iOWE0LTY4ZmIyMjZhOGYyYSIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImVycm9yLWJlZm9yZS1saWdodC5wbmcifQ.qVgMnd8c_VI82JIH9jVednhDKiVNlxv_K60eCb9UbTA)
| ![error after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzk0MzBlN2U0LWY1YjUtNDA5Ni1iZDRlLWM1YzQ3YTgwZDRjZiIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImVycm9yLWFmdGVyLWxpZ2h0LnBuZyJ9.612VxQuYtoittB4t-GJ8SkNaNDu5CqKierhWoJ5uA-o)
|
| Dark | ![error before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzBkZDBhYzdkLTc3NzItNDkwNS04MmEwLWUwMmZkYzMzOTg1MyIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImVycm9yLWJlZm9yZS1kYXJrLnBuZyJ9.UaM45CkfbiEpCZWHCt3IbgAoN_QcK6tBgPnAH85vb4k)
| ![error after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2U5NWMxYzZlLWRkNTUtNDBjMS1hYWMyLTE5MTRmYzdhZDRmZSIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImVycm9yLWFmdGVyLWRhcmsucG5nIn0.r3qiOPZKyNgpnDQJMPc6exaxzQnKm8wH3Jg5WcQTRCQ)
|

</details>

<details>
<summary><b>Team invitation</b></summary>

| | Before | After |
|---|---|---|
| Light | ![team-invitation before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2RkYmQ0YzMzLWFkYTctNGVlOS1iZWI5LTYyYWUxMWNlZDA5MSIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6InRlYW0taW52aXRhdGlvbi1iZWZvcmUtbGlnaHQucG5nIn0.KdNBx7LdUFquws4L8YE5bVsrtNh06hDLPcFqOVz7CD4)
| ![team-invitation after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzg2N2EwZmE2LWM4YzEtNDhkZi1iMTEwLTBmOGZiZDhiMjdiNyIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6InRlYW0taW52aXRhdGlvbi1hZnRlci1saWdodC5wbmcifQ.HLbHcxwjxObirriFXwTtY6jTiMNhKC6s-IafsG2irHA)
|
| Dark | ![team-invitation before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzNiZTAwMTZiLWIwZmQtNGRhMS05NmY1LTliMzIzY2IyNzdkNiIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6InRlYW0taW52aXRhdGlvbi1iZWZvcmUtZGFyay5wbmcifQ.W3Bout2l1fTdbBRKp_ztfUindfR2cZEJ0UTP5kmFPBg)
| ![team-invitation after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzhiZTJjODc4LTg0YzMtNDNjYy05OWRhLTI3ZmVkYmQwNWIzOCIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6InRlYW0taW52aXRhdGlvbi1hZnRlci1kYXJrLnBuZyJ9.m6G5vmWLFAh_yClcbg768rSiMZGkIyov8gHnNVLU95A)
|

</details>

<details>
<summary><b>CLI auth confirm</b></summary>

| | Before | After |
|---|---|---|
| Light | ![cli-auth-confirm before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzY4ZDA2YzdjLWFkN2ItNDE2ZS05N2E1LTZiZDI2ZDFmYmY1ZSIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImNsaS1hdXRoLWNvbmZpcm0tYmVmb3JlLWxpZ2h0LnBuZyJ9.0kGQpHc8RZc53_wKC8jJIhuXztp_4keASpMR24HtcK0)
| ![cli-auth-confirm after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzY4ZGU1M2VjLWU3YzItNDY5My1iZjgzLTM0OWVlYjZjY2M0ZiIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImNsaS1hdXRoLWNvbmZpcm0tYWZ0ZXItbGlnaHQucG5nIn0.sHm69r1KOP72z8wdKVzo38QTPp1GUIAUXVtac8IL-zM)
|
| Dark | ![cli-auth-confirm before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzVlMzVhNTQ0LTUxYjItNDFiYy1iYWNhLTA4YjcyMWQ2NzhkYSIsImlhdCI6MTc4MTEzNzkxMywiZXhwIjoxNzgxNzQyNzEzLCJmaWxlbmFtZSI6ImNsaS1hdXRoLWNvbmZpcm0tYmVmb3JlLWRhcmsucG5nIn0.MxJtvrhplMERLWTmm0KklvROBLjH90CB6FsVyQsB8ak)
| ![cli-auth-confirm after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2IxZDQxZjI3LWM0YmQtNGM5OC05OTU1LTkxOGMzNTJiN2NjMiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImNsaS1hdXRoLWNvbmZpcm0tYWZ0ZXItZGFyay5wbmcifQ.cyjPDer_-G8i_uQWSD4ESYEZmk32VfAF73zuUf-KHPw)
|

</details>

<details>
<summary><b>Account settings — Profile</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-profile before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2Q5ZTQzZjZlLWIwZGMtNDE3Yi04Njc3LWFiMzVhYjE5Mjg4MiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcHJvZmlsZS1iZWZvcmUtbGlnaHQucG5nIn0.lmgOIaj7IllT7txfIpzMKEo_iz1DLp00a_odsn9IW1s)
| ![account-settings-profile after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzM0YWEzNzI4LWU4MDMtNDA4Ny04NDliLTg5NWQxZjdlZWQzMiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcHJvZmlsZS1hZnRlci1saWdodC5wbmcifQ.512uIE8QjTWDlyrbvOqOw2QPV01_VyHUXxcdbdmr5CI)
|
| Dark | ![account-settings-profile before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzQyMzhjYmZmLWZlZTMtNDkwYS05NjE3LTdiYzU2MDY3ZDliYiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcHJvZmlsZS1iZWZvcmUtZGFyay5wbmcifQ.NWNH23YBwn67auhDQJNbR1jvP5BiW_QKWH0X-9ZB1wQ)
| ![account-settings-profile after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzhlODgxNDYzLWNmMDgtNDA1Ny04ZThkLTdhMjQ0NTkxYzQwZSIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcHJvZmlsZS1hZnRlci1kYXJrLnBuZyJ9.2Nfs2UXmq4pgFhULizgIHxYuISFtkb24KKGr2hveTkM)
|

</details>

<details>
<summary><b>Account settings — Notifications</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-notifications before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzIzZDk2NDQ4LTcwZWMtNDM5Ni1iNmNiLWEyZjI4MzU5Mjc2ZCIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtbm90aWZpY2F0aW9ucy1iZWZvcmUtbGlnaHQucG5nIn0.2um6D6uKDsgOp8javP5PcyRdbLewxyb2vGk_qc2zeho)
| ![account-settings-notifications after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzBlYjI0YTE4LTMzZGUtNDcxNC04NGQ5LTI2ODYwZjE0YWQ3NiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtbm90aWZpY2F0aW9ucy1hZnRlci1saWdodC5wbmcifQ.iIZM0PdMO_gavcUrYORGhnZ_oqjvoE1KHCnJwBGMAJQ)
|
| Dark | ![account-settings-notifications before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2Q2OGFjZmE3LTU5MTAtNDViNi1hOWQ1LTQ2MzU2YjUyNmFkMiIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtbm90aWZpY2F0aW9ucy1iZWZvcmUtZGFyay5wbmcifQ.L1VCD8J7ySFj6n_OOAZFh8gCXBWuF5j7OLWvyfGqvOc)
| ![account-settings-notifications after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2VkYmQ1NDg0LTQzMGUtNDU2Ni1hNzJhLWE0YzlhNWIyOTM2YyIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtbm90aWZpY2F0aW9ucy1hZnRlci1kYXJrLnBuZyJ9.JvPKISE9uWzn18CEEzOatR2Xp8CMOD4x978wFfT4ixA)
|

</details>

<details>
<summary><b>Account settings — Active sessions</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-sessions before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2NhNDQ5NjU1LWYyZDQtNGQ3Ny05YzBjLTI0MmM5ZTQ5MzdiOCIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtc2Vzc2lvbnMtYmVmb3JlLWxpZ2h0LnBuZyJ9.A62xUZfvNQ-yCVUBvITnbPB19cUl9FsVHngITE2XfTI)
| ![account-settings-sessions after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzI5YzlkY2JjLWQzM2EtNGViMC04NGUzLTY1ODIyMjQ2OGM1OCIsImlhdCI6MTc4MTEzNzkxNCwiZXhwIjoxNzgxNzQyNzE0LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtc2Vzc2lvbnMtYWZ0ZXItbGlnaHQucG5nIn0.JzIuAIuXxAOy4UWoaELGSkkwKx1MeUxeEBYWS1hLzeo)
|
| Dark | ![account-settings-sessions before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2IwNzkyNzcyLThmOGQtNDVhNi1iNTU3LTc0NjZlN2RhMDliMiIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtc2Vzc2lvbnMtYmVmb3JlLWRhcmsucG5nIn0.TAFHH_d2vZzZouOAn8HQY_UpEHnaCNaCtDWWNGGzBZk)
| ![account-settings-sessions after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2I5MDNkZjU2LWE5NzYtNGRmZS1hMDZhLWM0ODJlNTBhODMyMyIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3Mtc2Vzc2lvbnMtYWZ0ZXItZGFyay5wbmcifQ.BS4vn6FHt0ILUGzzHkoenSg-ITTOdlCbiPI-k7wCpW0)
|

</details>

<details>
<summary><b>Account settings — API keys</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-api-keys before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzY0MDQ2YjExLWEwNzYtNDFjYi1hYzE3LTU2NjI0MDZhYzFjNyIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtYXBpLWtleXMtYmVmb3JlLWxpZ2h0LnBuZyJ9.gIiXz5bL0rVTFi8m4xjBwqDrXGdep6eTAtrBl8-Vk3s)
| ![account-settings-api-keys after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzFmODUyMTEwLWM2YWQtNGVkOS04YWQ0LTAxOTVjNWMzOTkzYSIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtYXBpLWtleXMtYWZ0ZXItbGlnaHQucG5nIn0.9MQw8j0RH0nEvjWrCV478fIMeNnqhCKQr7yuUEx9HUM)
|
| Dark | ![account-settings-api-keys before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzIwNTA5ZWUzLTBjOTktNGUwNi1iODI0LTU4MjYwODA1NmJlOCIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtYXBpLWtleXMtYmVmb3JlLWRhcmsucG5nIn0.vQDdStoNd5qcCyW4jrqN5DrWjDmakmy1AG_7yjEhTVs)
| ![account-settings-api-keys after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzAxNDZiNWM2LWMwMDEtNDFiMy1hNDRiLTAzNmQ4OWJkMGE3MSIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtYXBpLWtleXMtYWZ0ZXItZGFyay5wbmcifQ.fET1gYmJX8TE_LAgEW_3mPgFMPQEf0gd3lm_SbN3CIQ)
|

</details>

<details>
<summary><b>Account settings — Payments</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-payments before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzg5MDc3NWI3LTVjMzItNDBjNS04NDIyLTExOTVmMTdhNTVmMCIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcGF5bWVudHMtYmVmb3JlLWxpZ2h0LnBuZyJ9.1EHLx9Y5eE30pX5s95qrHI63eBEqwAM_imJIvVuSkJs)
| ![account-settings-payments after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzc5YjEyYjkyLWEyZWUtNGIzMC1hYjRmLTEzZjk1N2FlZWI3ZSIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcGF5bWVudHMtYWZ0ZXItbGlnaHQucG5nIn0.TRjKFdwfArHf5NSYH8OkKydxKWQKPcy-DbLmx641IxM)
|
| Dark | ![account-settings-payments before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzU0MjY1ZGI3LTJjOWYtNDZiNi05MzY2LTE2OWRjZTk5YjM2OSIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcGF5bWVudHMtYmVmb3JlLWRhcmsucG5nIn0.E4qAaoYQ1_VM18WdRR0SndS1rNAy8Y_iiwZpG6XFmEA)
| ![account-settings-payments after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2E3NDUxYmQ4LTFhM2QtNDhjZC04MTdkLTEwYTc0ODNlYjdiZSIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtcGF5bWVudHMtYWZ0ZXItZGFyay5wbmcifQ.dSBbdK2uNNdQ3ZWm6wmF8B6vIldQ7C-BwuzyVkPbiTo)
|

</details>

<details>
<summary><b>Account settings — Emails &amp; auth</b></summary>

| | Before | After |
|---|---|---|
| Light | ![account-settings-email-auth before
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2M1MTNkZTFkLTY1Y2ItNGJlNi04MWEyLWZiZTJhNDk4MTllNCIsImlhdCI6MTc4MTEzNzkxNSwiZXhwIjoxNzgxNzQyNzE1LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtZW1haWwtYXV0aC1iZWZvcmUtbGlnaHQucG5nIn0.lWxhJCuN0cwTBMnbM1by6-iZoBVHlOi4Pnv4NTCJ67c)
| ![account-settings-email-auth after
light](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQL2I0NzBlOTY3LWY5NTUtNDRkMy1iZDY3LWU1ZDJiZWNkYmQ2MCIsImlhdCI6MTc4MTEzNzkxNiwiZXhwIjoxNzgxNzQyNzE2LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtZW1haWwtYXV0aC1hZnRlci1saWdodC5wbmcifQ.AH2FqUJJRBCFx5a08IkvNzScleqRd_ftlFFjbp_F3no)
|
| Dark | ![account-settings-email-auth before
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzYwYjQ2MmFlLTkzMDItNGQ2MC1iZmNkLWVhNThlN2I2OWI5ZiIsImlhdCI6MTc4MTEzNzkxNiwiZXhwIjoxNzgxNzQyNzE2LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtZW1haWwtYXV0aC1iZWZvcmUtZGFyay5wbmcifQ.PC9ll_6mOHvmd8aAlfL2IfgNBRGOL5K8QuyJoo7NpTs)
| ![account-settings-email-auth after
dark](https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmdfaGwzT2d1STVWMXBYcTUwUCIsInVzZXJfaWQiOm51bGwsImJ1Y2tldF9uYW1lIjoiZGV2aW5hdHRhY2htZW50cyIsImJ1Y2tldF9rZXkiOiJhdHRhY2htZW50c19wcml2YXRlL29yZ19obDNPZ3VJNVYxcFhxNTBQLzQxMWUzY2M1LWViYWYtNGMzZi1hMDhkLTJlOTk0ZDdjMGU0ZCIsImlhdCI6MTc4MTEzNzkxNiwiZXhwIjoxNzgxNzQyNzE2LCJmaWxlbmFtZSI6ImFjY291bnQtc2V0dGluZ3MtZW1haWwtYXV0aC1hZnRlci1kYXJrLnBuZyJ9.OlTYac0GJEdImBtOMqFXHBG6_JQacZ9F5h3-GB7IKms)
|

</details>

Link to Devin session:
https://app.devin.ai/sessions/1d2380aa55694f2fb12ed96e200a32ad
Requested by: @Developing-Gamer

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: armaan <armaan@stack-auth.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-06-15 04:25:33 +05:30
github-actions[bot]
7063aa2df7 chore: update package versions 2026-06-13 01:26:27 +00:00
github-actions[bot]
6de253633f chore: update package versions 2026-06-13 00:25:03 +00:00
Armaan Jain
9b767cc35e
Implement loading state for purchase page and enhance styling (#1586)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/hexclave/blob/dev/CONTRIBUTING.md

-->

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a skeleton loading state for the purchase flow and scopes
background styles to stop the first-paint flash across purchase views.
Improves perceived performance and keeps light/dark backgrounds
consistent.

- **New Features**
- Added skeleton `loading.tsx` for `/purchase/[code]` with responsive
placeholders.

- **Bug Fixes**
- Scoped `body` background with `:has([data-hexclave-purchase-page])`
for light/dark, and disabled `body::before` to prevent flash.
- Applied `data-hexclave-purchase-page` to the purchase page (including
invalid-code state) and return page to activate the scoped styles.

<sup>Written for commit 280eab0a5f.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1586?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a full-screen loading screen with animated skeleton placeholders
for the purchase flow.

* **Style**
* Applied theme overrides for purchase pages in light and dark modes to
ensure consistent backgrounds.
* Updated purchase page container layout and added a data attribute hook
for targeted styling and layout consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-12 16:37:05 -07:00
github-actions[bot]
5eedb484e1 chore: update package versions 2026-06-12 21:09:46 +00:00
Konstantin Wohlwend
18dd48f3f7 Fix verification code handler revoke order 2026-06-12 13:29:25 -07:00
Aman Ganapathy
21c5198255
chore(cli-auth): publishable key no longer required for cli auth (#1590)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
CLI authentication no longer requires a publishable client key. Login
works with only a project ID; pass `publishable_client_key` only if the
project has `requirePublishableClientKey` enabled.

- **New Features**
- In `stack-auth-cli-template.py`, `publishable_client_key` is optional;
requests send `x-hexclave-project-id` and `x-hexclave-access-type:
client`, and include `x-hexclave-publishable-client-key` only when
provided.
- Updated docs and generated prompts to remove the key from examples and
explain when it’s needed.

- **Migration**
- No changes required; existing calls that pass `publishable_client_key`
still work.
- You can remove the argument from `prompt_cli_login(...)` unless your
project requires it.

<sup>Written for commit 1f0e66ee74.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1590?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-12 10:12:27 -07:00
BilalG1
9d3ee6a0d6
Merge branch 'dev' into rename-env-vars-hexclave 2026-06-11 17:41:08 -07:00
Bilal Godil
d86b36565a fix: address PR review comments
- turnstile-signup demo: flatten the env fallback chains to single || chains so
  an empty placeholder pair can't shadow the later candidates; reference the
  canonical var name in the error message.
- spacetime-publish: mention the canonical HEXCLAVE_MCP_LOG_TOKEN name in the
  prod-publish error message.
- internal-feedback-emails test: also exercise the legacy STACK_ fallback path
  (legacy-only and empty-canonical cases).
2026-06-11 17:38:47 -07:00
BilalG1
64eeedce9f
Fix dev CI: docker prune missing template + cross-domain test failures (#1582)
Unbreaks the test workflows that have been red on every dev push since
June 4. All root causes trace to direct pushes whose own CI runs already
failed (`8b78587da`, `c60016226`, `59daf1321`).

> Note: this PR originally also fixed the "Docker Server Build and Push"
workflow (missing `@hexclave/template` in the Dockerfiles' `turbo prune`
scope), but dev picked up the identical fix via 59daf1321 while this was
open, so the Dockerfile changes dropped out after merging dev back in.

## 1. E2E cross-domain spies — broken since `c60016226` (June 4)

`c60016226` renamed `_getCurrentRefreshTokenIdIfSignedIn` →
`_fetchCurrentRefreshTokenIdIfSignedIn` in the SDK and template unit
tests, but missed the eight `vi.spyOn` calls in
`apps/e2e/tests/js/cross-domain-auth.test.ts`. `vi.spyOn` throws on
missing properties → all 8 tests failed with
`_getCurrentRefreshTokenIdIfSignedIn does not exist`.

**Fix:** rename the spies.

## 2. signOut test timeout in all 5 SDK packages — broken since
`c60016226` (June 4)

The refresh-cookie test added in the same commit writes to a cookie
token store, which queues a background trusted-parent-domain lookup.
That lookup fetches the unreachable test `baseUrl` with retries while
holding `storeLock`'s read lock (via `AsyncStore.setAsync`), so the
later signOut test deadlocks on `storeLock.withWriteLock` inside
`_signOut` and hits the 5s vitest timeout (passes in isolation, fails
when the file runs in order).

**Fix:** stub `_getTrustedParentDomain` in the cookie test so the queued
task settles immediately.

## 3. "does not await pending auth resolutions" — premise broken by
`8b78587da` (June 4), masked by the spy rename

`8b78587da` added `nonHostedHandlerNames`, making `afterSignIn` resolve
to a local URL instead of the hosted domain. The test redirected to
`afterSignIn` from a callback page expecting the nested cross-domain
auth params path to run — but the redirect became same-origin, so
`_fetchCurrentRefreshTokenIdIfSignedIn` is (correctly) never called.
This was invisible until fix 1 above unmasked it.

**Fix:** redirect to `accountSettings` (still hosted, so still
cross-origin), preserving the test's intent: the session lookup during
nested-param construction must not await pending auth resolutions.

## 4. internal-metrics e2e snapshots — broken on dev by `59daf1321`

The analytics overview filters PR reshaped the metrics endpoint response
(added `bounce_rate`, daily/hourly breakdown arrays,
`top_browsers`/`devices`/`operating_systems`/`regions`; slimmed the
zero-filled daily fallback arrays) and updated the backend unit-test
snapshots, but left the e2e snapshots stale — its own dev run fails
these two tests identically.

**Fix:** update `__snapshots__/internal-metrics.test.ts.snap`,
reconstructed from the CI diff with every context line verified against
the old snapshot, and the new fields cross-checked against the route
change in 59daf1321.

## Verification

- `client-app-impl.cross-domain.test.ts`: 7/7 in `packages/template` and
the regenerated `packages/js` copy (signOut: 5s timeout → 10ms).
- `tests/js/cross-domain-auth.test.ts`: 18/18 locally (fully mocked, no
backend needed).
- Lint + typecheck pass for the touched packages.
- The metrics snapshot can only be fully confirmed by CI (needs the live
backend).

## Out of scope

"Run setup tests with custom base port" also intermittently fails
unrelated test files at exactly 60s under runner load (last green May
5), and the local-emulator run had one `payments/switch-plans` flake —
pre-existing flakiness not addressed here.
2026-06-11 17:37:11 -07:00
BilalG1
f4c13db079
fix(sdk): stop nested cross-domain auth from restarting the redirect chain on the hosted domain (#1581)
## What users see

Setting up a new project with hosted components, clicking **Sign in**
sometimes throws the browser into a redirect ping-pong between the app
and the hosted components site — anywhere from 5 to 9+ cross-domain
redirects — before the sign-in page finally renders. Reproduced live
against production:

![redirect loop
demo](https://gist.githubusercontent.com/BilalG1/888feed849ef0bc1f73c4609bfd71662/raw/redirect-loop.gif)

Captured redirect chain from that recording (one line per navigation, ~1
per second):

```
localhost:3000/                                      ← click "Sign in"
HOSTED  /handler/sign-in?...nested_refresh_token_id  ← start session handoff
localhost:3000/?redirect_uri=...&state=S1            ← bounce: "prove the session"
HOSTED  /handler/sign-in?...&code=...                ← code delivered... then RESTART ↩
localhost:3000/?redirect_uri=...&state=S2            ← bounce again (fresh state!)
HOSTED  /handler/sign-in?...&code=...                ← code delivered... RESTART ↩
localhost:3000/?redirect_uri=...&state=S3            ← again
HOSTED  /handler/sign-in?...&code=...                ← again
localhost:3000/?redirect_uri=...&state=S4            ← again
HOSTED  /handler/sign-in?...&code=...                ← exchange finally wins the race
HOSTED  /handler/sign-in (clean URL)                 ← sign-in form renders
```

The designed handshake is only 3 cross-domain redirects. Everything past
that is one bug restarting the chain over and over.

## The bug

When a page on the hosted domain loads with a one-time `code`, the
`StackClientApp` constructor schedules **two** async startup flows
back-to-back:

1. `callOAuthCallback` — which **synchronously strips `code` + `state`
from the URL** (`history.replaceState`) before starting its network
token exchange, and
2. `_maybeHandleNestedCrossDomainAuth` — which has a guard for exactly
this situation ("a real OAuth callback wins"), implemented as *"is
`code`+`state` in the URL?"*

Flow 1 runs first. By the time flow 2 reads `window.location`, the
params it's guarding on are already gone — so it concludes no OAuth
callback is happening, sees the (un-stripped) nested handoff marker, and
bounces back to the app domain to request a *new* code, cancelling the
in-flight exchange:

```mermaid
sequenceDiagram
    participant A as Your app (a.com)
    participant B as Hosted sign-in (b.com)
    A->>B: 1. go to sign-in ("I have session X")
    B->>A: 2. "prove it" (state, code_challenge)
    A->>B: 3. one-time code for session X
    Note over B: callOAuthCallback strips code+state from URL,<br/>starts token exchange (network)
    Note over B: nested handler runs next, checks URL for code+state…<br/>already gone → guard defeated 
    B->>A: 2'. "prove it" AGAIN (fresh state) — exchange cancelled
    A->>B: 3'. another one-time code
    Note over B: …loop repeats until the exchange happens to<br/>finish before the re-bounce navigation commits
```

Whether each cycle escapes is a coin flip between two competing
navigations (the exchange's success redirect vs. the handler's
re-bounce), which is why the loop count varies run to run and the issue
reproduces so inconsistently.

## The fix

Capture the URL once, at construction time — before anything can mutate
it — and let the nested handler consult that snapshot in addition to the
live URL:

- The constructor now captures `new URL(window.location.href)` when
scheduling the nested-auth resolution and passes it in.
- `_maybeHandleNestedCrossDomainAuth(urlAtConstructionTime?)` stands
down if **either** the live URL **or** the construction-time URL carries
`code` + `state`.

A stripped callback still counts as a callback, so the handler no longer
re-bounces while the exchange is in flight. Every other path is
unchanged: the handler still reads all of its working params from the
live URL (the strip never touches the nested params), hop-1/hop-2 pages
have no `code` in either snapshot, and ordinary social-login callbacks
never had this race (the component-driven flow strips long after the
handler has run).

Note this fix removes the *restarts*. The remaining 3-redirect baseline
for signed-out users is a separate design issue (the analytics-created
anonymous session triggering the handoff at all) and is intentionally
out of scope here.

## Tests

- New: `does not re-bounce nested cross-domain auth after the OAuth
callback consumed code+state from the URL` — pins both guards
(mutation-tested: reverting either fix line fails it).
- New: `passes the construction-time URL to the nested cross-domain auth
handler` — pins the eager capture; fails if the URL is read lazily at
handler run time.
- Full cross-domain suite passes (the `signOut` timeout in that file is
a pre-existing flake on `dev`, reproducible without this change).


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes a race in nested cross-domain auth that caused repeated redirects
between the app and the hosted sign-in. We now snapshot the URL at
construction so OAuth callbacks are respected even after `code` and
`state` are stripped.

- **Bug Fixes**
- Capture `window.location` at construction and pass it to
`_maybeHandleNestedCrossDomainAuth`.
- Handler stands down if `code` and `state` exist in the live or
captured URL.
- Stops the redirect ping‑pong; the 3‑redirect baseline remains
unchanged.
- Keeps reading nested params from the live URL; no other paths changed.
  - Adds tests to pin the race and the construction‑time URL behavior.

<sup>Written for commit f312baa54c.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1581?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved cross-domain OAuth authentication handling to prevent
unnecessary redirects after OAuth callback processing.

* **Tests**
* Added test coverage for nested cross-domain OAuth authentication
scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-11 17:37:05 -07:00
Bilal Godil
f87c9c92c1 fix: address review findings for the HEXCLAVE_* env rename
- e2e helpers: also expand the port-prefix placeholder in HEXCLAVE_*/
  NEXT_PUBLIC_HEXCLAVE_* vars (the renamed .env.development keys no longer
  matched the STACK_-only prefix filter, leaving literal ${...} in every URL).
- docker/local-emulator/generate-env-development.mjs: read source keys under
  the canonical HEXCLAVE_* name with STACK_* fallback and emit canonical keys
  (the exact-name lookups threw after the source env files were renamed).
- prisma.config.ts: resolve the datasource URL from
  HEXCLAVE_DATABASE_CONNECTION_STRING with legacy fallback (Prisma's env()
  helper only knew the legacy name); same for the psql-inner script.
- backend vitest: accept both env prefixes and dual-read the DB connection
  string in the auto-migration tests.
- getProcessEnv: empty-as-unset fallback (||), consistent with getEnvVariable —
  an empty HEXCLAVE_* template placeholder must not shadow a real legacy value.
- errors.tsx debugger flag and dashboard next.config emulator flag: dual-read
  the canonical name.
- Vite examples and docs snippets: VITE_STACK_* → VITE_HEXCLAVE_* (the old
  names were dead after their .env.development files were renamed).
2026-06-11 16:47:19 -07:00
Bilal Godil
e55938308d chore: reference Hexclave instead of Stack in OAuth callback warning 2026-06-11 16:26:26 -07:00
Bilal Godil
178b5c5a8c chore: rename STACK_* env vars to HEXCLAVE_* in env templates, with legacy dual-read
Renames every STACK_*-prefixed variable (including NEXT_PUBLIC_STACK_*) to
HEXCLAVE_* across all checked-in .env, .env.development, and .env.example
files, completing the env-var side of the Hexclave rebrand. Legacy STACK_*
names keep working everywhere so existing deployments, .env.local files, and
self-hosted setups don't need immediate migration:

- getEnvVariable already prefers HEXCLAVE_* with STACK_* fallback; fix it to
  treat empty-string values as unset so the empty HEXCLAVE_* placeholders in
  the checked-in templates can't shadow a real value under the legacy name.
- Apply the same empty-as-unset rule (|| instead of ??) to all literal
  process.env dual-reads (dashboard inline env, docs, examples, CLI) and to
  the generated SDK env getter chains via packages/template generate-env.ts.
- Add explicit HEXCLAVE_* || STACK_* dual-reads to direct process.env readers
  fed by the renamed files: prisma seed, e2e tests/helpers, internal-tool
  scripts and app, demo/convex examples.
- docker/server/entrypoint.sh: add a generic two-way HEXCLAVE_/STACK_ env
  mirror (run at startup and again before sentinel replacement), replacing the
  previous URL-trio-only mirror; accept legacy NEXT_PUBLIC_STACK_PORT_PREFIX;
  rotate-secrets.sh falls back to HEXCLAVE_DATABASE_CONNECTION_STRING.
- e2e cross-domain-auth and the internal-feedback-emails in-source test now
  override the canonical HEXCLAVE_* names (the legacy override would be
  shadowed by the renamed env files).
- docs/code-examples snippets renamed outright to the canonical names.
2026-06-11 16:23:50 -07:00
Armaan Jain
a092be6dc3
Payments minor navigation and UI bugs fixed (#1585)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/hexclave/blob/dev/CONTRIBUTING.md

-->


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes product creation navigation and the quantity selector layout in
Payments. Links now resolve to the correct project route and the
quantity control no longer squishes or wraps.

- **Bug Fixes**
- Use admin app `projectId` and a shared `getCreateProductHref` helper
to build product creation URLs, preserving `productLineId` and
`customerType` when present.
- Prevent quantity selector buttons from shrinking and wrap the input in
a fixed-width container to keep the control stable in tight layouts.

<sup>Written for commit 22d2eb6d90.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1585?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-11 11:38:00 -07:00
Mantra
74c888fed7
chore(mcp/docs): canonicalize HEXCLAVE_ env vars in docs + raise ask_hexclave step limit & timeout (#1571)
## Summary

Follow-up from analyzing the dogfooding report on the `ask_hexclave` MCP
tool. Two root causes were confirmed against source:

1. **The "`STACK_` vs `HEXCLAVE_` env var hallucination" wasn't a
hallucination** — it's an incomplete Stack Auth → Hexclave rebrand. The
SDK resolves both prefixes (`packages/js/src/generated/env.ts`), with
`HEXCLAVE_*` canonical and `STACK_*` a legacy fallback, but several
docs/examples still showed the old `STACK_*` names. That inconsistency
is what misled agents into thinking `HEXCLAVE_*` was made up.
2. **`ask_hexclave` timeouts** — the tool proxies to a `quality:
"smart"` agentic docs-search loop. The agent step budget (50) and the
120s timeouts were too tight; broad/multi-part questions blew the budget
(reproduced 3× while investigating).

## Changes

### Docs: canonicalize client SDK auth env vars to `HEXCLAVE_*`
Converted `PROJECT_ID`, `PUBLISHABLE_CLIENT_KEY`, `SECRET_SERVER_KEY`,
`API_URL` (+ `NEXT_PUBLIC_` / `VITE_` forms) from `STACK_*` →
`HEXCLAVE_*` in app-setup docs + the package template:

-
`docs-mintlify/guides/integrations/{convex,tanstack-start,vercel}/overview.mdx`
- `docs-mintlify/guides/going-further/local-vs-cloud-dashboard.mdx`
- `docs-mintlify/guides/apps/analytics/overview.mdx`
- `docs-mintlify/guides/other/tutorials/ship-production-ready-auth.mdx`
- `docs-mintlify/sdk/objects/hexclave-app.mdx`
- `packages/template/src/integrations/convex/component/README.md` (the
tracked source of the generated `@hexclave/js` + `@hexclave/next` copies
— the generated copies are git-ignored)

**Deliberately left untouched** — read literally by the backend/CLI (no
`HEXCLAVE_` alias) or user-defined: `STACK_CLICKHOUSE_*`,
`STACK_DATABASE_*`, `STACK_OPENROUTER_*`, `STACK_CLI_*`, `STACK_SEED_*`,
`STACK_WEBHOOK_SECRET`, `STACK_DATA_VAULT_SECRET`, and the `x-stack-*`
HTTP headers. So `self-host.mdx`, `cli.mdx`, `jwts.mdx`, `webhooks`, and
`data-vault` docs are intentionally unchanged.

### Reliability: raise `ask_hexclave` step limit + timeout
- `apps/backend/src/app/api/latest/ai/query/[mode]/route.ts`:
docs/search agent step limit **50 → 75** (+50%); AI generation abort
**120s → 180s**
- `apps/mcp/src/mcp-handler.ts`: MCP function `maxDuration` **120 →
180** (kept ≥ backend timeout so the proxy doesn't die before the
backend finishes)

## Notes
- Also includes a small pre-existing `run pnpm fml` commit (regenerated
docs snippets / `llms-full.txt`).
- The step/timeout bumps address the *symptom*. The durable reliability
fix is streaming/keepalive on the MCP proxy so the client never idles
out mid-query — proposed as a follow-up.
- **Not** included: the separate `sendEmail` doc-vs-SDK drift (docs
declare `Promise<Result<void, KnownErrors>>` in
`sdk/objects/hexclave-app.mdx`, but the SDK returns `Promise<void>` and
throws). That's a docs *correctness* bug deserving its own PR.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Canonicalized auth env vars in docs/templates to `HEXCLAVE_*`, raised
docs/search step limits and timeouts, and clarified `HexclaveApp`
defaults. MCP tool and server instructions now require loading the
`skill` resource before queries.

- **Bug Fixes**
- Docs: Use `HEXCLAVE_PROJECT_ID`, `HEXCLAVE_PUBLISHABLE_CLIENT_KEY`,
`HEXCLAVE_SECRET_SERVER_KEY`, and optional `HEXCLAVE_API_URL` across
guides/templates (Vercel, Convex, TanStack Start, analytics). In SDK
docs, `secretServerKey` defaults to `HEXCLAVE_SECRET_SERVER_KEY`, and
client defaults use `NEXT_PUBLIC_HEXCLAVE_*`. Backend-only `STACK_*`
vars (`STACK_CLICKHOUSE_*`, `STACK_DATABASE_*`, `STACK_OPENROUTER_*`,
CLI/data-vault/webhook headers) unchanged.
- Reliability: Increase docs/search step limit 50→75 and timeouts
120s→180s; set MCP `maxDuration` to 180s; use `performance.now()` for
duration logging. MCP instructions updated to require loading the
`skill` resource before using tools.

<sup>Written for commit f6be2c3162.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1571?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Performance & Reliability**
* Increased AI operation timeouts and step limits for certain prompts;
improved generate-mode duration measurement for more accurate logging.
* **Documentation**
* Replaced Stack-branded environment variable names with Hexclave
equivalents across guides and examples.
* Clarified that hexclave dev injects required environment variables
automatically.
  * Added guidance on configuring custom authentication redirect URLs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-11 10:53:53 -07:00
Konstantin Wohlwend
be01ae733e Improved PKCE support 2026-06-11 10:28:14 -07:00
github-actions[bot]
1999ad8be3 chore: update package versions 2026-06-11 17:19:24 +00:00