diff --git a/docs/src/components/layouts/docs-layout-router.tsx b/docs/src/components/layouts/docs-layout-router.tsx index 8b06e0e8d..b026cf310 100644 --- a/docs/src/components/layouts/docs-layout-router.tsx +++ b/docs/src/components/layouts/docs-layout-router.tsx @@ -48,12 +48,18 @@ type DynamicDocsLayoutProps = { // Helper function to check if we're in SDK section function isInSdkSection(pathname: string): boolean { - return pathname.includes('/sdk'); + // Match the actual SDK section: /docs/platform/sdk or /docs/platform/sdk/... + // This excludes docs pages that might mention SDK in other contexts + const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/); + return Boolean(match); } // Helper function to check if we're in Components section function isInComponentsSection(pathname: string): boolean { - return pathname.includes('/components'); + // Match the actual Components section: /docs/platform/components or /docs/platform/components/... + // This excludes docs pages like /docs/platform/getting-started/components + const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/); + return Boolean(match); } // Helper function to find and extract a specific section from the page tree @@ -140,10 +146,32 @@ export function DynamicDocsLayout({ children, ...props }: DynamicDocsLayoutProps }, [pathname, props.tree]); const platformOptions: Option[] = useMemo(() => { - return PLATFORMS.map(platform => ({ - url: getSmartRedirectUrl(pathname, platform), - title: getPlatformDisplayName(platform), - })); + // Extract current platform from pathname + const currentPlatform = getCurrentPlatform(pathname); + + return PLATFORMS.map(platform => { + let url: string; + + if (isInSdkSection(pathname)) { + // For SDK section: /docs/platform/sdk + url = `/docs/${platform}/sdk`; + } else if (isInComponentsSection(pathname)) { + // For Components section: /docs/platform/components + url = `/docs/${platform}/components`; + } else { + // For normal docs: use smart redirect + url = getSmartRedirectUrl(pathname, platform); + } + + return { + url, + title: getPlatformDisplayName(platform), + // Add urls set for more precise matching if this is the current platform + ...(platform === currentPlatform && { + urls: new Set([pathname]) + }) + }; + }); }, [pathname]); // Auto-redirect to current platform if needed diff --git a/docs/src/components/layouts/shared-content-layout.tsx b/docs/src/components/layouts/shared-content-layout.tsx index 7a6929549..2d8fdae60 100644 --- a/docs/src/components/layouts/shared-content-layout.tsx +++ b/docs/src/components/layouts/shared-content-layout.tsx @@ -1,3 +1,5 @@ +'use client'; + import { type HTMLAttributes, type ReactNode } from 'react'; import { cn } from '../../lib/cn'; import { useSidebar } from './sidebar-context'; diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx index 53f1b941c..359d00982 100644 --- a/docs/src/components/layouts/shared-header.tsx +++ b/docs/src/components/layouts/shared-header.tsx @@ -30,11 +30,17 @@ type SharedHeaderProps = { * Helper functions to detect which section we're in */ export function isInSdkSection(pathname: string): boolean { - return pathname.includes('/sdk'); + // Match the actual SDK section: /docs/platform/sdk or /docs/platform/sdk/... + // This excludes docs pages that might mention SDK in other contexts + const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/); + return Boolean(match); } export function isInComponentsSection(pathname: string): boolean { - return pathname.includes('/components'); + // Match the actual Components section: /docs/platform/components or /docs/platform/components/... + // This excludes docs pages like /docs/platform/getting-started/components + const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/); + return Boolean(match); } export function isInApiSection(pathname: string): boolean { diff --git a/docs/templates/faq.mdx b/docs/templates/faq.mdx index eb5872e8d..8f43a94a5 100644 --- a/docs/templates/faq.mdx +++ b/docs/templates/faq.mdx @@ -1,5 +1,5 @@ --- -title: faq +title: FAQ description: Frequently asked questions about Stack --- diff --git a/docs/templates/sdk/objects/stack-app-test.mdx b/docs/templates/sdk/objects/stack-app-test.mdx deleted file mode 100644 index be01957b9..000000000 --- a/docs/templates/sdk/objects/stack-app-test.mdx +++ /dev/null @@ -1,912 +0,0 @@ ---- -title: StackApp -full: true ---- - -This is a detailed reference for the `StackApp` object. If you're looking for a more high-level overview, please read the [respective page in the Concepts section](../../concepts/stack-app.mdx). - -## Overview - -- [StackClientApp](#stackclientapp) - Client-level permissions for frontend code -- [StackServerApp](#stackserverapp) - Server-level permissions with full access - -# StackClientApp - -A [`StackApp`](../../concepts/stack-app.mdx) with client-level permissions. It contains most of the useful methods and hooks for your client-side code. - -{/* IF_PLATFORM: react-like */} -Most commonly you get an instance of `StackClientApp` by calling [`useStackApp()`](../hooks/use-stack-app.mdx) in a Client Component. -{/* END_PLATFORM */} - -## Table of Contents - ; //$stack-link-to:#stackclientappgetuseroptions - // NEXT_LINE_PLATFORM react-like - ⤷ useUser([options]): User; //$stack-link-to:#stackclientappuseuseroptions - getProject(): Promise; //$stack-link-to:#stackclientappgetproject - // NEXT_LINE_PLATFORM react-like - ⤷ useProject(): Project; //$stack-link-to:#stackclientappuseproject - - signInWithOAuth(provider): void; //$stack-link-to:#stackclientappsigninwithoauthprovider - signInWithCredential([options]): Promise<...>; //$stack-link-to:#stackclientappsigninwithcredentialoptions - signUpWithCredential([options]): Promise<...>; //$stack-link-to:#stackclientappsignupwithcredentialoptions - sendForgotPasswordEmail(email): Promise<...>; //$stack-link-to:#stackclientappsendforgotpasswordemailemail - sendMagicLinkEmail(email): Promise<...>; //$stack-link-to:#stackclientappsendmagiclinkemailemail - };`} /> - -## Constructor - - - - - -Creates a new `StackClientApp` instance. - -Because each app creates a new connection to Stack Auth's backend, you should re-use existing instances wherever possible. - -{/* IF_PLATFORM: react-like */} - -This object is not usually constructed directly. More commonly, you would construct a [`StackServerApp`](#stackserverapp) instead, pass it into a [``](../../components/stack-provider.mdx), and then use `useStackApp()` hook to obtain a `StackClientApp`. - -The [setup wizard](../../getting-started/setup.mdx) does these steps for you, so you don't need to worry about it unless you are manually setting up Stack Auth. - -If you're building a client-only app and don't have a [`SECRET_SERVER_KEY`](../../rest-api/overview#should-i-use-client-or-server-access-type), you can construct a `StackClientApp` directly. - -{/* END_PLATFORM */} - -**Parameters:** - -
- - An object containing multiple properties. - - - - - -
- -
- - -### Signature - -```typescript -declare new(options: { - tokenStore: "nextjs-cookie" | "cookie" | { accessToken: string, refreshToken: string } | Request; - baseUrl?: string; - projectId?: string; - publishableClientKey?: string; - urls: { - ... - }; - noAutomaticPrefetch?: boolean; -}): StackClientApp; -``` - -### Examples - - - - Creating new app - Using useStackApp - - -```typescript -const stackClientApp = new StackClientApp({ - tokenStore: "nextjs-cookie", - baseUrl: "https://api.stack-auth.com", - projectId: "123", - publishableClientKey: "123", - urls: { - home: "/", - }, -}); -``` - - -{/* IF_PLATFORM: react-like */} -```typescript -"use client"; - -function MyReactComponent() { - const stackClientApp = useStackApp(); -} -``` -{/* END_PLATFORM */} - - - - -
-
- - - - - -Gets the current user. - -**Parameters:** -- `options?` (object) - Optional configuration - - `or?` - What to do if user not found: `"return-null"` | `"redirect"` | `"throw"` - -**Returns:** `Promise` - The current user, or `null` if not signed in - - - - -### Signature - -```typescript -declare function getUser( - options?: { - or?: "return-null" | "redirect" | "throw" - } -): Promise; -``` - -### Examples - -```typescript -// Basic usage -const userOrNull = await stackClientApp.getUser(); -console.log(userOrNull); // null if not signed in - -// With redirect on no user -const user = await stackClientApp.getUser({ or: "redirect" }); -console.log(user); // always defined; redirects to sign-in page if not signed in -``` - - - - - -{/* IF_PLATFORM: react-like */} - - - - -React hook version of `getUser()`. Functionally equivalent to [`getUser()`](#stackclientappgetuseroptions), but as a React hook. - -Equivalent to the [`useUser()`](../hooks/use-user.mdx) standalone hook (which is an alias for `useStackApp().useUser()`). - -**Parameters:** -- `options?` (object) - Same as `getUser()` - -**Returns:** `CurrentUser | null` - - - - -### Signature - -```typescript -declare function useUser( - options?: { - or?: "return-null" | "redirect" | "throw" - } -): CurrentUser | null; -``` - -### Examples - - - - Basic Usage - With Redirect - Page Protection - - -```jsx -"use client"; - -function MyReactComponent() { - const user = useUser(); - return user ?
Hello, {user.name}
- :
Not signed in
; -} -``` -
- -```tsx -"use client"; - -function MyReactComponent() { - const user = useUser(); - console.log(user); // null if not signed in - - const user = useUser({ or: "redirect" }); // redirects to sign-in page if necessary - console.log(user); // always defined - - const user = useUser({ or: "throw" }); // throws an error if not signed in - console.log(user); // always defined -} -``` - - -```tsx -"use client"; - -function MyProtectedComponent() { - // Note: This component is protected on the client-side. - // It does not protect against malicious users, since - // they can just comment out the `useUser` call in their - // browser's developer console. - // - // For server-side protection, see the Stack Auth documentation. - - useUser({ or: "redirect" }); - return
You can only see this if you are authenticated
; -} -``` -
-
- -
-
-
-{/* END_PLATFORM */} - - - - - -Gets the current project. - -**Parameters:** -- No parameters - -**Returns:** `Promise` - - - - -### Signature - -```typescript -declare function getProject(): Promise; -``` - -### Examples - -```typescript -const project = await stackClientApp.getProject(); -``` - - - - - - - -{/* IF_PLATFORM: react-like */} - - - -React hook version of `getProject()`. - -**Parameters:** -- No parameters - -**Returns:** `Project` - - - -### Signature - -```typescript -declare function useProject(): Project; -``` - -### Examples -getting the current project in a react component -```typescript -function MyReactComponent() { - const project = useProject(); -} -``` - - - -{/* END_PLATFORM */} - - - - - -Initiates the OAuth sign-in process with the specified provider. - -**Parameters:** -- `provider` (string) - The OAuth provider type - -**Returns:** `Promise` - - - - -### Signature - -```typescript -declare function signInWithOAuth(provider: string): Promise; -``` - -### Examples - -```typescript -await stackClientApp.signInWithOAuth("google"); -``` - - - - - - - - - -Sign in using email and password credentials. - -**Parameters:** -- `options` (object) - - `email` (string) - User's email - - `password` (string) - User's password - - `noRedirect?` (boolean) - Whether to skip redirect after sign-in - -**Returns:** `Promise>` - - - - -### Signature - -```typescript -declare function signInWithCredential(options: { - email: string; - password: string; - noRedirect?: boolean; -}): Promise>; -``` - -### Examples - -```typescript -const result = await stackClientApp.signInWithCredential({ - email: "test@example.com", - password: "password", -}); - -if (result.status === "error") { - console.error("Sign in failed", result.error.message); -} -``` - - - - - - - - - -Sign up using email and password credentials. - -**Parameters:** -- `options` (object) - - `email` (string) - User's email - - `password` (string) - User's password - - `noRedirect?` (boolean) - Whether to skip redirect after sign-up - -**Returns:** `Promise>` - - - - -### Signature - -```typescript -declare function signUpWithCredential(options: { - email: string; - password: string; - noRedirect?: boolean; -}): Promise>; -``` - -### Examples - -```typescript -const result = await stackClientApp.signUpWithCredential({ - email: "test@example.com", - password: "password", -}); - -if (result.status === "error") { - console.error("Sign up failed", result.error.message); -} -``` - - - - - - - - - -Send a forgot password email to an email address. - -**Parameters:** -- `email` (string) - The email to send the forgot password email to - -**Returns:** `Promise>` - - - - -### Signature - -```typescript -declare function sendForgotPasswordEmail(email: string): Promise>; -``` - -### Examples - -```typescript -const result = await stackClientApp.sendForgotPasswordEmail("test@example.com"); - -if (result.status === "success") { - console.log("Forgot password email sent"); -} else { - console.error("Failed to send forgot password email", result.error.message); -} -``` - - - - - - - - - -Send a magic link/OTP sign-in email to an email address. - -**Parameters:** -- `email` (string) - The email to send the magic link to - -**Returns:** `Promise>` - - - - -### Signature - -```typescript -declare function sendMagicLinkEmail(email: string): Promise>; -``` - -### Examples - -```typescript -const result = await stackClientApp.sendMagicLinkEmail("test@example.com"); -``` - - - - - ---- - -# StackServerApp - -Like `StackClientApp`, but with [server permissions](../../concepts/stack-app.mdx#client-vs-server). Has full read and write access to all users. - - -Since this functionality should only be available in environments you trust (ie. your own server), it requires a [`SECRET_SERVER_KEY`](../../rest-api/overview.mdx). -In some cases, you may want to use a [`StackServerApp`](#stackserverapp) on the client; an example for this is an internal dashboard that only your own employees have access to. -We generally recommend against doing this unless you are aware of and protected against the (potentially severe) secutiry implications of -exposing [`SECRET_SERVER_KEY`](../../rest-api/overview.mdx) on the client. - - -## Table of Contents - ; //$stack-link-to:#stackserverappgetuseridoptions - // NEXT_LINE_PLATFORM react-like - ⤷ useUser([id][, options]): ServerUser; //$stack-link-to:#stackserverappuseuseridoptions - listUsers([options]): Promise; //$stack-link-to:#stackserverapplistusersoptions - // NEXT_LINE_PLATFORM react-like - ⤷ useUsers([options]): ServerUser[]; //$stack-link-to:#stackserverappuseusersoptions - createUser([options]): Promise; //$stack-link-to:#stackserverappcreateuseroptions - - getTeam(id): Promise; //$stack-link-to:#stackserverappgetteamid - // NEXT_LINE_PLATFORM react-like - ⤷ useTeam(id): ServerTeam; //$stack-link-to:#stackserverappuseteamid - listTeams(): Promise; //$stack-link-to:#stackserverapplistteams - // NEXT_LINE_PLATFORM react-like - ⤷ useTeams(): ServerTeam[]; //$stack-link-to:#stackserverappuseteams - createTeam([options]): Promise; //$stack-link-to:#stackserverappcreateteamoptions - }`} /> - -## Constructor - - - - - Creates a new `StackClientApp` instance. - -**Parameters:** - - - An object containing multiple properties. - - - - The secret server key of the app, as found on Stack Auth's dashboard. Defaults to the value of the `SECRET_SERVER_KEY` environment variable. - - - - - - - -### Signature - -```typescript -declare new(options: { - tokenStore: "nextjs-cookie" | "cookie" | { accessToken: string, refreshToken: string } | Request; - baseUrl?: string; - projectId?: string; - publishableClientKey?: string; - urls: { - ... - }; - noAutomaticPrefetch?: boolean; -}): StackServerApp; -``` - -### Examples - - - - Create a StackServerApp with a custom sign-in page - - - ```typescript - const stackServerApp = new StackServerApp({ - tokenStore: "nextjs-cookie", - urls: { - signIn: '/my-custom-sign-in-page', - }, - }); - ``` - - - - - - - - - - - - -Enhanced version of `StackClientApp.getUser()` with server permissions. - -**Overloads:** -1. `getUser(id: string): Promise` - Get user by ID -2. `getUser(options?: { or?: "return-null" | "redirect" | "throw" }): Promise` - Get current user - - - - -### Signature - -```typescript -// This function has two overloads: -declare function getUser(id: string): Promise; -declare function getUser( - options?: { - or?: "return-null" | "redirect" | "throw" - } -): Promise; -``` - -### Examples - - - - Get Current User - Get User by ID - - -```typescript -const user = await stackServerApp.getUser(); -console.log(user); // CurrentServerUser -``` - - -```typescript -const user = await stackServerApp.getUser("12345678-1234-1234-1234-123456789abc"); -console.log(user); // ServerUser -``` - - - - - - - -{/* IF_PLATFORM react-like */} - -Functionally equivalent to [`getUser()`](#stackserverappgetuserid-options), but as a React hook. - - -This should be used on the server-side only. - - -{/* END_PLATFORM */} - - - - - -Lists all users on the project. - -**Parameters:** - -
- - An object containing multiple properties. - - - The cursor to start the result set from. - - - The maximum number of items to return. If not provided, it will return all users. - - - The field to sort the results by. Currently, only `signedUpAt` is supported. - - - Whether to sort the results in descending order. - - - A query to filter the results by. This is a free-text search on the user's display name and emails. - - - -
- -**Returns:** `Promise` - -
- - -### Signature - -```typescript -declare function listUsers(options?: { - cursor?: string; - limit?: number; - orderBy?: "signedUpAt"; - desc?: boolean; - query?: string; -}): Promise; -``` - -### Examples - -```typescript -const users = await stackServerApp.listUsers({ limit: 20 }); -console.log(users); - -if (users.nextCursor) { - const nextPageUsers = await stackServerApp.listUsers({ - cursor: users.nextCursor, - limit: 20 - }); - console.log(nextPageUsers); -} -``` - -
-
- -{/* IF_PLATFORM react-like */} - - -Functionally equivalent to [`listUsers()`](#stackserverapplistusersoptions), but as a React hook. - - This should be used on the server-side only. - - -{/* END_PLATFORM */} - - - - - - -Creates a new user from the server. - -**Parameters:** -- `options?` (object) - - `primaryEmail?` (string) - User's primary email - - `primaryEmailVerified?` (boolean) - Whether email is verified - - `primaryEmailAuthEnabled?` (boolean) - Whether email auth is enabled - - `password?` (string) - User's password - - `otpAuthEnabled?` (boolean) - Enable OTP/magic link auth - - `displayName?` (string) - User's display name - -**Returns:** `Promise` - - - - - -### Signature - -```typescript -declare function createUser(options?: { - primaryEmail?: string; - primaryEmailVerified?: boolean; - primaryEmailAuthEnabled?: boolean; - password?: string; - otpAuthEnabled?: boolean; - displayName?: string; -}): Promise; -``` - -### Examples - - - - Password Auth - Magic Link Auth - - -```typescript -const user = await stackServerApp.createUser({ - primaryEmail: "test@example.com", - primaryEmailAuthEnabled: true, - password: "password123", -}); -``` - - -```typescript -const user = await stackServerApp.createUser({ - primaryEmail: "test@example.com", - primaryEmailVerified: true, - primaryEmailAuthEnabled: true, - otpAuthEnabled: true, -}); -``` - - - - - - - -## Team Management - - - - - -Get a team by its ID. - -**Parameters:** -- `id` (string) - Team ID - -**Returns:** `Promise` - - - - -### Signature - -```typescript -declare function getTeam(id: string): Promise; -``` - -### Examples - -```typescript -const team = await stackServerApp.getTeam("team_id_123"); -``` - - - - - -{/* IF_PLATFORM react-like */} - - -Functionally equivalent to [`getTeam(id)`](#stackserverappgetteamid), but as a React hook. - - This should be used on the server-side only. - - -{/* END_PLATFORM */} - - - - - Lists all teams on the current project. - -**Returns:** `Promise` - - - ### Signature - - ```typescript - declare function listTeams(): Promise; - ``` - - ### Examples - - ```typescript - const teams = await stackServerApp.listTeams(); - console.log(teams); - ``` - - - - - -{/* IF_PLATFORM react-like */} - - -Functionally equivalent to [`listTeams()`](#stackserverapplistteams), but as a React hook. - - This should be used on the server-side only. - - -{/* END_PLATFORM */} - - - - - -Creates a team without adding a user to it. - -**Parameters:** -- `data` (object) - - `displayName` (string) - Team display name - - `profileImageUrl?` (string | null) - Team profile image URL - -**Returns:** `Promise` - - - - -### Signature - -```typescript -declare function createTeam(data: { - displayName: string; - profileImageUrl?: string | null; -}): Promise; -``` - -### Examples - -```typescript -const team = await stackServerApp.createTeam({ - displayName: "New Team", - profileImageUrl: "https://example.com/profile.jpg", -}); -``` - - -