## What
Fixes the 9 failing tests in the E2E (Local Emulator) job — 2 test
files, both stale after recent refactors that renamed source but missed
the tests.
### `apps/e2e/tests/general/cli.test.ts` (6 failures)
The `stack emulator` command was removed in #1522 (which also reworded
its auth errors from "local emulator" → "development environment"), but
the e2e tests were never updated:
- Updated two error-string assertions:
- `"Local emulator publishable client key not found"` → `"Development
environment publishable client key not found"`
- `"Cannot reach local emulator"` → `"Cannot reach development
environment"`
- Removed the dead `"Stack CLI — Emulator"` describe block (4 tests for
the deleted `emulator pull/start/stop/list-releases` subcommands) and
the now-unused `CLI_SRC_BIN` const.
###
`apps/dashboard/src/lib/remote-development-environment/config-file.test.ts`
(3 failures)
Leftover `@stackframe/*` names from the `@hexclave` rename:
- Fixture imports `@stackframe/stack-shared/config` →
`@hexclave/shared/config` (the `defineStackConfig` /
`defineHexclaveConfig` cases were failing with `Cannot find module`).
- Rendered-config snapshot type import `@stackframe/js` →
`@hexclave/js`.
## Verification
- `config-file.test.ts`: **7 passed**.
- `cli.test.ts` against a live local backend: **69 passed / 4 skipped /
0 failed** (the 4 skips are environment-gated `it.runIf`/`it.skip`, not
failures).
- Reproduced both CLI error paths against the built CLI binary to
confirm the new strings match exactly.
- `lint` ✓ and `typecheck` ✓ for `@hexclave/e2e-tests` and
`@hexclave/dashboard`.
Only test files are changed — no production code.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes 9 failing E2E tests by updating CLI error messages and RDE config
test imports after the emulator command removal and the `@hexclave`
rename. Removes obsolete emulator CLI tests; no production code changed.
- **Bug Fixes**
- CLI: updated two error-string assertions to use “Development
environment …” wording.
- CLI: removed the obsolete “Stack CLI — Emulator” test block and the
unused `CLI_SRC_BIN`.
- Dashboard RDE config tests: replaced `@stackframe/stack-shared/config`
with `@hexclave/shared/config`.
- Snapshot import: `@stackframe/js` → `@hexclave/js`.
<sup>Written for commit a887d7209b.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1528?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**
* Updated error messages to use "development environment" terminology
instead of "emulator" references.
* **Tests**
* Adjusted test assertions and imports for consistency with updated
terminology.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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
## Summary
Replaces the request-host-header-derived OAuth `redirect_uri` with a
config-driven `customCallbackUrl` field on each environment-level OAuth
provider.
Resolution of the `redirect_uri` we send to providers (and that
customers register in their provider app config):
- **Shared providers** → always the stack-auth-branded callback, so
Stack's shared OAuth apps keep working. `customCallbackUrl` is
schema-forbidden when `isShared` is true.
- **Custom + `customCallbackUrl` set** → the configured URL verbatim.
- **Custom without it (legacy)** → the stack-auth-branded callback, so
providers registered before this field are unaffected.
- **New custom providers set up in the dashboard** → the env-aware
hexclave-branded callback (prod → `api.hexclave.com`, dev/staging →
siblings, self-host/localhost → `NEXT_PUBLIC_STACK_API_URL` unchanged).
## Details
- **Schema** (`schema.ts`, `schema-fields.ts`): optional
`customCallbackUrl` after `clientSecret`, with a `.when('isShared')`
rule rejecting any value for shared providers; added to the provider
default factory.
- **Shared host helper** (`utils/cloud-hosts.tsx`, new):
`CLOUD_HOST_PAIRS` moved into stack-shared with `getCloudApiUrlSiblings`
/ `getStackAuthApiBaseUrl` / `getHexclaveApiBaseUrl`;
`request-api-url.ts` re-exports it so the JWT `iss` logic is untouched.
- **Runtime** (`oauth/index.tsx` + all 13 provider `create()`s):
`getProvider` resolves the full `redirect_uri` from config instead of
the request host; providers now take `redirectUri` instead of `apiUrl`.
The JWT `iss` path still uses the request host.
- **Dashboard** (`page-client.tsx`, `providers.tsx`,
`oauth-callback-url.ts` new): brand-new custom providers get the
hexclave callback; existing providers keep whatever they had (edits
never silently move a registered redirect URL); the displayed Redirect
URL mirrors backend resolution.
- **Docs** (`migration.mdx`): existing `api.stack-auth.com` callbacks
keep working; only recreated providers use the hexclave URL.
## Notes / scope decisions
- **Dashboard-only injection**: SDK/CLI/legacy-config-created custom
providers fall back to the stack-auth callback (they don't auto-get the
hexclave URL).
- **shared → standard** conversions keep the stack-auth fallback rather
than flipping to hexclave (the safe path that never breaks a registered
redirect).
## Test plan
- [x] `typecheck` + `lint` green across stack-shared, backend,
dashboard, e2e
- [x] cloud-hosts unit tests, schema tests, schema fuzzer pass
- [x] e2e: shared-provider `customCallbackUrl` rejected (400);
standard-provider `customCallbackUrl` accepted and round-trips
- [ ] e2e OAuth authorize/callback flow (needs running stack) — reasoned
unaffected since localhost isn't a cloud host, so the redirect base
stays localhost as before
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a per-provider `customCallbackUrl` for OAuth `redirect_uri`,
removing the request-host dependency and making redirects predictable.
Shared providers always use the Stack-branded callback; new or converted
custom providers default to the Hexclave-branded callback. Existing
callbacks keep working; no changes needed unless you recreate or convert
a provider.
- **New Features**
- Added `customCallbackUrl` on provider configs (URL-validated;
forbidden when `isShared` is true).
- `getProvider` now resolves a config-driven `redirectUri`; providers
take `redirectUri` instead of `apiUrl` (pure resolver with in-source +
e2e tests to lock legacy behavior).
- Introduced `@stackframe/stack-shared` `utils/cloud-hosts.tsx` and
dashboard helpers to show the resolved Redirect URL and set the Hexclave
callback for new providers and when converting shared → standard.
- **Bug Fixes**
- OAuth callback now handles legitimate cross-host flows by recording
the authorize host and skipping the host-scoped CSRF cookie when
authorize and callback hosts differ, relying on server-side state and
PKCE.
<sup>Written for commit 32d95fcdcb.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1512?utm_source=github">Review
in cubic</a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Preserve and display custom OAuth callback/redirect URLs in the
dashboard; provider creation/edit flows respect existing custom URLs.
* Added cloud-host mapping and redirect-uri helpers to resolve branded
API callback bases.
* **Bug Fixes**
* Improved cross-host OAuth callback handling and CSRF validation for
reliable cross-host flows.
* **Tests**
* Added E2E and unit tests covering callback URL behavior and host
mapping.
* **Documentation**
* Updated migration guidance for callback URL changes and recreation
scenarios.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1512?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
The Stack Auth → Hexclave rebrand modal added in
[#1493](https://github.com/hexclave/stack-auth/pull/1493) rendered the
**Hexclave** logo on both sides of its illustration instead of *Stack
Auth → Hexclave*.
## Root cause
[\`hexclave-rebrand-modal.tsx\`](https://github.com/hexclave/stack-auth/blob/dev/apps/dashboard/src/components/hexclave-rebrand-modal.tsx)
referenced \`/logo.svg\` and \`/logo-bright.svg\` for the left-hand
"Stack Auth" mark. But the visible-rebrand flip in
[#1481](https://github.com/hexclave/stack-auth/pull/1481) replaced those
files in \`apps/dashboard/public/\` with the Hexclave benzene mark — so
post-merge, both \`<Image>\` slots resolved to the Hexclave logo.
## Fix
- Restored the **pre-rebrand Stack Auth SVGs** (lifted from
\`57ff5d3ce~1\`, the commit before the brand-flip) under dedicated
filenames so they can't get clobbered the next time \`/logo.svg\` is
updated:
- \`apps/dashboard/public/stack-auth-logo.svg\` — black mark, light
theme
- \`apps/dashboard/public/stack-auth-logo-bright.svg\` — white mark,
dark theme
- Pointed the modal's left-hand \`<Image>\` pair at the new paths and
left a comment explaining why we don't share \`/logo.svg\` (so the next
person doesn't try to consolidate it back).
The originals on \`origin/dev\` (\`/logo.svg\`, \`/logo-bright.svg\` =
Hexclave) are untouched.
## Verification
- \`pnpm --filter @stackframe/dashboard lint\` — clean.
- Diff of
[hexclave-rebrand-modal.tsx](https://github.com/hexclave/stack-auth/blob/fix-stack-logo-in-modal/apps/dashboard/src/components/hexclave-rebrand-modal.tsx)
is two \`src=\` swaps plus a comment; the dismissal logic, gates, and
storage key are untouched.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the rebrand modal to show the Stack Auth logo on the left instead
of rendering Hexclave on both sides. Restores pre-rebrand assets as
`stack-auth-logo.svg` and `stack-auth-logo-bright.svg` and updates the
modal to use them for light/dark themes.
<sup>Written for commit f4ed26266c.
Summary will update on new commits. <a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1495?utm_source=github">Review
in cubic</a></sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Style**
* Updated the rebrand modal illustration assets to display Stack Auth
branding correctly.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1495?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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
## Summary
**Stacked on [#1475](https://github.com/hexclave/stack-auth/pull/1475)**
(`cl/hexclave-pr1`, the invisible compatibility layer). Diff vs that
base = the actual PR 2 code.
This is **PR 2 of the Stack Auth → Hexclave rebrand: the visible flip**.
Old wire identifiers (cookies, request/response headers, Bearer prefix,
JWT issuers, MCP tool name) keep working indefinitely via PR 1's
dual-accept. This PR flips every user-visible surface — package names
taught in docs, SDK class names in code examples, dashboard setup
snippets, page titles, error messages, email content, CLI binary,
default base URLs, GitHub repo slug, contributor guidance — to the
Hexclave brand.
See [`RENAME-TO-HEXCLAVE.md`](./RENAME-TO-HEXCLAVE.md) → *"PR 2: Rebrand
to Hexclave (visible)"* for the full per-work-area spec.
## What's implemented (per the plan's PR 2 scope)
- **SDK base URLs** flipped: `defaultBaseUrl` and
`defaultAnalyticsBaseUrl` in
[common.ts](packages/template/src/lib/stack-app/apps/implementations/common.ts:127)
→ `https://api.hexclave.com` / `https://r.hexclave.com`. PR 1's
[`getHardcodedFallbackUrls`](packages/stack-shared/src/utils/urls.tsx:199)
table now keys on the Hexclave domain.
- **Domain inventory sweep** (16 subdomains from the plan): every
`api/app/docs/discord/demo/mcp/skill/feedback/test/preview/r/api2/api.staging/idp-jwk-audience/built-with.stack-auth.com`
reference in production code, docs-mintlify, examples, READMEs, and
contributor guidance flipped to `*.hexclave.com`. Carve-outs: PR 1's
intentional JWT issuer dual-accept table in
[tokens.tsx](apps/backend/src/lib/tokens.tsx), the legacy `./docs/`
folder, the `unified-docs-widget` allowlist (deliberately accepts both
during DNS transition), and `url-targets.ts` hosted-component default
(baked into existing customer deploys).
- **`@deprecated` JSDoc** on every `Stack*` public export
([packages/template/src/lib/stack-app/index.ts](packages/template/src/lib/stack-app/index.ts)
+ [packages/template/src/index.ts](packages/template/src/index.ts)) —
`StackClientApp`, `StackServerApp`, `StackAdminApp` + every
constructor/options/JSON type, `StackHandler`, `StackProvider`,
`StackTheme`, `useStackApp`, `defineStackConfig`, `StackConfig`.
Hexclave\* aliases are now canonical.
- **Runtime `console.warn`**
([packages/template/src/internal/deprecation-warning.ts](packages/template/src/internal/deprecation-warning.ts))
— once-per-process when the SDK is loaded from a `@stackframe/*`
artifact. Detection uses the existing
`STACK_COMPILE_TIME_CLIENT_PACKAGE_VERSION_SENTINEL` (rewritten at build
time to e.g. `js @stackframe/stack@2.8.92` or `js
@hexclave/next@1.0.0`); `@hexclave/*` mirror artifacts short-circuit the
warning.
- **Tier 3 data migration**: new idempotent SQL migration
[`20260523000000_rename_internal_project_to_hexclave`](apps/backend/prisma/migrations/20260523000000_rename_internal_project_to_hexclave/migration.sql)
— updates the internal Project `displayName` 'Stack Dashboard' →
'Hexclave Dashboard' and `description` only if both still hold the
pre-rebrand defaults. Operator-renamed projects untouched, missing row
no-ops, re-runs are no-ops. [`seed.ts`](apps/backend/prisma/seed.ts:87)
default flipped. `getSharedEmailConfig("Stack Auth")` → `("Hexclave")`.
- **Tier 4 brand strings** (mechanical sweep, ~340 files):
- Page + OpenAPI titles (Hexclave API / Dashboard / REST API / Webhooks
API / Documentation). OpenAPI `info.description` documents
`X-Hexclave-*` headers as canonical with compat note on `X-Stack-*`.
- `HexclaveAssertionError` message text
([errors.tsx:71](packages/stack-shared/src/utils/errors.tsx:71)) — "an
error in Stack." → "an error in Hexclave."
- Known-error message templates
([known-errors.tsx](packages/stack-shared/src/known-errors.tsx)) flipped
to lead with `x-hexclave-*` + the new `docs.hexclave.com` URL; legacy
`x-stack-*` mentioned as compat aliases. **25 e2e test files updated in
lockstep**.
- Email content: failed-emails-digest body, sendTestEmail recipient (now
`sent-with-hexclave.com`), test-email-recipient default.
- `CHANGELOG.md` title → "Hexclave Changelog".
- `AGENTS.md` env var convention: new vars prefix `HEXCLAVE_` /
`NEXT_PUBLIC_HEXCLAVE_` for Category A/B; legacy `STACK_*` explicitly
noted as accepted via PR 1's dual-read.
- **CLI / init wizard**:
- Every dashboard setup snippet, init-stack template, and docs-mintlify
page teaches `npx @hexclave/cli@latest init` (was
`@stackframe/stack-cli`).
[setup-page.tsx](apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/setup-page.tsx)
+
[link-existing-onboarding](apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/link-existing-onboarding.tsx).
- [init-stack](packages/init-stack/src/index.ts:634)
`STACK_*_INSTALL_PACKAGE_NAME_OVERRIDE` defaults flipped to
`@hexclave/*`.
- Generated `stack/client.ts` / `stack/server.ts` import from
`@hexclave/next` and reference `HexclaveClientApp` /
`HexclaveServerApp`.
- Internal `StackAuthKeys` dashboard component renamed to
`HexclaveKeys`.
- **docs-mintlify rewrite** (legacy `./docs/` intentionally untouched
per scoping decision):
- **78 MDX files swept**.
`@stackframe/{react,stack,js,tanstack-start,...}` →
`@hexclave/{react,stack,js,...}` in install snippets and code blocks;
`Stack*` SDK class names → `Hexclave*` in all code examples; 'Stack
Auth' brand phrase → 'Hexclave'.
- `openapi/{server,admin,client,webhooks}.json` titles → 'Hexclave REST
API' / 'Hexclave Webhooks API'.
- **Generators flipped before regeneration**:
-
[`packages/stack-shared/src/helpers/init-prompt.ts`](packages/stack-shared/src/helpers/init-prompt.ts),
[`/ai/prompts.ts`](packages/stack-shared/src/ai/prompts.ts),
[`apps/backend/src/lib/ai/prompts.ts`](apps/backend/src/lib/ai/prompts.ts),
[`apps/backend/src/lib/ai/tools/create-email-{template,draft}.ts`](apps/backend/src/lib/ai/tools/create-email-template.ts),
[`apps/skills/src/app/route.ts`](apps/skills/src/app/route.ts) (taught
MCP tool → `ask_hexclave` with compat note; CLI binary teach →
`hexclave`),
[`docs-mintlify/snippets/home-prompt-island.jsx`](docs-mintlify/snippets/home-prompt-island.jsx),
[`packages/template/README.md`](packages/template/README.md) +
integrations/convex/component/README.md.
- `generate-sdks` propagated changes to `packages/{react,stack,js}`.
- **OpenAPI dual-documentation**:
[`apps/backend/src/app/api/latest/route.ts`](apps/backend/src/app/api/latest/route.ts)
now lists `X-Hexclave-*` headers as primary documented schemas with
`X-Stack-*` duplicates marked `.optional()` (both accepted at runtime by
PR 1's normalize-at-proxy shim).
- **`@stackframe/emails` virtual module**: dual-aliased to
`@hexclave/emails` at the bundler boundary
([email-rendering.tsx:89](apps/backend/src/lib/email-rendering.tsx:89)).
Stored email templates continue to import from either name; new
AI-generated templates and the system prompt teach `@hexclave/emails`.
- **Tier 2 mirror-publish wiring** (new this PR, lays the groundwork for
`@hexclave/*` first publish):
-
[`scripts/rewrite-packages-to-hexclave.ts`](scripts/rewrite-packages-to-hexclave.ts)
— rewrites 9 publishable `@stackframe/*` → `@hexclave/*` `package.json`
files (reads `HEXCLAVE_VERSION` env or `--version=` flag), pins
cross-deps to the shared `@hexclave` version, registers `hexclave` bin
alongside `stack` for `@hexclave/cli`.
-
[`.github/workflows/npm-publish.yaml`](.github/workflows/npm-publish.yaml)
appended with rewrite-then-republish step. `pnpm publish` skips
already-on-npm versions so reruns are safe.
- **Sender email domain**: `noreply@stackframe.co` →
`noreply@sent-with-hexclave.com` (the dedicated transactional-sender
domain split per the plan, to isolate bulk deliverability from
`hexclave.com` reputation); `security@` / `team@stack-auth.com` inbound
mailboxes → `@hexclave.com`.
- **Self-host docs**: docker network / container names in the bash
examples flipped from `stack-auth` to `hexclave` (`hexclave-postgres`,
`hexclave-clickhouse`, `hexclave.env`). The docker image tag
`stackauth/server:latest` stays per the plan's locked decision.
- **GitHub repo slug**: `hexclave/stack-auth` → `hexclave/hexclave` in
every `package.json` `repository` field, README link, CHANGELOG
raw-asset URL.
## Carve-outs (deliberately untouched)
-
**[`apps/backend/src/lib/tokens.tsx`](apps/backend/src/lib/tokens.tsx)**
JWT issuer dual-accept table — PR 1 intentional infrastructure, kept
indefinitely.
- **Legacy `./docs/` folder** — per scoping decision (only
`docs-mintlify/` rewritten).
- **`unified-docs-widget` hostname allowlist** — accepts both
`.hexclave.com` (canonical) and `.stack-auth.com` (transition window)
for DNS rollout.
- **`url-targets.ts`** hosted-domain default
`.built-with-stack-auth.com` — wire identifier baked into existing
customer deploys; indefinite read-fallback.
- **Binary visual assets** (logos, favicons, OG images, README
screenshots) — out of scope for this PR. Need design work; tracked
separately.
## Verification
- **`pnpm typecheck`** on
`packages/{template,stack-shared,react,stack,js}` + `apps/dashboard`:
**all green**. The remaining backend / e-commerce-demo typecheck errors
are pre-existing (Prisma codegen output +
`./generated/api-versions.json` not present in fresh worktrees without
`pnpm run codegen-prisma` + a live DB) and unrelated to this diff.
- **`pnpm lint`** on the same 6 packages: all green.
- **Final grep** for residual `Stack Auth` / `stack-auth.com` /
`@stackframe/stack-cli@latest` references: zero outside the intentional
carve-outs above.
- **25 e2e test files updated in lockstep** with the known-error message
changes (asserted strings flipped to match the new x-hexclave-* +
compat-note messages).
## Deploy blockers (ops sequencing before this rebrand goes live)
This PR is code-complete, but the rebrand's visible surfaces (SDK
default URLs, dashboard links, npm READMEs, REST error messages, runtime
deprecation warning) all point at `*.hexclave.com` / `@hexclave/*`
resources that don't exist yet. None of these are fixable from a PR —
they're ops/registrar/npm work that has to be sequenced before merging
this to a release tag.
Suggested ordering, hardest blockers first:
### Tier 1 — required before customer-facing deploy (everything below
this line *will visibly break customers on day 1* if skipped)
1. **DNS + TLS for `api.hexclave.com` + `api1./api2.hexclave.com`** →
must point at the same backend that serves `api.stack-auth.com` (or a
backend that mirrors PR 1's dual-accept). The SDK's new `defaultBaseUrl`
is `https://api.hexclave.com`; every customer that relied on the old
default and upgrades to a post-PR2 SDK build sends API requests here.
Until this resolves, every default-config customer's API call NXDOMAINs.
2. **DNS for `app.hexclave.com`** → the dashboard. Referenced in the
SDK's default-error messages ("Please create a project on the Hexclave
dashboard at https://app.hexclave.com"), the init-stack flow's
`wizard-congrats` redirect, and the OAuth dashboard handoff.
3. **DNS for `docs.hexclave.com`** + Mintlify deploy → the SDK runtime
deprecation warning (`https://docs.hexclave.com/migration`), every
README, every "Learn more" link in the dashboard, and every REST API
error body (`/api/overview#authentication`) points here. The MDX is in
this PR; the docs build target needs DNS.
4. **DNS for `mcp.hexclave.com`** → the MCP server endpoint that every
taught agent integration (`claude mcp add ...`, `cursor`, `codex`,
`vscode`) registers. Until this resolves, every `npx
@hexclave/cli@latest init` MCP-registration step fails.
5. **Reserve the `@hexclave` npm scope + set repo variable
`HEXCLAVE_VERSION`** → the mirror-publish step in
`.github/workflows/npm-publish.yaml` is gated on this variable. Without
it, the entire taught onboarding command `npx @hexclave/cli@latest init`
404s from the npm registry, *and* every README that says "install
`@hexclave/next`" leads to install failure. Pick the initial version
intentionally (`1.0.0` or aligned to `@stackframe/stack`); don't accept
a silent default.
### Tier 2 — required before announcing the rebrand publicly (lookalike
or low-traffic surfaces, but visibly broken)
6. **DNS for `r.hexclave.com`** → the analytics beacon
`defaultAnalyticsBaseUrl`. Silent failure if missing (analytics drops),
but should land alongside Tier 1.
7. **Register `sent-with-hexclave.com` + full email auth (SPF / DKIM /
DMARC)** → the new default sender domain for shared-sender transactional
emails. Without it the dashboard "send test email" path emits bounces,
and shared-sender flows (`getSharedEmailConfig("Hexclave")`) deliver to
spam at best.
8. **MX + SPF / DMARC for `hexclave.com`** → `team@hexclave.com` and
`security@hexclave.com` mailboxes. The security disclosure mailbox is
referenced in [`.github/SECURITY.md`](.github/SECURITY.md);
`team@hexclave.com` is the actual recipient of internal feedback emails
sent at runtime by
[`apps/backend/src/lib/internal-feedback-emails.tsx`](apps/backend/src/lib/internal-feedback-emails.tsx).
Today, every runtime feedback email bounces.
9. **DNS for `skill.hexclave.com`** → the canonical AI-agent skill fetch
URL (the agent bootstrap pivot). Without it, the entire "agent downloads
`SKILL.md` from a known URL" flow taught in
[`packages/stack-shared/src/helpers/init-prompt.ts`](packages/stack-shared/src/helpers/init-prompt.ts)
fails.
10. **Create `github.com/hexclave/hexclave` as a public repo** (even as
a redirect to `hexclave/stack-auth`) **OR** rewrite every `package.json`
`"repository"` field + dashboard footer "view on GitHub" link to point
at `hexclave/stack-auth` (which already exists). Currently every npm
package page's "Repository" link is dead, and the dashboard's GitHub
button + dev-tool repo link are dead.
### Tier 3 — broken but low-visibility / low-traffic
11. **DNS for `discord.hexclave.com`** → Discord invite redirect, used
in every README's chip and the dashboard footer.
12. **DNS for `demo.hexclave.com`** → "✨ Demo" badge in every npm
package README. Broken-image badge on the package page.
13. **DNS + TLS for `built-with-hexclave.com`** → optional
hosted-handler domain (the default reverted to
`.built-with-stack-auth.com` in this PR's carve-outs, so this only
matters for projects that manually flip).
## Other follow-ups (not deploy-blocking)
- **E2E snapshot regen across the full suite** for the dual-emitted
`x-hexclave-*` response headers (PR 1 follow-up; `vitest -u` in CI
absorbs).
- **Binary visual assets** — logos, favicons, OG images, README
screenshots; need design pass.
- **Backend OpenAPI fumadocs regen** in CI flow — the JSON files in
`docs-mintlify/openapi/` are committed but regen runs in CI. Verify the
workflow that does this still works against the post-PR2 source.
- **Backend typecheck infra debt** — needs `codegen-prisma` +
`codegen-route-info` to clear; pre-existing, unaffected by this PR.
## Test plan
- [ ] CI runs full e2e suite (with `vitest -u` to absorb residual
snapshot deltas, then committed back).
- [ ] Spot-check: new `@hexclave/cli init` (once published) generates
`hexclave.config.ts` and works against a fresh project.
- [ ] Spot-check: existing customer with `@stackframe/stack` import sees
the once-per-process `console.warn` recommending `@hexclave/next` on SDK
init.
- [ ] Manual: dashboard setup page renders the `npx @hexclave/cli@latest
init` snippet and the `x-hexclave-publishable-client-key` API header in
the curl example.
- [ ] Manual: a fresh `pnpm run prisma migrate` against a clean DB sets
the internal project displayName to 'Hexclave Dashboard'.
---------
Co-authored-by: Konstantin Wohlwend <n2d4xc@gmail.com>
<!--
Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/hexclave/stack-auth/blob/dev/CONTRIBUTING.md
-->
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Improves onboarding and analytics visuals. Adds clear Stripe setup
actions (Connect or Do Later) with safe redirects and precise
loading/disabled states, and fixes a stuck dashboard reload after
linking an existing project.
- **New Features**
- Payments onboarding: separate Connect/Do Later actions with per-button
loading and mutual disabling.
- US-only: “Do Later” creates a deferred Stripe account before finishing
onboarding.
- Secure redirect: enforce HTTPS on Connect and navigate via
window.location.href.
- Refresh Stripe account cache after `setupPayments()` to avoid stale
data on return.
- Analytics: smoother pie hover transitions, fading center label,
optional `showDateRange`; dashboard donut hides date range and adjusts
radii; revenue hover chart uses split bars for rounded tops and an avg
line.
- Tests cover deferred/unsupported payments setup and button loading
isolation.
- **Bug Fixes**
- After linking an existing config, use a full page navigation to the
project to prevent the dashboard from getting stuck on initial load.
<sup>Written for commit c80034ad1f.
Summary will update on new commits. <a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1489?utm_source=github">Review
in cubic</a></sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Option to defer payments setup during project onboarding;
connect/defer actions show targeted loading states.
* **Improvements**
* Linking existing projects now performs full navigation when
applicable.
* Charts: refined donut/pie sizing, smoother center fade animation,
optional date-range display, and improved color/stack rendering.
* Payments setup now refreshes account info after setup.
* **Tests**
* Added tests covering payments deferral, connect flows, and UI/loading
behavior.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1489?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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
## Summary
**Stacked on #1468** (`docs/hexclave-rename-plan` — the plan doc). Diff
vs that base = the actual PR 1 code.
This is **PR 1 of the Hexclave rebrand: the invisible compatibility
layer**. Everything is additive. Old SDKs, old wire identifiers, and old
env var names keep working unchanged. The backend dual-accepts and
dual-emits; new SDK code emits `x-hexclave-*` headers and the
`hexclave_` Bearer prefix; cookies dual-write; env vars dual-read across
every category. **No user-visible rebranding lands here** — that's PR 2.
See [`RENAME-TO-HEXCLAVE.md`](./RENAME-TO-HEXCLAVE.md) → *"PR 1
implementation guide"* for the full per-work-area spec, file pointers,
and chosen approach.
## What's implemented (all 14 PR-1 work-areas)
- **SDK export aliases** — `Hexclave*` aliases for the user-facing
`Stack*` exports added in `packages/template`; codegen propagates them
to `@stackframe/{js,stack,react,tanstack-start}`. React-only aliases
correctly excluded from `@stackframe/js`. (`e60550a2`)
- **JWT issuer dual-accept** — `decodeAccessToken` accepts both
`api.stack-auth.com` and `api.hexclave.com` issuers. Signing unchanged.
(`fc781def`)
- **Request-header dual-accept** — backend + dashboard proxies normalize
`x-hexclave-*` → `x-stack-*` at the existing empty proxy hook (so
`smart-request.tsx` and every route schema keep working unchanged); CORS
allowlists extended via a derive-once helper. (`2a056eac`)
- **MCP `ask_hexclave`** — registered alongside `ask_stack_auth` via a
shared helper; `ask_stack_auth` behavior byte-identical. (`30ffd604`)
- **Dev-tool** — DOM ids + header emit switched.
`window.HexclaveDevTool` exposed alongside `window.StackDevTool`.
(`32131ea7`)
- **The big consolidated commit** (`7fed864a`):
- **Env vars** — central `getEnvVariable` prefix-transform (HEXCLAVE
first, STACK fallback); dashboard + template client env files dual-read;
`turbo.json` globalEnv; `NEXT_PUBLIC_STACK_PORT_PREFIX` renamed outright
across ~82 files including docker.
- **Cookies** — dual-write/dual-read auth (`stack-access`/`-refresh-*`
and custom-domain variants), OAuth-state
(`stack-oauth-{inner,outer}-*`), and low-risk cookies (`stack-is-https`,
`stack-last-seen-changelog-version`). Bypass sites patched (backend
OAuth callback, dashboard remote-dev auth route, impersonation snippets,
snapshot serializer).
- **Bearer prefix** — SDK token parser accepts both `stackauth_` and
`hexclave_`; emits `hexclave_`. Discovery correction: this is purely
SDK-internal — the backend never parses it.
- **Response headers** — backend dual-emits
`x-hexclave-{request-id,actual-status,known-error}`; SDKs dual-read (new
first, stack fallback).
- **SDK request-header emit switch** —
`client/server/admin-interface.ts` + dashboard `api-headers.ts` +
`internal-project-headers.ts` + `feedback-form.tsx` switched to
`x-hexclave-*`. Plus `stack_response_mode` query param.
- **Storage keys** — dev-tool / cli-auth / oauth-button / docs keys
renamed (straight); `stack:session-replay:v1` dual-read so in-progress
recordings survive SDK upgrades; `stack_mfa_attempt_code` dual-read.
- **Query params** — cross-domain params dual-emit/dual-accept via
shared helpers; backend `oauth/authorize` accepts
`hexclave_response_mode` and `stack_response_mode`; `stack-init-id`
renamed.
- **`Symbol.for`** — app-internals symbol gets a parallel
`Symbol.for("Hexclave--app-internals")` getter on each attach site (no
read-site churn — old symbol still attached). 3 file-private symbols
renamed outright.
- **Config discovery** — prefer `hexclave.config.ts`, fall back to
`stack.config.ts` at every discovery site (CLI / dashboard / backend /
local-emulator); `init` writes the new filename; CLI credentials path
migrates.
- **Internal renames** — `StackAssertionError`,
`StackClient/Server/AdminInterface` renamed outright (no alias, per the
"internal-only → rename" rule). ~264 files touched.
- **Review-pass fixes** (`21217fbe`) — three real bugs found by parallel
review agents and fixed:
- `snapshot-serializer.ts` was interpolating the whole
`keyedCookieNamePrefixes` array (`${arr}`) — adding a second prefix
would have corrupted **every** OAuth-cookie snapshot, not just new ones.
- **Docker port-prefix producer/consumer mismatch** —
`entrypoint.sh`/`run-emulator.sh`/cloud-init `user-data` were still
producing `NEXT_PUBLIC_STACK_PORT_PREFIX` while the dashboard sentinel +
consumers had been renamed; silent self-host regression (custom port
prefix would be ignored).
- **Missing `hexclave-oauth-inner-*` dual-write** in the OAuth authorize
route — callback's fallback masked it but the dual-write was specified
by the plan.
- Plus: `mcp.test.ts` tool-list assertions updated to include
`ask_hexclave`; two dashboard header-emit sites switched to
`x-hexclave-*` for consistency.
- **E2E snapshot serializer follow-up** (`4b16cc5d`) —
`x-hexclave-request-id` added to the hidden-headers list (mirroring
`x-stack-request-id` treatment), and 2 sample inline snapshots
regenerated in `projects.test.ts` to include the new dual-emitted
headers.
## Verification
- **`pnpm typecheck`** — clean (the fresh-worktree `@/.source` / Prisma
codegen gap in `stack-docs` is pre-existing and unrelated).
- **`pnpm lint`** — 29/29 packages green.
- **`pnpm exec turbo run build --filter=./packages/*`** — 13/13 packages
build (including `@stackframe/stack-cli` once the dashboard standalone
is present).
- **Live E2E** against a running backend on `cl/hexclave-pr1`:
- `pnpm test run
apps/e2e/tests/backend/endpoints/api/v1/internal/mcp.test.ts` — **6/6
pass** (verifies the new `ask_hexclave` tool — the hand-written inline
snapshot matched actual MCP server output).
- `pnpm test run
apps/e2e/tests/backend/endpoints/api/v1/internal/projects.test.ts` —
**11/11 pass** (verifies wire dual-accept + dual-emit end-to-end; the
snapshot serializer fix was found and applied during this check).
A four-agent parallel **review pass** also audited the full diff for
logic/runtime bugs across the work-areas (wire headers + JWT, cookies +
bearer + symbols, env vars, query params + config + MCP + aliases). All
in-slice review verdicts were ✓ except the three bugs listed above,
which are now fixed.
## Known follow-ups (out of scope for this PR)
- **E2E snapshots across the rest of the suite** — backend now
dual-emits `x-hexclave-{known-error,actual-status}` alongside
`x-stack-*`, which legitimately appears in inline snapshots throughout
`apps/e2e`. Two were regenerated here as a sample; the rest should regen
with `vitest -u` in CI.
- **Docker shell env vars beyond `PORT_PREFIX`** — `entrypoint.sh` still
reads `STACK_*` env vars directly (the JS-side `getEnvVariable`
transform doesn't help the shell). JS consumers dual-read so it works in
practice; full shell-level dual-read is a deeper self-host follow-up.
- **`@stackframe/stack-cli` build ordering** — pre-existing; needs
`build:rde-standalone` first. Not affected by this PR.
## Test plan
- [ ] CI runs full e2e suite (with `vitest -u` to absorb dual-emit
snapshot deltas, then committed back)
- [ ] Spot-check: an old SDK build (emitting only `x-stack-*`) still
authenticates against the new backend
- [ ] Spot-check: a new SDK (emitting `x-hexclave-*` / `Bearer
hexclave_*`) still authenticates against an old backend during deploy
ordering
- [ ] Manual: `npx @stackframe/stack-cli@latest init` (new onboarding
entrypoint) generates `hexclave.config.ts`
- [ ] Manual: existing `stack.config.ts`-only project still resolves (no
migration required)
---------
Co-authored-by: bilal <bilal@stack-auth.com>
## Summary
- Forward Babel/JSX compile errors, runtime throws, and unhandled
rejections from the AI dashboard sandbox iframe to the parent composer
via `postMessage`, so users see actionable errors instead of a blank
preview
- Compile AI-generated dashboard source explicitly with
`Babel.transform` + try/catch (stored in `text/plain` to avoid Babel's
auto-handler swallowing parse errors) and add `crossorigin="anonymous"`
on the Babel script for readable cross-origin error messages
- Switch authenticated smart-tier model from
`moonshotai/kimi-k2.6:nitro` to `x-ai/grok-build-0.1`
## Test plan
- [ ] Generate a dashboard with valid AI code and confirm the preview
still renders
- [ ] Generate a dashboard with invalid JSX and confirm the composer
shows the compile error (not a blank iframe)
- [ ] Trigger a runtime error in generated dashboard code and confirm it
reaches the parent error boundary
- [ ] Verify authenticated smart-tier requests route to
`x-ai/grok-build-0.1`
Made with [Cursor](https://cursor.com)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Embedded dashboards now show a clear “Dashboard failed to compile”
message on compilation errors instead of a blank iframe.
* Dashboard runtime errors and unhandled promise rejections are captured
earlier and forwarded to the parent for improved visibility.
* **Updates**
* The authenticated AI model used for the "smart" quality has been
changed, affecting model selection for authenticated requests.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1476?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Add an admin-only delete endpoint and SDK method to remove managed
email domains, with Resend/DNSimple cleanup and a guard against deleting
domains currently in use for sending.
- Add dashboard UI to remove unused managed domains (with confirmation)
and improve the DNS setup step with Cloudflare detection, zone file
download, and import instructions.
- Add E2E coverage for delete auth, success, in-use rejection,
post-switch deletion, and 404 cases.
## Test plan
- [ ] Run `pnpm test run managed-email-onboarding`
- [ ] In dashboard email settings, add a managed domain and verify
Cloudflare hint appears when NS records point to Cloudflare
- [ ] Remove an unused managed domain and confirm it disappears from the
list
- [ ] Verify active (in-use) managed domains cannot be deleted until
email provider is switched away
Made with [Cursor](https://cursor.com)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Delete managed email domains from the dashboard with a confirmation
flow and success notification
* Cloudflare-aware domain setup: detection banner, quick links to
Cloudflare DNS, downloadable zone file, and import instructions
* Admin API and admin-app method to perform managed-domain deletion
* **Bug Fixes**
* Deletion blocked with a clear error when a domain is actively used for
sending
* **Tests**
* Added end-to-end coverage for managed-domain delete scenarios
(success, in-use conflict, auth rejection, and 404)
* **Style**
* Data grid layout adjusted to prevent unintended full-height stretching
across various tables
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1442?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
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
### Context
There was a small bug via dashboard checkout flow where it would fail on
trying to create a checkout flow for a free product subscription because
no client secret is generated for a 0 dollar subscription.
### Summary of Changes
The flow should be fine now. There's special carve out logic for it.
That being said, users attempting to mimic a free plan grant are
encouraged to follow the `ensureFreePlan` pattern.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Free subscription selections now bypass Stripe payment processing,
streamlining checkout for zero-cost offerings.
* Purchase return flow now properly recognizes and activates free
subscriptions without requiring payment confirmation.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1465?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
End-to-end flow for managing Stack Auth config via GitHub: link a repo
during onboarding, edit settings in the dashboard, and have the change
committed to your repo + synced back via a GitHub Actions workflow.

## What this adds
- **CLI** — `stack config push --source github --source-repo
--source-path --source-workflow-path`. Records the source on the config
row so the dashboard knows where the file lives. Reads `GITHUB_SHA` /
`GITHUB_REF_NAME` for commit + branch.
- **Onboarding "Link existing project"** — searchable repo/branch
comboboxes, auto-detects candidate `stack.config.{ts,js}` paths, writes
`STACK_AUTH_PROJECT_ID` + `STACK_AUTH_SECRET_SERVER_KEY` secrets, and
commits a generated workflow YAML that re-runs `stack config push` on
every change to the config file.
- **Dashboard "Push to GitHub" dialog** — replaces the prior TODO
buttons. Pre-flights `repo`+`workflow` scopes on the user's GitHub
connection; if missing, the button flips to "Reconnect with GitHub". On
push, commits the dashboard's edit straight to the linked repo/branch
via the Contents API (with `cache: "no-store"` to dodge GitHub's 60s GET
cache so consecutive pushes don't 409). Suspense boundary scoped to the
dialog body so opening it doesn't blank the dashboard.
- **Project settings** — surface the linked workflow file as a clickable
GitHub link when the source carries `workflow_path`.
## Test plan
- `pnpm lint` (29/29) ✓
- `pnpm typecheck` (29/29) ✓
- `pnpm --filter @stackframe/stack-cli test` (111/111) ✓
- Dashboard vitest on the three relevant files
(`link-existing-onboarding-workflow`, `github-api`,
`github-config-push`) — 37/37 ✓
- Live end-to-end: `BilalG1/lex-lookup` linked to a local dev project;
passkey toggled, push committed `0bb958bd`
([commit](0bb958bda3)).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Persist workflow file paths for GitHub-backed config sync
* Dashboard “Push” flow to commit config updates with trimmed/default
commit messages
* CLI options to declare GitHub source (repo/path/workflow) and persist
selectable package runner for manual pushes
* Show workflow-file link in project configuration when present
* **Improvements**
* Robust config-path normalization, existence checks, debounced
repo/branch search, and better GitHub rate-limit handling
* New GitHub API utilities for safe file read/commit and import-package
detection
* **Tests**
* Expanded tests covering GitHub API, config rendering/merge, and push
behaviors
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1450?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->