feat(studio): TanStack app shell — root + auth/org routes (stack 3/6, from #46424) (#47112)

**Stack 3/6** of the TanStack Start migration (#46424). Stacked on
**#47110** (S2) → review that first; this PR's diff is the app shell.

> [!NOTE]
> Thin route wrappers that render the existing pages-router page
components through the compat shims (S2). Next is untouched — it builds
`pages/` and ignores `routes/`. The app doesn't function end-to-end on
TanStack until the API + project routes land (S4/S5) and the flag is
flipped.

## What's in this PR
- `routes/__root.tsx` — root layout + a `beforeLoad` that runs the
shared redirect rules; `router.tsx`.
- `routes/_auth/*` — sign-in/up, forgot/reset password, SSO/MFA/partner
sign-in, CLI login, Stripe-projects login.
- `routes/_app/*` — account (me/security/audit/tokens), `org/$slug/*`
(general/billing/team/usage/…), support.
- `routeTree.gen.ts` — **regenerated** by the tanstackStart vite plugin
for exactly the routes in this PR (the migration branch's tree
references all ~300 routes, so it can't be copied verbatim here). It's a
generated artifact; the meaningful review surface is the route files.

## Verification
On top of S1+S2: `studio` typecheck ✓, lint (0 errors) ✓.


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

* **Refactor**
* Enhanced internal routing infrastructure to improve application
performance and code organization. These behind-the-scenes updates
ensure a more stable and maintainable foundation for the platform
without affecting existing functionality or user experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-06-29 14:08:26 +02:00
1 parent e938016141
commit 3d931aceb7
40 files changed
+1985

No files matched your search

+850
View File
@@ -0,0 +1,850 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root'
import { Route as AuthSignUpRouteImport } from './routes/_auth/sign-up'
import { Route as AuthSignInSsoRouteImport } from './routes/_auth/sign-in-sso'
import { Route as AuthSignInPartnerRouteImport } from './routes/_auth/sign-in-partner'
import { Route as AuthSignInMfaRouteImport } from './routes/_auth/sign-in-mfa'
import { Route as AuthSignInRouteImport } from './routes/_auth/sign-in'
import { Route as AuthResetPasswordRouteImport } from './routes/_auth/reset-password'
import { Route as AuthForgotPasswordMfaRouteImport } from './routes/_auth/forgot-password-mfa'
import { Route as AuthForgotPasswordRouteImport } from './routes/_auth/forgot-password'
import { Route as AppOrganizationsRouteImport } from './routes/_app/organizations'
import { Route as AppOrgRouteImport } from './routes/_app/org'
import { Route as AppAccountRouteImport } from './routes/_app/account'
import { Route as AppOrgIndexRouteImport } from './routes/_app/org/index'
import { Route as AppNewIndexRouteImport } from './routes/_app/new/index'
import { Route as AuthCliLoginRouteImport } from './routes/_auth/cli/login'
import { Route as AppSupportNewRouteImport } from './routes/_app/support/new'
import { Route as AppSupportLinkRouteImport } from './routes/_app/support/link'
import { Route as AppAccountSecurityRouteImport } from './routes/_app/account/security'
import { Route as AppAccountMeRouteImport } from './routes/_app/account/me'
import { Route as AppAccountAuditRouteImport } from './routes/_app/account/audit'
import { Route as AppOrgSlugIndexRouteImport } from './routes/_app/org/$slug/index'
import { Route as AppAccountTokensIndexRouteImport } from './routes/_app/account/tokens/index'
import { Route as AppOrgSlugUsageRouteImport } from './routes/_app/org/$slug/usage'
import { Route as AppOrgSlugTeamRouteImport } from './routes/_app/org/$slug/team'
import { Route as AppOrgSlugSsoRouteImport } from './routes/_app/org/$slug/sso'
import { Route as AppOrgSlugSecurityRouteImport } from './routes/_app/org/$slug/security'
import { Route as AppOrgSlugIntegrationsRouteImport } from './routes/_app/org/$slug/integrations'
import { Route as AppOrgSlugGeneralRouteImport } from './routes/_app/org/$slug/general'
import { Route as AppOrgSlugDocumentsRouteImport } from './routes/_app/org/$slug/documents'
import { Route as AppOrgSlugBillingRouteImport } from './routes/_app/org/$slug/billing'
import { Route as AppOrgSlugAuditLogDrainsRouteImport } from './routes/_app/org/$slug/audit-log-drains'
import { Route as AppOrgSlugAuditRouteImport } from './routes/_app/org/$slug/audit'
import { Route as AppOrgSlugAppsRouteImport } from './routes/_app/org/$slug/apps'
import { Route as AppAccountTokensScopedRouteImport } from './routes/_app/account/tokens/scoped'
import { Route as AppOrgSlugWebhooksIndexRouteImport } from './routes/_app/org/$slug/webhooks/index'
import { Route as AppOrgSlugPrivateAppsIndexRouteImport } from './routes/_app/org/$slug/private-apps/index'
import { Route as AuthPartnersStripeProjectsLoginRouteImport } from './routes/_auth/partners/stripe/projects/login'
import { Route as AppOrgSlugWebhooksEndpointIdRouteImport } from './routes/_app/org/$slug/webhooks/$endpointId'
const AuthSignUpRoute = AuthSignUpRouteImport.update({
id: '/_auth/sign-up',
path: '/sign-up',
getParentRoute: () => rootRouteImport,
} as any)
const AuthSignInSsoRoute = AuthSignInSsoRouteImport.update({
id: '/_auth/sign-in-sso',
path: '/sign-in-sso',
getParentRoute: () => rootRouteImport,
} as any)
const AuthSignInPartnerRoute = AuthSignInPartnerRouteImport.update({
id: '/_auth/sign-in-partner',
path: '/sign-in-partner',
getParentRoute: () => rootRouteImport,
} as any)
const AuthSignInMfaRoute = AuthSignInMfaRouteImport.update({
id: '/_auth/sign-in-mfa',
path: '/sign-in-mfa',
getParentRoute: () => rootRouteImport,
} as any)
const AuthSignInRoute = AuthSignInRouteImport.update({
id: '/_auth/sign-in',
path: '/sign-in',
getParentRoute: () => rootRouteImport,
} as any)
const AuthResetPasswordRoute = AuthResetPasswordRouteImport.update({
id: '/_auth/reset-password',
path: '/reset-password',
getParentRoute: () => rootRouteImport,
} as any)
const AuthForgotPasswordMfaRoute = AuthForgotPasswordMfaRouteImport.update({
id: '/_auth/forgot-password-mfa',
path: '/forgot-password-mfa',
getParentRoute: () => rootRouteImport,
} as any)
const AuthForgotPasswordRoute = AuthForgotPasswordRouteImport.update({
id: '/_auth/forgot-password',
path: '/forgot-password',
getParentRoute: () => rootRouteImport,
} as any)
const AppOrganizationsRoute = AppOrganizationsRouteImport.update({
id: '/_app/organizations',
path: '/organizations',
getParentRoute: () => rootRouteImport,
} as any)
const AppOrgRoute = AppOrgRouteImport.update({
id: '/_app/org',
path: '/org',
getParentRoute: () => rootRouteImport,
} as any)
const AppAccountRoute = AppAccountRouteImport.update({
id: '/_app/account',
path: '/account',
getParentRoute: () => rootRouteImport,
} as any)
const AppOrgIndexRoute = AppOrgIndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => AppOrgRoute,
} as any)
const AppNewIndexRoute = AppNewIndexRouteImport.update({
id: '/_app/new/',
path: '/new/',
getParentRoute: () => rootRouteImport,
} as any)
const AuthCliLoginRoute = AuthCliLoginRouteImport.update({
id: '/_auth/cli/login',
path: '/cli/login',
getParentRoute: () => rootRouteImport,
} as any)
const AppSupportNewRoute = AppSupportNewRouteImport.update({
id: '/_app/support/new',
path: '/support/new',
getParentRoute: () => rootRouteImport,
} as any)
const AppSupportLinkRoute = AppSupportLinkRouteImport.update({
id: '/_app/support/link',
path: '/support/link',
getParentRoute: () => rootRouteImport,
} as any)
const AppAccountSecurityRoute = AppAccountSecurityRouteImport.update({
id: '/security',
path: '/security',
getParentRoute: () => AppAccountRoute,
} as any)
const AppAccountMeRoute = AppAccountMeRouteImport.update({
id: '/me',
path: '/me',
getParentRoute: () => AppAccountRoute,
} as any)
const AppAccountAuditRoute = AppAccountAuditRouteImport.update({
id: '/audit',
path: '/audit',
getParentRoute: () => AppAccountRoute,
} as any)
const AppOrgSlugIndexRoute = AppOrgSlugIndexRouteImport.update({
id: '/$slug/',
path: '/$slug/',
getParentRoute: () => AppOrgRoute,
} as any)
const AppAccountTokensIndexRoute = AppAccountTokensIndexRouteImport.update({
id: '/tokens/',
path: '/tokens/',
getParentRoute: () => AppAccountRoute,
} as any)
const AppOrgSlugUsageRoute = AppOrgSlugUsageRouteImport.update({
id: '/$slug/usage',
path: '/$slug/usage',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugTeamRoute = AppOrgSlugTeamRouteImport.update({
id: '/$slug/team',
path: '/$slug/team',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugSsoRoute = AppOrgSlugSsoRouteImport.update({
id: '/$slug/sso',
path: '/$slug/sso',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugSecurityRoute = AppOrgSlugSecurityRouteImport.update({
id: '/$slug/security',
path: '/$slug/security',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugIntegrationsRoute = AppOrgSlugIntegrationsRouteImport.update({
id: '/$slug/integrations',
path: '/$slug/integrations',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugGeneralRoute = AppOrgSlugGeneralRouteImport.update({
id: '/$slug/general',
path: '/$slug/general',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugDocumentsRoute = AppOrgSlugDocumentsRouteImport.update({
id: '/$slug/documents',
path: '/$slug/documents',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugBillingRoute = AppOrgSlugBillingRouteImport.update({
id: '/$slug/billing',
path: '/$slug/billing',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugAuditLogDrainsRoute =
AppOrgSlugAuditLogDrainsRouteImport.update({
id: '/$slug/audit-log-drains',
path: '/$slug/audit-log-drains',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugAuditRoute = AppOrgSlugAuditRouteImport.update({
id: '/$slug/audit',
path: '/$slug/audit',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugAppsRoute = AppOrgSlugAppsRouteImport.update({
id: '/$slug/apps',
path: '/$slug/apps',
getParentRoute: () => AppOrgRoute,
} as any)
const AppAccountTokensScopedRoute = AppAccountTokensScopedRouteImport.update({
id: '/tokens/scoped',
path: '/tokens/scoped',
getParentRoute: () => AppAccountRoute,
} as any)
const AppOrgSlugWebhooksIndexRoute = AppOrgSlugWebhooksIndexRouteImport.update({
id: '/$slug/webhooks/',
path: '/$slug/webhooks/',
getParentRoute: () => AppOrgRoute,
} as any)
const AppOrgSlugPrivateAppsIndexRoute =
AppOrgSlugPrivateAppsIndexRouteImport.update({
id: '/$slug/private-apps/',
path: '/$slug/private-apps/',
getParentRoute: () => AppOrgRoute,
} as any)
const AuthPartnersStripeProjectsLoginRoute =
AuthPartnersStripeProjectsLoginRouteImport.update({
id: '/_auth/partners/stripe/projects/login',
path: '/partners/stripe/projects/login',
getParentRoute: () => rootRouteImport,
} as any)
const AppOrgSlugWebhooksEndpointIdRoute =
AppOrgSlugWebhooksEndpointIdRouteImport.update({
id: '/$slug/webhooks/$endpointId',
path: '/$slug/webhooks/$endpointId',
getParentRoute: () => AppOrgRoute,
} as any)
export interface FileRoutesByFullPath {
'/account': typeof AppAccountRouteWithChildren
'/org': typeof AppOrgRouteWithChildren
'/organizations': typeof AppOrganizationsRoute
'/forgot-password': typeof AuthForgotPasswordRoute
'/forgot-password-mfa': typeof AuthForgotPasswordMfaRoute
'/reset-password': typeof AuthResetPasswordRoute
'/sign-in': typeof AuthSignInRoute
'/sign-in-mfa': typeof AuthSignInMfaRoute
'/sign-in-partner': typeof AuthSignInPartnerRoute
'/sign-in-sso': typeof AuthSignInSsoRoute
'/sign-up': typeof AuthSignUpRoute
'/account/audit': typeof AppAccountAuditRoute
'/account/me': typeof AppAccountMeRoute
'/account/security': typeof AppAccountSecurityRoute
'/support/link': typeof AppSupportLinkRoute
'/support/new': typeof AppSupportNewRoute
'/cli/login': typeof AuthCliLoginRoute
'/new/': typeof AppNewIndexRoute
'/org/': typeof AppOrgIndexRoute
'/account/tokens/scoped': typeof AppAccountTokensScopedRoute
'/org/$slug/apps': typeof AppOrgSlugAppsRoute
'/org/$slug/audit': typeof AppOrgSlugAuditRoute
'/org/$slug/audit-log-drains': typeof AppOrgSlugAuditLogDrainsRoute
'/org/$slug/billing': typeof AppOrgSlugBillingRoute
'/org/$slug/documents': typeof AppOrgSlugDocumentsRoute
'/org/$slug/general': typeof AppOrgSlugGeneralRoute
'/org/$slug/integrations': typeof AppOrgSlugIntegrationsRoute
'/org/$slug/security': typeof AppOrgSlugSecurityRoute
'/org/$slug/sso': typeof AppOrgSlugSsoRoute
'/org/$slug/team': typeof AppOrgSlugTeamRoute
'/org/$slug/usage': typeof AppOrgSlugUsageRoute
'/account/tokens/': typeof AppAccountTokensIndexRoute
'/org/$slug/': typeof AppOrgSlugIndexRoute
'/org/$slug/webhooks/$endpointId': typeof AppOrgSlugWebhooksEndpointIdRoute
'/partners/stripe/projects/login': typeof AuthPartnersStripeProjectsLoginRoute
'/org/$slug/private-apps/': typeof AppOrgSlugPrivateAppsIndexRoute
'/org/$slug/webhooks/': typeof AppOrgSlugWebhooksIndexRoute
}
export interface FileRoutesByTo {
'/account': typeof AppAccountRouteWithChildren
'/organizations': typeof AppOrganizationsRoute
'/forgot-password': typeof AuthForgotPasswordRoute
'/forgot-password-mfa': typeof AuthForgotPasswordMfaRoute
'/reset-password': typeof AuthResetPasswordRoute
'/sign-in': typeof AuthSignInRoute
'/sign-in-mfa': typeof AuthSignInMfaRoute
'/sign-in-partner': typeof AuthSignInPartnerRoute
'/sign-in-sso': typeof AuthSignInSsoRoute
'/sign-up': typeof AuthSignUpRoute
'/account/audit': typeof AppAccountAuditRoute
'/account/me': typeof AppAccountMeRoute
'/account/security': typeof AppAccountSecurityRoute
'/support/link': typeof AppSupportLinkRoute
'/support/new': typeof AppSupportNewRoute
'/cli/login': typeof AuthCliLoginRoute
'/new': typeof AppNewIndexRoute
'/org': typeof AppOrgIndexRoute
'/account/tokens/scoped': typeof AppAccountTokensScopedRoute
'/org/$slug/apps': typeof AppOrgSlugAppsRoute
'/org/$slug/audit': typeof AppOrgSlugAuditRoute
'/org/$slug/audit-log-drains': typeof AppOrgSlugAuditLogDrainsRoute
'/org/$slug/billing': typeof AppOrgSlugBillingRoute
'/org/$slug/documents': typeof AppOrgSlugDocumentsRoute
'/org/$slug/general': typeof AppOrgSlugGeneralRoute
'/org/$slug/integrations': typeof AppOrgSlugIntegrationsRoute
'/org/$slug/security': typeof AppOrgSlugSecurityRoute
'/org/$slug/sso': typeof AppOrgSlugSsoRoute
'/org/$slug/team': typeof AppOrgSlugTeamRoute
'/org/$slug/usage': typeof AppOrgSlugUsageRoute
'/account/tokens': typeof AppAccountTokensIndexRoute
'/org/$slug': typeof AppOrgSlugIndexRoute
'/org/$slug/webhooks/$endpointId': typeof AppOrgSlugWebhooksEndpointIdRoute
'/partners/stripe/projects/login': typeof AuthPartnersStripeProjectsLoginRoute
'/org/$slug/private-apps': typeof AppOrgSlugPrivateAppsIndexRoute
'/org/$slug/webhooks': typeof AppOrgSlugWebhooksIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/_app/account': typeof AppAccountRouteWithChildren
'/_app/org': typeof AppOrgRouteWithChildren
'/_app/organizations': typeof AppOrganizationsRoute
'/_auth/forgot-password': typeof AuthForgotPasswordRoute
'/_auth/forgot-password-mfa': typeof AuthForgotPasswordMfaRoute
'/_auth/reset-password': typeof AuthResetPasswordRoute
'/_auth/sign-in': typeof AuthSignInRoute
'/_auth/sign-in-mfa': typeof AuthSignInMfaRoute
'/_auth/sign-in-partner': typeof AuthSignInPartnerRoute
'/_auth/sign-in-sso': typeof AuthSignInSsoRoute
'/_auth/sign-up': typeof AuthSignUpRoute
'/_app/account/audit': typeof AppAccountAuditRoute
'/_app/account/me': typeof AppAccountMeRoute
'/_app/account/security': typeof AppAccountSecurityRoute
'/_app/support/link': typeof AppSupportLinkRoute
'/_app/support/new': typeof AppSupportNewRoute
'/_auth/cli/login': typeof AuthCliLoginRoute
'/_app/new/': typeof AppNewIndexRoute
'/_app/org/': typeof AppOrgIndexRoute
'/_app/account/tokens/scoped': typeof AppAccountTokensScopedRoute
'/_app/org/$slug/apps': typeof AppOrgSlugAppsRoute
'/_app/org/$slug/audit': typeof AppOrgSlugAuditRoute
'/_app/org/$slug/audit-log-drains': typeof AppOrgSlugAuditLogDrainsRoute
'/_app/org/$slug/billing': typeof AppOrgSlugBillingRoute
'/_app/org/$slug/documents': typeof AppOrgSlugDocumentsRoute
'/_app/org/$slug/general': typeof AppOrgSlugGeneralRoute
'/_app/org/$slug/integrations': typeof AppOrgSlugIntegrationsRoute
'/_app/org/$slug/security': typeof AppOrgSlugSecurityRoute
'/_app/org/$slug/sso': typeof AppOrgSlugSsoRoute
'/_app/org/$slug/team': typeof AppOrgSlugTeamRoute
'/_app/org/$slug/usage': typeof AppOrgSlugUsageRoute
'/_app/account/tokens/': typeof AppAccountTokensIndexRoute
'/_app/org/$slug/': typeof AppOrgSlugIndexRoute
'/_app/org/$slug/webhooks/$endpointId': typeof AppOrgSlugWebhooksEndpointIdRoute
'/_auth/partners/stripe/projects/login': typeof AuthPartnersStripeProjectsLoginRoute
'/_app/org/$slug/private-apps/': typeof AppOrgSlugPrivateAppsIndexRoute
'/_app/org/$slug/webhooks/': typeof AppOrgSlugWebhooksIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/account'
| '/org'
| '/organizations'
| '/forgot-password'
| '/forgot-password-mfa'
| '/reset-password'
| '/sign-in'
| '/sign-in-mfa'
| '/sign-in-partner'
| '/sign-in-sso'
| '/sign-up'
| '/account/audit'
| '/account/me'
| '/account/security'
| '/support/link'
| '/support/new'
| '/cli/login'
| '/new/'
| '/org/'
| '/account/tokens/scoped'
| '/org/$slug/apps'
| '/org/$slug/audit'
| '/org/$slug/audit-log-drains'
| '/org/$slug/billing'
| '/org/$slug/documents'
| '/org/$slug/general'
| '/org/$slug/integrations'
| '/org/$slug/security'
| '/org/$slug/sso'
| '/org/$slug/team'
| '/org/$slug/usage'
| '/account/tokens/'
| '/org/$slug/'
| '/org/$slug/webhooks/$endpointId'
| '/partners/stripe/projects/login'
| '/org/$slug/private-apps/'
| '/org/$slug/webhooks/'
fileRoutesByTo: FileRoutesByTo
to:
| '/account'
| '/organizations'
| '/forgot-password'
| '/forgot-password-mfa'
| '/reset-password'
| '/sign-in'
| '/sign-in-mfa'
| '/sign-in-partner'
| '/sign-in-sso'
| '/sign-up'
| '/account/audit'
| '/account/me'
| '/account/security'
| '/support/link'
| '/support/new'
| '/cli/login'
| '/new'
| '/org'
| '/account/tokens/scoped'
| '/org/$slug/apps'
| '/org/$slug/audit'
| '/org/$slug/audit-log-drains'
| '/org/$slug/billing'
| '/org/$slug/documents'
| '/org/$slug/general'
| '/org/$slug/integrations'
| '/org/$slug/security'
| '/org/$slug/sso'
| '/org/$slug/team'
| '/org/$slug/usage'
| '/account/tokens'
| '/org/$slug'
| '/org/$slug/webhooks/$endpointId'
| '/partners/stripe/projects/login'
| '/org/$slug/private-apps'
| '/org/$slug/webhooks'
id:
| '__root__'
| '/_app/account'
| '/_app/org'
| '/_app/organizations'
| '/_auth/forgot-password'
| '/_auth/forgot-password-mfa'
| '/_auth/reset-password'
| '/_auth/sign-in'
| '/_auth/sign-in-mfa'
| '/_auth/sign-in-partner'
| '/_auth/sign-in-sso'
| '/_auth/sign-up'
| '/_app/account/audit'
| '/_app/account/me'
| '/_app/account/security'
| '/_app/support/link'
| '/_app/support/new'
| '/_auth/cli/login'
| '/_app/new/'
| '/_app/org/'
| '/_app/account/tokens/scoped'
| '/_app/org/$slug/apps'
| '/_app/org/$slug/audit'
| '/_app/org/$slug/audit-log-drains'
| '/_app/org/$slug/billing'
| '/_app/org/$slug/documents'
| '/_app/org/$slug/general'
| '/_app/org/$slug/integrations'
| '/_app/org/$slug/security'
| '/_app/org/$slug/sso'
| '/_app/org/$slug/team'
| '/_app/org/$slug/usage'
| '/_app/account/tokens/'
| '/_app/org/$slug/'
| '/_app/org/$slug/webhooks/$endpointId'
| '/_auth/partners/stripe/projects/login'
| '/_app/org/$slug/private-apps/'
| '/_app/org/$slug/webhooks/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
AppAccountRoute: typeof AppAccountRouteWithChildren
AppOrgRoute: typeof AppOrgRouteWithChildren
AppOrganizationsRoute: typeof AppOrganizationsRoute
AuthForgotPasswordRoute: typeof AuthForgotPasswordRoute
AuthForgotPasswordMfaRoute: typeof AuthForgotPasswordMfaRoute
AuthResetPasswordRoute: typeof AuthResetPasswordRoute
AuthSignInRoute: typeof AuthSignInRoute
AuthSignInMfaRoute: typeof AuthSignInMfaRoute
AuthSignInPartnerRoute: typeof AuthSignInPartnerRoute
AuthSignInSsoRoute: typeof AuthSignInSsoRoute
AuthSignUpRoute: typeof AuthSignUpRoute
AppSupportLinkRoute: typeof AppSupportLinkRoute
AppSupportNewRoute: typeof AppSupportNewRoute
AuthCliLoginRoute: typeof AuthCliLoginRoute
AppNewIndexRoute: typeof AppNewIndexRoute
AuthPartnersStripeProjectsLoginRoute: typeof AuthPartnersStripeProjectsLoginRoute
}
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/_auth/sign-up': {
id: '/_auth/sign-up'
path: '/sign-up'
fullPath: '/sign-up'
preLoaderRoute: typeof AuthSignUpRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/sign-in-sso': {
id: '/_auth/sign-in-sso'
path: '/sign-in-sso'
fullPath: '/sign-in-sso'
preLoaderRoute: typeof AuthSignInSsoRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/sign-in-partner': {
id: '/_auth/sign-in-partner'
path: '/sign-in-partner'
fullPath: '/sign-in-partner'
preLoaderRoute: typeof AuthSignInPartnerRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/sign-in-mfa': {
id: '/_auth/sign-in-mfa'
path: '/sign-in-mfa'
fullPath: '/sign-in-mfa'
preLoaderRoute: typeof AuthSignInMfaRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/sign-in': {
id: '/_auth/sign-in'
path: '/sign-in'
fullPath: '/sign-in'
preLoaderRoute: typeof AuthSignInRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/reset-password': {
id: '/_auth/reset-password'
path: '/reset-password'
fullPath: '/reset-password'
preLoaderRoute: typeof AuthResetPasswordRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/forgot-password-mfa': {
id: '/_auth/forgot-password-mfa'
path: '/forgot-password-mfa'
fullPath: '/forgot-password-mfa'
preLoaderRoute: typeof AuthForgotPasswordMfaRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/forgot-password': {
id: '/_auth/forgot-password'
path: '/forgot-password'
fullPath: '/forgot-password'
preLoaderRoute: typeof AuthForgotPasswordRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/organizations': {
id: '/_app/organizations'
path: '/organizations'
fullPath: '/organizations'
preLoaderRoute: typeof AppOrganizationsRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/org': {
id: '/_app/org'
path: '/org'
fullPath: '/org'
preLoaderRoute: typeof AppOrgRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/account': {
id: '/_app/account'
path: '/account'
fullPath: '/account'
preLoaderRoute: typeof AppAccountRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/org/': {
id: '/_app/org/'
path: '/'
fullPath: '/org/'
preLoaderRoute: typeof AppOrgIndexRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/new/': {
id: '/_app/new/'
path: '/new'
fullPath: '/new/'
preLoaderRoute: typeof AppNewIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/cli/login': {
id: '/_auth/cli/login'
path: '/cli/login'
fullPath: '/cli/login'
preLoaderRoute: typeof AuthCliLoginRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/support/new': {
id: '/_app/support/new'
path: '/support/new'
fullPath: '/support/new'
preLoaderRoute: typeof AppSupportNewRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/support/link': {
id: '/_app/support/link'
path: '/support/link'
fullPath: '/support/link'
preLoaderRoute: typeof AppSupportLinkRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/account/security': {
id: '/_app/account/security'
path: '/security'
fullPath: '/account/security'
preLoaderRoute: typeof AppAccountSecurityRouteImport
parentRoute: typeof AppAccountRoute
}
'/_app/account/me': {
id: '/_app/account/me'
path: '/me'
fullPath: '/account/me'
preLoaderRoute: typeof AppAccountMeRouteImport
parentRoute: typeof AppAccountRoute
}
'/_app/account/audit': {
id: '/_app/account/audit'
path: '/audit'
fullPath: '/account/audit'
preLoaderRoute: typeof AppAccountAuditRouteImport
parentRoute: typeof AppAccountRoute
}
'/_app/org/$slug/': {
id: '/_app/org/$slug/'
path: '/$slug'
fullPath: '/org/$slug/'
preLoaderRoute: typeof AppOrgSlugIndexRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/account/tokens/': {
id: '/_app/account/tokens/'
path: '/tokens'
fullPath: '/account/tokens/'
preLoaderRoute: typeof AppAccountTokensIndexRouteImport
parentRoute: typeof AppAccountRoute
}
'/_app/org/$slug/usage': {
id: '/_app/org/$slug/usage'
path: '/$slug/usage'
fullPath: '/org/$slug/usage'
preLoaderRoute: typeof AppOrgSlugUsageRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/team': {
id: '/_app/org/$slug/team'
path: '/$slug/team'
fullPath: '/org/$slug/team'
preLoaderRoute: typeof AppOrgSlugTeamRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/sso': {
id: '/_app/org/$slug/sso'
path: '/$slug/sso'
fullPath: '/org/$slug/sso'
preLoaderRoute: typeof AppOrgSlugSsoRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/security': {
id: '/_app/org/$slug/security'
path: '/$slug/security'
fullPath: '/org/$slug/security'
preLoaderRoute: typeof AppOrgSlugSecurityRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/integrations': {
id: '/_app/org/$slug/integrations'
path: '/$slug/integrations'
fullPath: '/org/$slug/integrations'
preLoaderRoute: typeof AppOrgSlugIntegrationsRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/general': {
id: '/_app/org/$slug/general'
path: '/$slug/general'
fullPath: '/org/$slug/general'
preLoaderRoute: typeof AppOrgSlugGeneralRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/documents': {
id: '/_app/org/$slug/documents'
path: '/$slug/documents'
fullPath: '/org/$slug/documents'
preLoaderRoute: typeof AppOrgSlugDocumentsRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/billing': {
id: '/_app/org/$slug/billing'
path: '/$slug/billing'
fullPath: '/org/$slug/billing'
preLoaderRoute: typeof AppOrgSlugBillingRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/audit-log-drains': {
id: '/_app/org/$slug/audit-log-drains'
path: '/$slug/audit-log-drains'
fullPath: '/org/$slug/audit-log-drains'
preLoaderRoute: typeof AppOrgSlugAuditLogDrainsRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/audit': {
id: '/_app/org/$slug/audit'
path: '/$slug/audit'
fullPath: '/org/$slug/audit'
preLoaderRoute: typeof AppOrgSlugAuditRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/apps': {
id: '/_app/org/$slug/apps'
path: '/$slug/apps'
fullPath: '/org/$slug/apps'
preLoaderRoute: typeof AppOrgSlugAppsRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/account/tokens/scoped': {
id: '/_app/account/tokens/scoped'
path: '/tokens/scoped'
fullPath: '/account/tokens/scoped'
preLoaderRoute: typeof AppAccountTokensScopedRouteImport
parentRoute: typeof AppAccountRoute
}
'/_app/org/$slug/webhooks/': {
id: '/_app/org/$slug/webhooks/'
path: '/$slug/webhooks'
fullPath: '/org/$slug/webhooks/'
preLoaderRoute: typeof AppOrgSlugWebhooksIndexRouteImport
parentRoute: typeof AppOrgRoute
}
'/_app/org/$slug/private-apps/': {
id: '/_app/org/$slug/private-apps/'
path: '/$slug/private-apps'
fullPath: '/org/$slug/private-apps/'
preLoaderRoute: typeof AppOrgSlugPrivateAppsIndexRouteImport
parentRoute: typeof AppOrgRoute
}
'/_auth/partners/stripe/projects/login': {
id: '/_auth/partners/stripe/projects/login'
path: '/partners/stripe/projects/login'
fullPath: '/partners/stripe/projects/login'
preLoaderRoute: typeof AuthPartnersStripeProjectsLoginRouteImport
parentRoute: typeof rootRouteImport
}
'/_app/org/$slug/webhooks/$endpointId': {
id: '/_app/org/$slug/webhooks/$endpointId'
path: '/$slug/webhooks/$endpointId'
fullPath: '/org/$slug/webhooks/$endpointId'
preLoaderRoute: typeof AppOrgSlugWebhooksEndpointIdRouteImport
parentRoute: typeof AppOrgRoute
}
}
}
interface AppAccountRouteChildren {
AppAccountAuditRoute: typeof AppAccountAuditRoute
AppAccountMeRoute: typeof AppAccountMeRoute
AppAccountSecurityRoute: typeof AppAccountSecurityRoute
AppAccountTokensScopedRoute: typeof AppAccountTokensScopedRoute
AppAccountTokensIndexRoute: typeof AppAccountTokensIndexRoute
}
const AppAccountRouteChildren: AppAccountRouteChildren = {
AppAccountAuditRoute: AppAccountAuditRoute,
AppAccountMeRoute: AppAccountMeRoute,
AppAccountSecurityRoute: AppAccountSecurityRoute,
AppAccountTokensScopedRoute: AppAccountTokensScopedRoute,
AppAccountTokensIndexRoute: AppAccountTokensIndexRoute,
}
const AppAccountRouteWithChildren = AppAccountRoute._addFileChildren(
AppAccountRouteChildren,
)
interface AppOrgRouteChildren {
AppOrgIndexRoute: typeof AppOrgIndexRoute
AppOrgSlugAppsRoute: typeof AppOrgSlugAppsRoute
AppOrgSlugAuditRoute: typeof AppOrgSlugAuditRoute
AppOrgSlugAuditLogDrainsRoute: typeof AppOrgSlugAuditLogDrainsRoute
AppOrgSlugBillingRoute: typeof AppOrgSlugBillingRoute
AppOrgSlugDocumentsRoute: typeof AppOrgSlugDocumentsRoute
AppOrgSlugGeneralRoute: typeof AppOrgSlugGeneralRoute
AppOrgSlugIntegrationsRoute: typeof AppOrgSlugIntegrationsRoute
AppOrgSlugSecurityRoute: typeof AppOrgSlugSecurityRoute
AppOrgSlugSsoRoute: typeof AppOrgSlugSsoRoute
AppOrgSlugTeamRoute: typeof AppOrgSlugTeamRoute
AppOrgSlugUsageRoute: typeof AppOrgSlugUsageRoute
AppOrgSlugIndexRoute: typeof AppOrgSlugIndexRoute
AppOrgSlugWebhooksEndpointIdRoute: typeof AppOrgSlugWebhooksEndpointIdRoute
AppOrgSlugPrivateAppsIndexRoute: typeof AppOrgSlugPrivateAppsIndexRoute
AppOrgSlugWebhooksIndexRoute: typeof AppOrgSlugWebhooksIndexRoute
}
const AppOrgRouteChildren: AppOrgRouteChildren = {
AppOrgIndexRoute: AppOrgIndexRoute,
AppOrgSlugAppsRoute: AppOrgSlugAppsRoute,
AppOrgSlugAuditRoute: AppOrgSlugAuditRoute,
AppOrgSlugAuditLogDrainsRoute: AppOrgSlugAuditLogDrainsRoute,
AppOrgSlugBillingRoute: AppOrgSlugBillingRoute,
AppOrgSlugDocumentsRoute: AppOrgSlugDocumentsRoute,
AppOrgSlugGeneralRoute: AppOrgSlugGeneralRoute,
AppOrgSlugIntegrationsRoute: AppOrgSlugIntegrationsRoute,
AppOrgSlugSecurityRoute: AppOrgSlugSecurityRoute,
AppOrgSlugSsoRoute: AppOrgSlugSsoRoute,
AppOrgSlugTeamRoute: AppOrgSlugTeamRoute,
AppOrgSlugUsageRoute: AppOrgSlugUsageRoute,
AppOrgSlugIndexRoute: AppOrgSlugIndexRoute,
AppOrgSlugWebhooksEndpointIdRoute: AppOrgSlugWebhooksEndpointIdRoute,
AppOrgSlugPrivateAppsIndexRoute: AppOrgSlugPrivateAppsIndexRoute,
AppOrgSlugWebhooksIndexRoute: AppOrgSlugWebhooksIndexRoute,
}
const AppOrgRouteWithChildren =
AppOrgRoute._addFileChildren(AppOrgRouteChildren)
const rootRouteChildren: RootRouteChildren = {
AppAccountRoute: AppAccountRouteWithChildren,
AppOrgRoute: AppOrgRouteWithChildren,
AppOrganizationsRoute: AppOrganizationsRoute,
AuthForgotPasswordRoute: AuthForgotPasswordRoute,
AuthForgotPasswordMfaRoute: AuthForgotPasswordMfaRoute,
AuthResetPasswordRoute: AuthResetPasswordRoute,
AuthSignInRoute: AuthSignInRoute,
AuthSignInMfaRoute: AuthSignInMfaRoute,
AuthSignInPartnerRoute: AuthSignInPartnerRoute,
AuthSignInSsoRoute: AuthSignInSsoRoute,
AuthSignUpRoute: AuthSignUpRoute,
AppSupportLinkRoute: AppSupportLinkRoute,
AppSupportNewRoute: AppSupportNewRoute,
AuthCliLoginRoute: AuthCliLoginRoute,
AppNewIndexRoute: AppNewIndexRoute,
AuthPartnersStripeProjectsLoginRoute: AuthPartnersStripeProjectsLoginRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
import type { getRouter } from './router.tsx'
import type { startInstance } from './start.ts'
declare module '@tanstack/react-start' {
interface Register {
ssr: true
router: Awaited<ReturnType<typeof getRouter>>
config: Awaited<ReturnType<typeof startInstance.getOptions>>
}
}
+97
View File
@@ -0,0 +1,97 @@
import type { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'
import { getQueryClient } from '@/data/query-client'
import { BASE_PATH, IS_PLATFORM } from '@/lib/constants'
export interface RouterContext {
queryClient: QueryClient
}
// Skew protection: pin this browser session to the deployment that served it,
// so a long-lived dashboard session never 404s on a lazily-loaded JS chunk or
// gets a surprise version change mid-session. It's a session cookie (no
// expiry) — cleared when the tab/window closes, so the next visit gets the
// latest deploy. Scoped to BASE_PATH so the version check (hit at the root
// `/api/...`, outside this Path) stays unpinned and can still detect new
// deploys; the "Refresh" toast clears it before reloading (see
// use-check-latest-deploy). No-op unless we're on a Vercel deploy with Skew
// Protection enabled.
function pinDeploymentForSession() {
if (typeof document === 'undefined') return
if (!IS_PLATFORM) return
if (process.env.NEXT_PUBLIC_VERCEL_SKEW_PROTECTION_ENABLED !== '1') return
const deploymentId = process.env.NEXT_PUBLIC_VERCEL_DEPLOYMENT_ID
if (!deploymentId) return
if (document.cookie.includes('__vdpl=')) return
document.cookie = `__vdpl=${deploymentId}; Path=${BASE_PATH || '/'}; SameSite=Lax; Secure`
}
// Backstop for the pin above: if a lazily-loaded chunk 404s — most likely the
// pinned deployment aged out of Skew Protection's Maximum Age, so its hashed
// chunks are gone — Vite emits `vite:preloadError`. Drop the pin and reload so
// we land on the latest deployment (a plain reload wouldn't recover, since the
// cookie would just re-pin to the dead deployment). A short time-window guard
// prevents a reload loop if the latest deployment is itself broken.
function registerChunkErrorBackstop() {
if (typeof window === 'undefined') return
window.addEventListener('vite:preloadError', (event) => {
const KEY = 'studio:chunk-error-reload-at'
let last = 0
try {
last = Number(sessionStorage.getItem(KEY) || 0)
} catch {
// sessionStorage unavailable — fall through and attempt a reload anyway.
}
// Reloaded very recently → likely a loop; let Vite surface the error.
if (Date.now() - last < 10_000) return
event.preventDefault()
try {
sessionStorage.setItem(KEY, String(Date.now()))
} catch {
// ignore — worst case we lose loop protection for this reload.
}
document.cookie = `__vdpl=; Path=${BASE_PATH || '/'}; Max-Age=0`
window.location.reload()
})
}
function getContext(): RouterContext {
return {
queryClient: getQueryClient(),
}
}
export function getRouter() {
pinDeploymentForSession()
registerChunkErrorBackstop()
const context = getContext()
const router = createRouter({
routeTree,
context,
scrollRestoration: true,
defaultPreload: 'intent',
// Inlined via Vite's `define` at build time; stays undefined (= app at `/`)
// unless NEXT_PUBLIC_BASE_PATH is set. Must agree with Vite `base`
basepath: process.env.NEXT_PUBLIC_BASE_PATH || undefined,
})
// @tanstack/react-router-ssr-query@1.166.12 pulls in @tanstack/query-core@5.100
// as a peer, but our app pins react-query to 5.83. The QueryClient class is
// structurally identical between the two, but TS treats them as nominally
// distinct types because each version has its own `#private` field.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setupRouterSsrQueryIntegration({ router, queryClient: context.queryClient as any })
return router
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>
}
}
+395
View File
@@ -0,0 +1,395 @@
/// <reference types="vite/client" />
import 'react-data-grid/lib/styles.css'
import '@/styles/code.css'
import '@/styles/editor.css'
import '@/styles/focus.css'
// Vite-only: defines @font-face for the custom fonts. The Next pipeline
// (pages/_app.tsx) loads these via next/font instead, so this import has no
// counterpart there — but dropping it under Vite makes the browser fall back
// to system fonts.
import '@/styles/fonts.css'
import '@/styles/graphiql-base.css'
import '@/styles/grid.css'
import '@/styles/globals.css'
import '@/styles/markdown-preview.css'
import '@/styles/monaco.css'
import '@/styles/react-data-grid-logs.css'
import '@/styles/reactflow.css'
import '@/styles/storage.css'
import '@/styles/stripe.css'
import '@/styles/ui.css'
import 'ui-patterns/ShimmeringLoader/index.css'
import { loader } from '@monaco-editor/react'
import * as Sentry from '@sentry/react'
import { TanStackDevtools } from '@tanstack/react-devtools'
import type { QueryClient } from '@tanstack/react-query'
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
import {
createRootRouteWithContext,
HeadContent,
Outlet,
redirect,
Scripts,
} from '@tanstack/react-router'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import {
FeatureFlagProvider,
getFlags,
TelemetryTagManager,
ThemeProvider,
useThemeSandbox,
} from 'common'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import duration from 'dayjs/plugin/duration'
import relativeTime from 'dayjs/plugin/relativeTime'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
import { DevToolbar, DevToolbarProvider, DevToolbarTrigger, type ExtraTab } from 'dev-tools'
import { NuqsAdapter } from 'nuqs/adapters/tanstack-router'
import {
lazy,
Suspense,
useCallback,
useEffect,
type ComponentProps,
type ErrorInfo,
type ReactNode,
} from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { TooltipProvider } from 'ui'
import { StudioCommandMenu } from '@/components/interfaces/App/CommandMenu'
import { StudioCommandProvider as CommandProvider } from '@/components/interfaces/App/CommandMenu/StudioCommandProvider'
import { FeaturePreviewContextProvider } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { FeaturePreviewModal } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewModal'
import { MonacoThemeProvider } from '@/components/interfaces/App/MonacoThemeProvider'
import { RouteValidationWrapper } from '@/components/interfaces/App/RouteValidationWrapper'
import { MainScrollContainerProvider } from '@/components/layouts/MainScrollContainerContext'
import { BannerStackProvider } from '@/components/ui/BannerStack/BannerStackProvider'
import { GlobalErrorBoundaryState } from '@/components/ui/ErrorBoundary/GlobalErrorBoundaryState'
import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { AuthProvider } from '@/lib/auth'
import { API_URL, BASE_PATH, IS_PLATFORM, useDefaultProvider } from '@/lib/constants'
import { ProfileProvider } from '@/lib/profile'
import { Telemetry } from '@/lib/telemetry'
import { Toaster } from '@/lib/toaster'
import Error404 from '@/pages/404'
import Error500 from '@/pages/500'
import { matchRedirect } from '@/redirects.shared'
import { AiAssistantStateContextProvider } from '@/state/ai-assistant-state'
dayjs.extend(customParseFormat)
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(relativeTime)
dayjs.extend(duration)
interface RouterContext {
queryClient: QueryClient
}
const FeatureFlagProviderWithOrgContext = ({
children,
...props
}: ComponentProps<typeof FeatureFlagProvider>) => {
const { data: selectedOrganization } = useSelectedOrganizationQuery({ enabled: IS_PLATFORM })
return (
<FeatureFlagProvider {...props} organizationSlug={selectedOrganization?.slug ?? undefined}>
{children}
</FeatureFlagProvider>
)
}
// Keep dev-only components out of the production bundle.
const IS_DEV_TOOLBAR_ENABLED =
process.env.NEXT_PUBLIC_ENVIRONMENT === 'local' ||
process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging'
const ResourceWarningsTab = IS_DEV_TOOLBAR_ENABLED
? lazy(() =>
import('@/components/ui/DevToolbar/ResourceWarningsTab').then((m) => ({
default: m.ResourceWarningsTab,
}))
)
: () => null
const devToolbarExtraTabs: ExtraTab[] = IS_DEV_TOOLBAR_ENABLED
? [
{
id: 'warnings',
label: 'Warnings',
content: (
<Suspense fallback={null}>
<ResourceWarningsTab />
</Suspense>
),
},
]
: []
// [Joshen] Attempt for offline support/bypass ISP issues is to store the assets required for monaco
// locally. We're however, only storing the assets which we need (based on what the network tab loads
// while using monaco). If we end up facing more effort trying to maintain this, probably to either
// use cloudflare or find some way to pull all the files from a CDN via a CLI, rather than tracking individual files
// The alternative was to import * as monaco from 'monaco-editor' but i couldn't get it working
loader.config({
paths: {
vs: IS_PLATFORM
? 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs'
: `${BASE_PATH}/monaco-editor`,
},
})
const FAVICON_ROUTE = '/favicon'
const THEME_COLOR = '1E1E1E'
const APPLICATION_NAME = 'Supabase Studio'
const APPLE_TOUCH_ICON_SIZES = [
'57x57',
'60x60',
'72x72',
'76x76',
'114x114',
'120x120',
'144x144',
'152x152',
]
// The 128 variant ships as `favicon-128.png` (no dimensions in the filename);
// the rest follow `favicon-<size>.png`.
const FAVICON_PNG_VARIANTS: Array<{ sizes: string; file: string }> = [
{ sizes: '16x16', file: 'favicon-16x16.png' },
{ sizes: '32x32', file: 'favicon-32x32.png' },
{ sizes: '48x48', file: 'favicon-48x48.png' },
{ sizes: '96x96', file: 'favicon-96x96.png' },
{ sizes: '128x128', file: 'favicon-128.png' },
{ sizes: '180x180', file: 'favicon-180x180.png' },
{ sizes: '196x196', file: 'favicon-196x196.png' },
]
function buildRootHead() {
const meta: Array<Record<string, string>> = [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'initial-scale=1.0, width=device-width' },
{ property: 'og:image', content: `${BASE_PATH}/img/supabase-logo.png` },
{ name: 'googlebot', content: 'notranslate' },
{ name: 'application-name', content: APPLICATION_NAME },
{ name: 'msapplication-TileColor', content: `#${THEME_COLOR}` },
{ name: 'msapplication-TileImage', content: `${BASE_PATH}${FAVICON_ROUTE}/mstile-144x144.png` },
{
name: 'msapplication-square70x70logo',
content: `${BASE_PATH}${FAVICON_ROUTE}/mstile-70x70.png`,
},
{
name: 'msapplication-square150x150logo',
content: `${BASE_PATH}${FAVICON_ROUTE}/mstile-150x150.png`,
},
{
name: 'msapplication-wide310x150logo',
content: `${BASE_PATH}${FAVICON_ROUTE}/mstile-310x150.png`,
},
{
name: 'msapplication-square310x310logo',
content: `${BASE_PATH}${FAVICON_ROUTE}/mstile-310x310.png`,
},
{ name: 'theme-color', content: `#${THEME_COLOR}` },
{ title: 'Supabase' },
]
const links: Array<Record<string, string>> = [
// Google Fonts — Source Code Pro (the local CustomFont is declared in styles/fonts.css).
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: '' },
{
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600;700&display=swap',
},
...APPLE_TOUCH_ICON_SIZES.map((size) => ({
rel: 'apple-touch-icon-precomposed',
sizes: size,
href: `${BASE_PATH}${FAVICON_ROUTE}/apple-icon-${size}.png`,
})),
...FAVICON_PNG_VARIANTS.map(({ sizes, file }) => ({
rel: 'icon',
type: 'image/png',
sizes,
href: `${BASE_PATH}${FAVICON_ROUTE}/${file}`,
})),
{ rel: 'shortcut icon', href: `${BASE_PATH}${FAVICON_ROUTE}/favicon.ico` },
{ rel: 'icon', type: 'image/x-icon', href: `${BASE_PATH}${FAVICON_ROUTE}/favicon.ico` },
{ rel: 'apple-touch-icon', href: `${BASE_PATH}${FAVICON_ROUTE}/favicon.ico` },
{ rel: 'manifest', href: `${BASE_PATH}${FAVICON_ROUTE}/manifest.json` },
]
if (IS_PLATFORM) {
links.unshift({
rel: 'preconnect',
href: new URL(API_URL).origin,
crossOrigin: 'use-credentials',
})
}
return { meta, links }
}
function DynamicTitle() {
const { appTitle } = useCustomContent(['app:title'])
if (!appTitle) return null
return <title>{appTitle}</title>
}
const errorBoundaryHandler = (error: Error, _info: ErrorInfo) => {
Sentry.withScope(function (scope) {
scope.setTag('globalErrorBoundary', true)
const eventId = Sentry.captureException(error)
// Attach the Sentry event ID to the error object so it can be accessed by the error boundary
if (eventId && error && typeof error === 'object') {
;(error as Error & { sentryId?: string }).sentryId = eventId
}
})
console.error(error.stack)
}
function NotFound() {
return <Error404 />
}
function ErrorBoundaryRoute({ error }: { error: Error }) {
// Mirrors `errorBoundaryHandler` above (used by the in-tree
// `react-error-boundary`) — TanStack's `errorComponent` covers
// errors thrown during route load/render before the in-tree
// boundary mounts, so we report from both layers.
useEffect(() => {
Sentry.withScope((scope) => {
scope.setTag('routerErrorComponent', true)
const eventId = Sentry.captureException(error)
if (eventId && error && typeof error === 'object') {
;(error as Error & { sentryId?: string }).sentryId = eventId
}
})
console.error(error.stack)
}, [error])
return <Error500 />
}
export const Route = createRootRouteWithContext<RouterContext>()({
head: buildRootHead,
// Mirrors the redirect rules in `next.config.ts` / `vercel.ts`. Vercel's
// edge layer already handles these for the platform deploy; this is the
// self-hosted (Node-server) fallback and the client-side safety net.
beforeLoad: ({ location }) => {
const match = matchRedirect({
pathname: location.pathname,
search: location.search as Record<string, string | string[] | undefined>,
isPlatform: IS_PLATFORM,
})
if (!match) return
const href = BASE_PATH ? `${BASE_PATH}${match.destination}` : match.destination
throw redirect({ href, statusCode: match.permanent ? 308 : 307 })
},
component: RootComponent,
shellComponent: RootDocument,
notFoundComponent: NotFound,
errorComponent: ErrorBoundaryRoute,
})
function RootComponent() {
useThemeSandbox()
const cloudProvider = useDefaultProvider()
const getConfigCatFlags = useCallback(
(userEmail?: string) => {
const customAttributes = cloudProvider ? { cloud_provider: cloudProvider } : undefined
return getFlags(userEmail, customAttributes)
},
[cloudProvider]
)
return (
<ErrorBoundary FallbackComponent={GlobalErrorBoundaryState} onError={errorBoundaryHandler}>
<NuqsAdapter>
<AuthProvider>
<FeatureFlagProviderWithOrgContext
API_URL={API_URL}
enabled={IS_PLATFORM}
getConfigCatFlags={getConfigCatFlags}
>
<ProfileProvider>
<DynamicTitle />
<TooltipProvider delayDuration={0}>
<RouteValidationWrapper>
<ThemeProvider
defaultTheme="system"
themes={['dark', 'light', 'classic-dark']}
enableSystem
disableTransitionOnChange
>
<DevToolbarProvider apiUrl={API_URL}>
<AiAssistantStateContextProvider>
<CommandProvider>
<BannerStackProvider>
<FeaturePreviewContextProvider>
<MainScrollContainerProvider>
<Outlet />
</MainScrollContainerProvider>
<StudioCommandMenu />
<FeaturePreviewModal />
</FeaturePreviewContextProvider>
</BannerStackProvider>
<Toaster />
<MonacoThemeProvider />
</CommandProvider>
</AiAssistantStateContextProvider>
<DevToolbar extraTabs={devToolbarExtraTabs} />
<DevToolbarTrigger />
</DevToolbarProvider>
</ThemeProvider>
</RouteValidationWrapper>
</TooltipProvider>
<Telemetry />
</ProfileProvider>
</FeatureFlagProviderWithOrgContext>
</AuthProvider>
</NuqsAdapter>
<TelemetryTagManager />
</ErrorBoundary>
)
}
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
// suppressHydrationWarning is for next-themes: it writes data-theme and
// color-scheme onto <html> from localStorage pre-hydration, which the
// prerendered shell can't know. Scoped to this element only.
<html lang="en" suppressHydrationWarning>
<head>
<HeadContent />
</head>
<body>
{children}
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[
{
name: 'TanStack Router',
render: <TanStackRouterDevtoolsPanel />,
},
{
name: 'TanStack Query',
render: <ReactQueryDevtoolsPanel />,
},
]}
/>
<Scripts />
</body>
</html>
)
}
+23
View File
@@ -0,0 +1,23 @@
import { createFileRoute, Outlet, useMatches } from '@tanstack/react-router'
import AccountLayout from '@/components/layouts/AccountLayout/AccountLayout'
export const Route = createFileRoute('/_app/account')({
component: AccountShell,
})
function AccountShell() {
// `select` form: only re-render when the selected title changes, not on
// every router tick. See routes/_app.tsx for the full rationale.
const title = useMatches({
select: (matches) =>
(matches[matches.length - 1]?.staticData as { accountLayoutTitle?: string } | undefined)
?.accountLayoutTitle ?? '',
})
return (
<AccountLayout title={title}>
<Outlet />
</AccountLayout>
)
}
+15
View File
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import AuditPage from '@/pages/account/audit'
export const Route = createFileRoute('/_app/account/audit')({
component: AccountAuditPage,
staticData: {
defaultLayoutHeaderTitle: 'Account',
accountLayoutTitle: 'Audit Logs',
},
})
function AccountAuditPage() {
return <AuditPage dehydratedState={undefined} />
}
+16
View File
@@ -0,0 +1,16 @@
import { createFileRoute } from '@tanstack/react-router'
import { IS_PLATFORM } from '@/lib/constants'
import User from '@/pages/account/me'
export const Route = createFileRoute('/_app/account/me')({
component: AccountMePage,
staticData: {
defaultLayoutHeaderTitle: IS_PLATFORM ? 'Account' : 'Preferences',
accountLayoutTitle: 'Preferences',
},
})
function AccountMePage() {
return <User dehydratedState={undefined} />
}
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import SecurityPage from '@/pages/account/security'
export const Route = createFileRoute('/_app/account/security')({
component: AccountSecurityPage,
staticData: {
defaultLayoutHeaderTitle: 'Account',
accountLayoutTitle: 'Security',
},
})
function AccountSecurityPage() {
return <SecurityPage dehydratedState={undefined} />
}
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import UserAccessTokensPage from '@/pages/account/tokens'
export const Route = createFileRoute('/_app/account/tokens/')({
component: AccountTokensPage,
staticData: {
defaultLayoutHeaderTitle: 'Account',
accountLayoutTitle: 'Access Tokens',
},
})
function AccountTokensPage() {
return <UserAccessTokensPage dehydratedState={undefined} />
}
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import ScopedTokensPage from '@/pages/account/tokens/scoped'
export const Route = createFileRoute('/_app/account/tokens/scoped')({
component: AccountScopedTokensPage,
staticData: {
defaultLayoutHeaderTitle: 'Account',
accountLayoutTitle: 'Access Tokens',
},
})
function AccountScopedTokensPage() {
return <ScopedTokensPage dehydratedState={undefined} />
}
+24
View File
@@ -0,0 +1,24 @@
import { createFileRoute } from '@tanstack/react-router'
import WizardLayout from '@/components/layouts/WizardLayout'
import Wizard from '@/pages/new/index'
export const Route = createFileRoute('/_app/new/')({
component: NewOrgRoute,
staticData: {
hideMobileMenu: true,
defaultLayoutHeaderTitle: 'New organization',
},
})
// Inline WizardLayout here rather than via a `_app/new.tsx` sub-shell —
// `_app/new/$slug.tsx` is not under _app (no AppLayout in Next), and the
// only other potential leaf has a different inner wrapper (PageLayout),
// so a shared shell would not actually share anything.
function NewOrgRoute() {
return (
<WizardLayout>
<Wizard dehydratedState={undefined} />
</WizardLayout>
)
}
+23
View File
@@ -0,0 +1,23 @@
import { createFileRoute, Outlet, useMatches } from '@tanstack/react-router'
import OrganizationLayout from '@/components/layouts/OrganizationLayout'
export const Route = createFileRoute('/_app/org')({
component: OrgShell,
})
function OrgShell() {
// `select` form: only re-render when the selected title changes, not on
// every router tick. See routes/_app.tsx for the full rationale.
const title = useMatches({
select: (matches) =>
(matches[matches.length - 1]?.staticData as { orgLayoutTitle?: string } | undefined)
?.orgLayoutTitle ?? '',
})
return (
<OrganizationLayout title={title}>
<Outlet />
</OrganizationLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgOAuthAppsPage from '@/pages/org/[slug]/apps'
export const Route = createFileRoute('/_app/org/$slug/apps')({
component: OrgApps,
staticData: {
orgLayoutTitle: 'OAuth Apps',
},
})
function OrgApps() {
return (
<OrganizationSettingsLayout>
<OrgOAuthAppsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgAuditLogDrainsPage from '@/pages/org/[slug]/audit-log-drains'
export const Route = createFileRoute('/_app/org/$slug/audit-log-drains')({
component: OrgAuditLogDrains,
staticData: {
orgLayoutTitle: 'Audit Log Drains',
},
})
function OrgAuditLogDrains() {
return (
<OrganizationSettingsLayout>
<OrgAuditLogDrainsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgAuditLogsPage from '@/pages/org/[slug]/audit'
export const Route = createFileRoute('/_app/org/$slug/audit')({
component: OrgAudit,
staticData: {
orgLayoutTitle: 'Audit Logs',
},
})
function OrgAudit() {
return (
<OrganizationSettingsLayout>
<OrgAuditLogsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import OrgBillingSettingsPage from '@/pages/org/[slug]/billing'
export const Route = createFileRoute('/_app/org/$slug/billing')({
component: OrgBilling,
staticData: {
orgLayoutTitle: 'Billing',
},
})
function OrgBilling() {
return <OrgBillingSettingsPage dehydratedState={undefined} />
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgDocumentsPage from '@/pages/org/[slug]/documents'
export const Route = createFileRoute('/_app/org/$slug/documents')({
component: OrgDocuments,
staticData: {
orgLayoutTitle: 'Legal Documents',
},
})
function OrgDocuments() {
return (
<OrganizationSettingsLayout>
<OrgDocumentsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgGeneralSettingsPage from '@/pages/org/[slug]/general'
export const Route = createFileRoute('/_app/org/$slug/general')({
component: OrgGeneral,
staticData: {
orgLayoutTitle: 'General',
},
})
function OrgGeneral() {
return (
<OrganizationSettingsLayout>
<OrgGeneralSettingsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { PageLayout } from '@/components/layouts/PageLayout/PageLayout'
import ProjectsPage from '@/pages/org/[slug]/index'
export const Route = createFileRoute('/_app/org/$slug/')({
component: OrgSlugIndex,
staticData: {
orgLayoutTitle: 'Projects',
},
})
function OrgSlugIndex() {
return (
<PageLayout title="Projects">
<ProjectsPage dehydratedState={undefined} />
</PageLayout>
)
}
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import OrgIntegrationSettingsPage from '@/pages/org/[slug]/integrations'
export const Route = createFileRoute('/_app/org/$slug/integrations')({
component: OrgIntegrations,
staticData: {
orgLayoutTitle: 'Integrations',
},
})
function OrgIntegrations() {
return <OrgIntegrationSettingsPage dehydratedState={undefined} />
}
@@ -0,0 +1,22 @@
import { createFileRoute } from '@tanstack/react-router'
import { PrivateAppsProvider } from '@/components/interfaces/Organization/PrivateApps/PrivateAppsContext'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import PrivateAppsPage from '@/pages/org/[slug]/private-apps/index'
export const Route = createFileRoute('/_app/org/$slug/private-apps/')({
component: OrgPrivateApps,
staticData: {
orgLayoutTitle: 'Private Apps',
},
})
function OrgPrivateApps() {
return (
<OrganizationSettingsLayout>
<PrivateAppsProvider>
<PrivateAppsPage dehydratedState={undefined} />
</PrivateAppsProvider>
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgSecuritySettingsPage from '@/pages/org/[slug]/security'
export const Route = createFileRoute('/_app/org/$slug/security')({
component: OrgSecurity,
staticData: {
orgLayoutTitle: 'Security',
},
})
function OrgSecurity() {
return (
<OrganizationSettingsLayout>
<OrgSecuritySettingsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
+19
View File
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgSSOPage from '@/pages/org/[slug]/sso'
export const Route = createFileRoute('/_app/org/$slug/sso')({
component: OrgSSO,
staticData: {
orgLayoutTitle: 'SSO',
},
})
function OrgSSO() {
return (
<OrganizationSettingsLayout>
<OrgSSOPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import OrgTeamSettingsPage from '@/pages/org/[slug]/team'
export const Route = createFileRoute('/_app/org/$slug/team')({
component: OrgTeam,
staticData: {
orgLayoutTitle: 'Team',
},
})
function OrgTeam() {
return <OrgTeamSettingsPage dehydratedState={undefined} />
}
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import OrgUsagePage from '@/pages/org/[slug]/usage'
export const Route = createFileRoute('/_app/org/$slug/usage')({
component: OrgUsage,
staticData: {
orgLayoutTitle: 'Usage',
},
})
function OrgUsage() {
return <OrgUsagePage dehydratedState={undefined} />
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgWebhookEndpointSettingsPage from '@/pages/org/[slug]/webhooks/[endpointId]'
export const Route = createFileRoute('/_app/org/$slug/webhooks/$endpointId')({
component: OrgWebhookEndpoint,
staticData: {
orgLayoutTitle: 'Webhooks',
},
})
function OrgWebhookEndpoint() {
return (
<OrganizationSettingsLayout>
<OrgWebhookEndpointSettingsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { OrganizationSettingsLayout } from '@/components/layouts/ProjectLayout/OrganizationSettingsLayout'
import OrgWebhooksSettingsPage from '@/pages/org/[slug]/webhooks/index'
export const Route = createFileRoute('/_app/org/$slug/webhooks/')({
component: OrgWebhooks,
staticData: {
orgLayoutTitle: 'Webhooks',
},
})
function OrgWebhooks() {
return (
<OrganizationSettingsLayout>
<OrgWebhooksSettingsPage dehydratedState={undefined} />
</OrganizationSettingsLayout>
)
}
+14
View File
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import OrgIndexPage from '@/pages/org/index'
export const Route = createFileRoute('/_app/org/')({
component: OrgIndex,
staticData: {
orgLayoutTitle: 'Organizations',
},
})
function OrgIndex() {
return <OrgIndexPage dehydratedState={undefined} />
}
+21
View File
@@ -0,0 +1,21 @@
import { createFileRoute } from '@tanstack/react-router'
import { PageLayout } from '@/components/layouts/PageLayout/PageLayout'
import OrganizationsPage from '@/pages/organizations'
export const Route = createFileRoute('/_app/organizations')({
component: Organizations,
staticData: {
defaultLayoutHeaderTitle: 'Organizations',
hideMobileMenu: true,
},
})
function Organizations() {
// Next page default export is already wrapped in withAuth.
return (
<PageLayout title="Your Organizations" className="max-w-[1200px] lg:px-6 mx-auto">
<OrganizationsPage dehydratedState={undefined} />
</PageLayout>
)
}
+11
View File
@@ -0,0 +1,11 @@
import { createFileRoute } from '@tanstack/react-router'
import LinkSupportTicketPageRoute from '@/pages/support/link'
export const Route = createFileRoute('/_app/support/link')({
component: SupportLinkRoute,
})
function SupportLinkRoute() {
return <LinkSupportTicketPageRoute dehydratedState={undefined} />
}
+14
View File
@@ -0,0 +1,14 @@
import { createFileRoute } from '@tanstack/react-router'
import SupportPage from '@/pages/support/new'
export const Route = createFileRoute('/_app/support/new')({
component: SupportNewRoute,
// _app shell reads hideMobileMenu from leaf staticData and forwards it to
// DefaultLayout. The Next-side getLayout sets hideMobileMenu on DefaultLayout.
staticData: { hideMobileMenu: true },
})
function SupportNewRoute() {
return <SupportPage dehydratedState={undefined} />
}
+12
View File
@@ -0,0 +1,12 @@
import { createFileRoute } from '@tanstack/react-router'
import CliLoginPage from '@/pages/cli/login'
export const Route = createFileRoute('/_auth/cli/login')({
component: CliLogin,
})
function CliLogin() {
// Next page default export is already wrapped in withAuth and inlines APIAuthorizationLayout.
return <CliLoginPage dehydratedState={undefined} />
}
@@ -0,0 +1,12 @@
import { createFileRoute } from '@tanstack/react-router'
import ForgotPasswordMfaPage from '@/pages/forgot-password-mfa'
export const Route = createFileRoute('/_auth/forgot-password-mfa')({
component: ForgotPasswordMfa,
})
function ForgotPasswordMfa() {
// The Next page inlines its own ForgotPasswordLayout; just render it.
return <ForgotPasswordMfaPage dehydratedState={undefined} />
}
@@ -0,0 +1,19 @@
import { createFileRoute } from '@tanstack/react-router'
import { ForgotPasswordLayout } from '@/components/layouts/SignInLayout/ForgotPasswordLayout'
import ForgotPasswordPage from '@/pages/forgot-password'
export const Route = createFileRoute('/_auth/forgot-password')({
component: ForgotPassword,
})
function ForgotPassword() {
return (
<ForgotPasswordLayout
heading="Forgot your password?"
subheading="Enter your email and we'll send you a code to reset the password"
>
<ForgotPasswordPage dehydratedState={undefined} />
</ForgotPasswordLayout>
)
}
@@ -0,0 +1,12 @@
import { createFileRoute } from '@tanstack/react-router'
import StripeProjectsLoginPage from '@/pages/partners/stripe/projects/login'
export const Route = createFileRoute('/_auth/partners/stripe/projects/login')({
component: StripeProjectsLogin,
})
function StripeProjectsLogin() {
// Next page default export is already wrapped in withAuth and inlines APIAuthorizationLayout.
return <StripeProjectsLoginPage dehydratedState={undefined} />
}
@@ -0,0 +1,20 @@
import { createFileRoute } from '@tanstack/react-router'
import { ForgotPasswordLayout } from '@/components/layouts/SignInLayout/ForgotPasswordLayout'
import ResetPasswordPage from '@/pages/reset-password'
export const Route = createFileRoute('/_auth/reset-password')({
component: ResetPassword,
})
function ResetPassword() {
// Next page default export is already wrapped in withAuth — session guard runs inline.
return (
<ForgotPasswordLayout
heading="Change your password"
subheading="Welcome back! Choose a new strong password and save it to proceed"
>
<ResetPasswordPage dehydratedState={undefined} />
</ForgotPasswordLayout>
)
}
+12
View File
@@ -0,0 +1,12 @@
import { createFileRoute } from '@tanstack/react-router'
import SignInMfaPage from '@/pages/sign-in-mfa'
export const Route = createFileRoute('/_auth/sign-in-mfa')({
component: SignInMfa,
})
function SignInMfa() {
// The Next page inlines its own SignInLayout; just render it.
return <SignInMfaPage dehydratedState={undefined} />
}
@@ -0,0 +1,25 @@
import { createFileRoute } from '@tanstack/react-router'
import { cn } from 'ui'
import { ForgotPasswordLayout } from '@/components/layouts/SignInLayout/ForgotPasswordLayout'
import SignInPartnerPage from '@/pages/sign-in-partner'
export const Route = createFileRoute('/_auth/sign-in-partner')({
component: SignInPartner,
})
function SignInPartner() {
return (
// [Joshen] Just using this layout for the styling
<ForgotPasswordLayout
showHeadings={false}
className={cn(
'mx-auto max-w-7xl px-8 sm:px-12 lg:px-16 !gap-y-0',
'[&>div:first-child]:absolute [&>div:first-child]:!px-0',
'[&>div:last-child]:flex-grow [&>div:last-child>main]:!px-0'
)}
>
<SignInPartnerPage dehydratedState={undefined} />
</ForgotPasswordLayout>
)
}
+20
View File
@@ -0,0 +1,20 @@
import { createFileRoute } from '@tanstack/react-router'
import { SignInLayout } from '@/components/layouts/SignInLayout/SignInLayout'
import SignInSSOPage from '@/pages/sign-in-sso'
export const Route = createFileRoute('/_auth/sign-in-sso')({
component: SignInSSO,
})
function SignInSSO() {
return (
<SignInLayout
heading="Welcome back"
subheading="Sign in to your enterprise account"
logoLinkToMarketingSite={true}
>
<SignInSSOPage dehydratedState={undefined} />
</SignInLayout>
)
}
+21
View File
@@ -0,0 +1,21 @@
import { createFileRoute } from '@tanstack/react-router'
import { SignInLayout } from '@/components/layouts/SignInLayout/SignInLayout'
import SignInPage from '@/pages/sign-in'
export const Route = createFileRoute('/_auth/sign-in')({
component: SignIn,
})
function SignIn() {
return (
<SignInLayout
heading="Welcome back"
subheading="Sign in to your account"
logoLinkToMarketingSite={true}
inboundFlow="sign-in"
>
<SignInPage dehydratedState={undefined} />
</SignInLayout>
)
}
+16
View File
@@ -0,0 +1,16 @@
import { createFileRoute } from '@tanstack/react-router'
import { SignInLayout } from '@/components/layouts/SignInLayout/SignInLayout'
import SignUpPage from '@/pages/sign-up'
export const Route = createFileRoute('/_auth/sign-up')({
component: SignUp,
})
function SignUp() {
return (
<SignInLayout heading="Get started" subheading="Create a new account" inboundFlow="sign-up">
<SignUpPage dehydratedState={undefined} />
</SignInLayout>
)
}