diff --git a/.github/assets/hexclave-rebrand-modal.png b/.github/assets/hexclave-rebrand-modal.png new file mode 100644 index 000000000..407961568 Binary files /dev/null and b/.github/assets/hexclave-rebrand-modal.png differ diff --git a/apps/dashboard/public/hexclave-icon.svg b/apps/dashboard/public/hexclave-icon.svg new file mode 100644 index 000000000..6954a8f3f --- /dev/null +++ b/apps/dashboard/public/hexclave-icon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/dashboard/public/logo-bright.svg b/apps/dashboard/public/logo-bright.svg index 7596871fe..553154975 100644 --- a/apps/dashboard/public/logo-bright.svg +++ b/apps/dashboard/public/logo-bright.svg @@ -1,3 +1,26 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/dashboard/public/logo-full-bright.svg b/apps/dashboard/public/logo-full-bright.svg index 16370cdc7..e00184c02 100644 --- a/apps/dashboard/public/logo-full-bright.svg +++ b/apps/dashboard/public/logo-full-bright.svg @@ -1,5 +1,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + Hexclave diff --git a/apps/dashboard/public/logo-full.svg b/apps/dashboard/public/logo-full.svg index 164e3e15a..d18208b97 100644 --- a/apps/dashboard/public/logo-full.svg +++ b/apps/dashboard/public/logo-full.svg @@ -1,5 +1,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + Hexclave diff --git a/apps/dashboard/public/logo.svg b/apps/dashboard/public/logo.svg index ba3a16fdb..553154975 100644 --- a/apps/dashboard/public/logo.svg +++ b/apps/dashboard/public/logo.svg @@ -1,3 +1,26 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/dashboard/public/open-graph-image.png b/apps/dashboard/public/open-graph-image.png index fac98410c..69afe8559 100644 Binary files a/apps/dashboard/public/open-graph-image.png and b/apps/dashboard/public/open-graph-image.png differ diff --git a/apps/dashboard/src/app/(main)/(protected)/layout-client.tsx b/apps/dashboard/src/app/(main)/(protected)/layout-client.tsx index bd5ccbd9f..45d6c815f 100644 --- a/apps/dashboard/src/app/(main)/(protected)/layout-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/layout-client.tsx @@ -3,6 +3,7 @@ import Loading from "@/app/loading"; import { CursorBlastEffect } from "@hexclave/dashboard-ui-components"; import { ConfigUpdateDialogProvider } from "@/lib/config-update"; +import { HexclaveRebrandModal } from "@/components/hexclave-rebrand-modal"; import { getPublicEnvVar } from '@/lib/env'; import { useStackApp, useUser } from "@hexclave/next"; import { LOCAL_EMULATOR_ADMIN_EMAIL, LOCAL_EMULATOR_ADMIN_PASSWORD } from "@hexclave/shared/dist/local-emulator"; @@ -60,6 +61,7 @@ export default function LayoutClient({ children }: { children: React.ReactNode } return ( + {children} ); diff --git a/apps/dashboard/src/app/favicon.ico b/apps/dashboard/src/app/favicon.ico index b2197e144..89769b5ff 100644 Binary files a/apps/dashboard/src/app/favicon.ico and b/apps/dashboard/src/app/favicon.ico differ diff --git a/apps/dashboard/src/components/hexclave-rebrand-modal.tsx b/apps/dashboard/src/components/hexclave-rebrand-modal.tsx new file mode 100644 index 000000000..b96ff01bc --- /dev/null +++ b/apps/dashboard/src/components/hexclave-rebrand-modal.tsx @@ -0,0 +1,207 @@ +"use client"; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { getPublicEnvVar } from "@/lib/env"; +import { useUser } from "@stackframe/stack"; +import Image from "next/image"; +import { useEffect, useState } from "react"; + +// Per-user dismissal flag. Keyed by user.id so a shared browser (e.g. a +// machine where two teammates each log into their own accounts) tracks the +// dismissal separately for each account — otherwise one teammate dismissing +// would silently hide the announcement from the other. +const STORAGE_KEY_PREFIX = "hexclave-rebrand-modal-dismissed:"; +const MIGRATION_DOCS_URL = "https://docs.hexclave.com/migration"; + +// Users who signed up before this instant predate the Stack Auth → Hexclave +// rebrand and are the only ones who benefit from the announcement. Anyone +// signing up after this already lands on a Hexclave-branded experience and +// has no "Stack Auth" mental model to update — no point telling them. +const REBRAND_CUTOFF = new Date("2026-05-27T00:00:00.000Z"); + +/** + * One-time informational modal announcing the Stack Auth → Hexclave rebrand. + * + * Skipped entirely in preview / local-emulator / remote-development environments + * — those auto-create throwaway users or seed a fixture admin, so the rebrand + * notice would be friction for developers and meaningless for preview visitors + * who never used "Stack Auth" in the first place. + * + * For real customers: only renders for a logged-in user who signed up before + * {@link REBRAND_CUTOFF}. On any dismissal (confirm button, close button, + * overlay click, or Escape) writes `${STORAGE_KEY_PREFIX}${user.id}` to + * localStorage so the modal never re-appears for that account on that browser. + */ +export function HexclaveRebrandModal() { + // Skip in dev/preview environments — same flags the protected layout already + // gates on. Read at top so we can short-circuit before any hook runs the + // useEffect or computes the user-based gate. + const isDevEnvironment = + getPublicEnvVar("NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR") === "true" + || getPublicEnvVar("NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT") === "true" + || getPublicEnvVar("NEXT_PUBLIC_STACK_IS_PREVIEW") === "true"; + + // `or: "return-null"` keeps this from triggering the sign-in redirect when + // it's rendered above the auth boundary — we simply opt out for guests. + const user = useUser({ or: "return-null" }); + const isPreRebrandUser = + !isDevEnvironment && user != null && user.signedUpAt < REBRAND_CUTOFF; + const [open, setOpen] = useState(false); + + // Per-user storage key. `null` when there's no user; the gates below + // ensure we never try to read/write it in that case. + const storageKey = user ? `${STORAGE_KEY_PREFIX}${user.id}` : null; + + // Read localStorage after hydration to avoid SSR mismatch — render closed + // on the server and only open if we know this user hasn't dismissed it. + useEffect(() => { + if (!isPreRebrandUser || !storageKey) return; + try { + const dismissed = localStorage.getItem(storageKey); + if (dismissed !== "true") { + setOpen(true); + } + } catch { + // localStorage can throw in private-mode / sandboxed iframes; treat + // unavailable storage as "already dismissed" so we don't spam users + // who can't persist the dismissal anyway. + } + }, [isPreRebrandUser, storageKey]); + + const dismiss = () => { + if (storageKey) { + try { + localStorage.setItem(storageKey, "true"); + } catch { + // see above — best-effort write + } + } + setOpen(false); + }; + + if (!isPreRebrandUser) return null; + + return ( + { + if (!next) dismiss(); + }} + > + + + + + Stack Auth is now Hexclave + + + We're rebranding! Same product, same team, new home at{" "} + + app.hexclave.com + + . To update your project, rename all{" "} + @stackframe/* imports to{" "} + @hexclave/* — the only + exception is{" "} + @stackframe/stack, which + becomes @hexclave/next. + See the{" "} + + migration guide + {" "} + for full details. + + + + + + + + ); +} + +/** + * Stack Auth mark (faded) → arrow → Hexclave benzene mark. Both logos are + * served from `/public` so they match the canonical brand assets. + */ +function RebrandIllustration() { + return ( + + ); +} diff --git a/apps/dev-launchpad/public/favicon.ico b/apps/dev-launchpad/public/favicon.ico index 099b1db65..89769b5ff 100644 Binary files a/apps/dev-launchpad/public/favicon.ico and b/apps/dev-launchpad/public/favicon.ico differ diff --git a/docs-mintlify/docs.json b/docs-mintlify/docs.json index d1a071932..41233d690 100644 --- a/docs-mintlify/docs.json +++ b/docs-mintlify/docs.json @@ -154,7 +154,7 @@ { "group": "Tutorials", "pages": [ - "guides/other/tutorials/build-a-saas-with-stack-auth", + "guides/other/tutorials/build-a-saas-with-hexclave", "guides/other/tutorials/build-a-team-based-app", "guides/other/tutorials/ship-production-ready-auth" ] diff --git a/docs-mintlify/guides/other/tutorials/build-a-saas-with-stack-auth.mdx b/docs-mintlify/guides/other/tutorials/build-a-saas-with-hexclave.mdx similarity index 100% rename from docs-mintlify/guides/other/tutorials/build-a-saas-with-stack-auth.mdx rename to docs-mintlify/guides/other/tutorials/build-a-saas-with-hexclave.mdx diff --git a/docs-mintlify/guides/other/tutorials/build-a-team-based-app.mdx b/docs-mintlify/guides/other/tutorials/build-a-team-based-app.mdx index 29aa237f5..967c580f1 100644 --- a/docs-mintlify/guides/other/tutorials/build-a-team-based-app.mdx +++ b/docs-mintlify/guides/other/tutorials/build-a-team-based-app.mdx @@ -5,7 +5,7 @@ description: Model B2B tenants as teams, wire team selection and deep links, enf This tutorial walks through a **multi-tenant** product where a **team** is the customer boundary (workspace, organization, account). You get membership-scoped team access, permission checks, team selection UX, and invitations. -If you have not installed Stack yet (handler routes, `HexclaveProvider`, environment variables), start with [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-stack-auth), then continue here. +If you have not installed Stack yet (handler routes, `HexclaveProvider`, environment variables), start with [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-hexclave), then continue here. ## What you will have at the end @@ -17,7 +17,7 @@ If you have not installed Stack yet (handler routes, `HexclaveProvider`, environ ## Prerequisites -- Hexclave installed as in [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-stack-auth) (Next.js App Router examples below assume `stackServerApp` in `stack/server.ts` and `@hexclave/next` in the app). +- Hexclave installed as in [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-hexclave) (Next.js App Router examples below assume `stackServerApp` in `stack/server.ts` and `@hexclave/next` in the app). - A project in the [dashboard](https://app.hexclave.com/projects) where you can edit **Teams** and **Team permissions**. @@ -356,7 +356,7 @@ Teams support `clientMetadata`, `serverMetadata`, and `clientReadOnlyMetadata` o | Topic | Guide | |--------|--------| -| Auth bootstrap and route protection | [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-stack-auth) | +| Auth bootstrap and route protection | [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-hexclave) | | Teams API reference | [Teams](/guides/apps/teams/overview) | | `SelectedTeamSwitcher` and URL strategies | [Team selection](/guides/apps/teams/team-selection) | | Permission modeling and nesting | [RBAC](/guides/apps/rbac/overview) | diff --git a/docs-mintlify/guides/other/tutorials/ship-production-ready-auth.mdx b/docs-mintlify/guides/other/tutorials/ship-production-ready-auth.mdx index 5580662d7..0653a7e88 100644 --- a/docs-mintlify/guides/other/tutorials/ship-production-ready-auth.mdx +++ b/docs-mintlify/guides/other/tutorials/ship-production-ready-auth.mdx @@ -5,7 +5,7 @@ description: Lock down page and API access, handle secrets and environments, the Going live is not only “turning on production mode.” This guide focuses on **what must be true** so only signed-in users reach protected surfaces, **secrets stay server-only**, and Stack’s dev-friendly defaults are replaced with **your** domains, OAuth apps, and email. -If you are still wiring Stack into your app, complete [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-stack-auth) first. For team RBAC before launch, see [Build a team-based app](/guides/other/tutorials/build-a-team-based-app). +If you are still wiring Stack into your app, complete [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-hexclave) first. For team RBAC before launch, see [Build a team-based app](/guides/other/tutorials/build-a-team-based-app). ## What you will have at the end @@ -153,7 +153,7 @@ If you consume Stack webhooks, **verify every payload** (for example with Svix a | Topic | Guide | |--------|--------| -| First integration | [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-stack-auth) | +| First integration | [Build a SaaS with Hexclave](/guides/other/tutorials/build-a-saas-with-hexclave) | | Page protection details | [User fundamentals](/guides/getting-started/user-fundamentals) | | Domains, OAuth, email, prod mode | [Launch checklist](/guides/apps/launch-checklist/overview) | | `HexclaveServerApp` and keys | [Stack App](/guides/going-further/stack-app) | diff --git a/docs-mintlify/images/favicon.ico b/docs-mintlify/images/favicon.ico index fed7c426b..89769b5ff 100644 Binary files a/docs-mintlify/images/favicon.ico and b/docs-mintlify/images/favicon.ico differ diff --git a/docs-mintlify/images/logo-dark.svg b/docs-mintlify/images/logo-dark.svg index 16370cdc7..e00184c02 100644 --- a/docs-mintlify/images/logo-dark.svg +++ b/docs-mintlify/images/logo-dark.svg @@ -1,5 +1,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + Hexclave diff --git a/docs-mintlify/images/logo-light.svg b/docs-mintlify/images/logo-light.svg index 46e3e45f4..d18208b97 100644 --- a/docs-mintlify/images/logo-light.svg +++ b/docs-mintlify/images/logo-light.svg @@ -1,5 +1,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + Hexclave diff --git a/examples/demo/public/logo-bright.svg b/examples/demo/public/logo-bright.svg index 16370cdc7..553154975 100644 --- a/examples/demo/public/logo-bright.svg +++ b/examples/demo/public/logo-bright.svg @@ -1,5 +1,26 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/demo/public/logo.svg b/examples/demo/public/logo.svg index 164e3e15a..553154975 100644 --- a/examples/demo/public/logo.svg +++ b/examples/demo/public/logo.svg @@ -1,5 +1,26 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/demo/src/app/layout.tsx b/examples/demo/src/app/layout.tsx index 6754a0ef4..979fe84cf 100644 --- a/examples/demo/src/app/layout.tsx +++ b/examples/demo/src/app/layout.tsx @@ -7,8 +7,8 @@ import { stackServerApp } from "src/stack"; import './global.css'; export const metadata: Metadata = { - title: 'Stack Demo', - description: 'Example of using Stack as your authentication system.', + title: 'Hexclave Demo', + description: 'Example of using Hexclave as your authentication system.', }; export default function RootLayout({ diff --git a/examples/demo/src/components/header.tsx b/examples/demo/src/components/header.tsx index ede8c59cb..1a04b8e49 100644 --- a/examples/demo/src/components/header.tsx +++ b/examples/demo/src/components/header.tsx @@ -17,7 +17,6 @@ export default function Header() { alt="Hexclave Logo" width={64} height={64} - className="dark:invert" /> Demo diff --git a/examples/docs-examples/src/app/layout.tsx b/examples/docs-examples/src/app/layout.tsx index e90ed3042..23d7c92cc 100644 --- a/examples/docs-examples/src/app/layout.tsx +++ b/examples/docs-examples/src/app/layout.tsx @@ -8,8 +8,8 @@ import './global.css'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { - title: 'Stack Demo', - description: 'Example of using Stack as your authentication system.', + title: 'Hexclave Docs Example', + description: 'Example of using Hexclave as your authentication system.', }; export default function RootLayout({ diff --git a/examples/middleware/src/app/layout.tsx b/examples/middleware/src/app/layout.tsx index 8f0ec35ee..86ce45dd8 100644 --- a/examples/middleware/src/app/layout.tsx +++ b/examples/middleware/src/app/layout.tsx @@ -7,7 +7,7 @@ const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Hexclave Middleware Demo", - description: "A demo of Stack's middleware capabilities.", + description: "A demo of Hexclave's middleware capabilities.", }; export default function RootLayout({ diff --git a/examples/tanstack-start-demo/src/components/header.tsx b/examples/tanstack-start-demo/src/components/header.tsx index 14d082f61..ac49c14cc 100644 --- a/examples/tanstack-start-demo/src/components/header.tsx +++ b/examples/tanstack-start-demo/src/components/header.tsx @@ -8,7 +8,7 @@ export function Header() {