stack/docs-mintlify/sdk/objects/hexclave-app.mdx
Mantra 74c888fed7
chore(mcp/docs): canonicalize HEXCLAVE_ env vars in docs + raise ask_hexclave step limit & timeout (#1571)
## Summary

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

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

## Changes

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

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

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

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

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

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

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

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

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

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

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

* **Performance & Reliability**
* Increased AI operation timeouts and step limits for certain prompts;
improved generate-mode duration measurement for more accurate logging.
* **Documentation**
* Replaced Stack-branded environment variable names with Hexclave
equivalents across guides and examples.
* Clarified that hexclave dev injects required environment variables
automatically.
  * Added guidance on configuring custom authentication redirect URLs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-11 10:53:53 -07:00

1137 lines
30 KiB
Plaintext

---
title: "StackApp"
description: "Reference documentation for HexclaveClientApp and HexclaveServerApp objects."
sidebarTitle: "StackApp"
mode: "wide"
---
import {
AsideSection,
ContentSection,
MethodAside,
MethodContent,
MethodLayout,
MethodReturns,
} from "/snippets/sdk-type-components.jsx";
This is a detailed reference for the `StackApp` object. For setup instructions, see [Setup](/guides/getting-started/setup).
## Overview
- [HexclaveClientApp](#stackclientapp) - Client-level permissions for frontend code
- [HexclaveServerApp](#stackserverapp) - Server-level permissions with full access
---
# HexclaveClientApp
A `StackApp` with client-level permissions. It contains most of the useful methods and hooks for your client-side code.
Most commonly you get an instance of `HexclaveClientApp` by calling [`useHexclaveApp()`](/sdk/hooks/use-hexclave-app) in a Client Component.
## Table of Contents
```typescript
type HexclaveClientApp = {
new(options): HexclaveClientApp;
getUser([options]): Promise<User>;
useUser([options]): User;
getProject(): Promise<Project>;
useProject(): Project;
signInWithOAuth(provider): void;
signInWithCredential([options]): Promise<...>;
signUpWithCredential([options]): Promise<...>;
sendForgotPasswordEmail(email): Promise<...>;
sendMagicLinkEmail(email): Promise<...>;
};
```
## Constructor
Creates a new `HexclaveClientApp` instance.
Because each app creates a new connection to Hexclave's backend, you should re-use existing instances wherever possible.
<Info>
This object is not usually constructed directly. More commonly, you would construct a [`HexclaveServerApp`](#stackserverapp) instead, pass it into your app setup (see the [setup guide](/guides/getting-started/setup)), and then use the `useHexclaveApp()` hook to obtain a `HexclaveClientApp`.
The [setup wizard](/guides/getting-started/setup) does these steps for you, so you don't need to worry about it unless you are manually setting up Hexclave.
If you're building a client-only app and don't have a `HEXCLAVE_SECRET_SERVER_KEY`, you can construct a `HexclaveClientApp` directly.
</Info>
<MethodLayout>
<MethodContent>
<ContentSection title="Parameters">
<ParamField body="tokenStore" type='"nextjs-cookie" | "cookie" | { accessToken, refreshToken } | Request' required>
Token storage configuration.
</ParamField>
<ParamField body="baseUrl" type="string">
Base URL for the Hexclave API.
</ParamField>
<ParamField body="projectId" type="string">
Project ID. Defaults to the `NEXT_PUBLIC_HEXCLAVE_PROJECT_ID` environment variable.
</ParamField>
<ParamField body="publishableClientKey" type="string">
Publishable client key. Defaults to the `NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY` environment variable.
</ParamField>
<ParamField body="urls" type="object">
Redirect URL configuration.
</ParamField>
<ParamField body="analytics" type="object">
Analytics capture configuration. SDK-managed capture is enabled by default; pass `{ enabled: false }` to disable it entirely (which also avoids the `ANALYTICS_NOT_ENABLED` console warning on projects that haven't enabled the Analytics app), or `{ replays: { enabled: true } }` to record session replays.
</ParamField>
<ParamField body="noAutomaticPrefetch" type="boolean">
Disable automatic prefetching.
</ParamField>
</ContentSection>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare class HexclaveClientApp {
constructor(options: {
tokenStore: "nextjs-cookie" | "cookie" | {
accessToken: string;
refreshToken: string;
} | Request;
baseUrl?: string;
projectId?: string;
publishableClientKey?: string;
urls?: object;
analytics?: object;
noAutomaticPrefetch?: boolean;
});
}
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const hexclaveClientApp = new HexclaveClientApp({
tokenStore: "nextjs-cookie",
baseUrl: "https://api.hexclave.com",
projectId: "123",
publishableClientKey: "123",
urls: {
home: "/",
},
});
```
```typescript
"use client";
function MyReactComponent() {
const hexclaveClientApp = useHexclaveApp();
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
## User Management
### `hexclaveClientApp.getUser([options])`
<MethodLayout>
<MethodContent>
Gets the current user.
<ContentSection title="Parameters">
<ParamField body="options.or" type='"return-null" | "redirect" | "throw"'>
What to do if the user is not found.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<CurrentUser | null>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function getUser(options?: {
or?: "return-null" | "redirect" | "throw";
}): Promise<CurrentUser | null>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const userOrNull = await hexclaveClientApp.getUser();
console.log(userOrNull);
const user = await hexclaveClientApp.getUser({ or: "redirect" });
console.log(user);
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.useUser([options])`
<MethodLayout>
<MethodContent>
React hook version of `getUser()`. Equivalent to the [`useUser()`](/sdk/hooks/use-user) standalone hook, which is an alias for `useHexclaveApp().useUser()`.
<ContentSection title="Parameters">
<ParamField body="options.or" type='"return-null" | "redirect" | "throw"'>
What to do if the user is not found.
</ParamField>
</ContentSection>
<MethodReturns type="CurrentUser | null" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useUser(options?: {
or?: "return-null" | "redirect" | "throw";
}): CurrentUser | null;
```
</AsideSection>
<AsideSection title="Examples">
```jsx
"use client";
function MyReactComponent() {
const user = useUser();
return user ? <div>Hello, {user.name}</div> : <div>Not signed in</div>;
}
```
```tsx
"use client";
function MyProtectedComponent() {
useUser({ or: "redirect" });
return <div>You can only see this if you are authenticated</div>;
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.getProject()`
<MethodLayout>
<MethodContent>
Gets the current project.
<MethodReturns type="Promise<Project>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function getProject(): Promise<Project>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const project = await hexclaveClientApp.getProject();
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.useProject()`
<MethodLayout>
<MethodContent>
React hook version of `getProject()`.
<MethodReturns type="Project" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useProject(): Project;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
function MyReactComponent() {
const project = useProject();
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
## Authentication
### `hexclaveClientApp.signInWithOAuth(provider)`
<MethodLayout>
<MethodContent>
Initiates the OAuth sign-in process with the specified provider.
<ContentSection title="Parameters">
<ParamField body="provider" type="string">
The OAuth provider type.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<void>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function signInWithOAuth(provider: string): Promise<void>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
await hexclaveClientApp.signInWithOAuth("google");
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.signInWithCredential([options])`
<MethodLayout>
<MethodContent>
Sign in using email and password credentials.
<ContentSection title="Parameters">
<ParamField body="options.email" type="string">
User's email.
</ParamField>
<ParamField body="options.password" type="string">
User's password.
</ParamField>
<ParamField body="options.noRedirect" type="boolean">
Whether to skip redirect after sign-in.
</ParamField>
</ContentSection>
<MethodReturns type='Promise<Result<undefined, KnownErrors["EmailPasswordMismatch"]>>' />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function signInWithCredential(options?: {
email?: string;
password?: string;
noRedirect?: boolean;
}): Promise<Result<undefined, KnownErrors["EmailPasswordMismatch"]>>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const result = await hexclaveClientApp.signInWithCredential({
email: "test@example.com",
password: "password",
});
if (result.status === "error") {
console.error("Sign in failed", result.error.message);
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.signUpWithCredential([options])`
<MethodLayout>
<MethodContent>
Sign up using email and password credentials.
<ContentSection title="Parameters">
<ParamField body="options.email" type="string">
User's email.
</ParamField>
<ParamField body="options.password" type="string">
User's password.
</ParamField>
<ParamField body="options.noRedirect" type="boolean">
Whether to skip redirect after sign-up.
</ParamField>
</ContentSection>
<MethodReturns type='Promise<Result<undefined, KnownErrors["UserWithEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]>>' />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function signUpWithCredential(options?: {
email?: string;
password?: string;
noRedirect?: boolean;
}): Promise<Result<
undefined,
KnownErrors["UserWithEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]
>>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const result = await hexclaveClientApp.signUpWithCredential({
email: "test@example.com",
password: "password",
});
if (result.status === "error") {
console.error("Sign up failed", result.error.message);
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.sendForgotPasswordEmail(email)`
<MethodLayout>
<MethodContent>
Send a forgot-password email to an email address.
<ContentSection title="Parameters">
<ParamField body="email" type="string">
The email to send the forgot-password email to.
</ParamField>
</ContentSection>
<MethodReturns type='Promise<Result<undefined, KnownErrors["UserNotFound"]>>' />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function sendForgotPasswordEmail(
email: string,
): Promise<Result<undefined, KnownErrors["UserNotFound"]>>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const result = await hexclaveClientApp.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);
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveClientApp.sendMagicLinkEmail(email)`
<MethodLayout>
<MethodContent>
Send a magic-link or OTP sign-in email to an email address.
<ContentSection title="Parameters">
<ParamField body="email" type="string">
The email to send the magic link to.
</ParamField>
</ContentSection>
<MethodReturns type='Promise<Result<{ nonce: string }, KnownErrors["RedirectUrlNotWhitelisted"]>>' />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function sendMagicLinkEmail(
email: string,
): Promise<Result<{ nonce: string }, KnownErrors["RedirectUrlNotWhitelisted"]>>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const result = await hexclaveClientApp.sendMagicLinkEmail("test@example.com");
```
</AsideSection>
</MethodAside>
</MethodLayout>
---
# HexclaveServerApp
Like `HexclaveClientApp`, but with server permissions. Has full read and write access to all users.
<Warning>
Since this functionality should only be available in environments you trust
(ie. your own server), it requires a `HEXCLAVE_SECRET_SERVER_KEY`. In some cases, you
may want to use a `HexclaveServerApp` 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) security implications of exposing `HEXCLAVE_SECRET_SERVER_KEY` on
the client.
</Warning>
## Table of Contents
```typescript
type HexclaveServerApp =
// Inherits all functionality from HexclaveClientApp
& HexclaveClientApp
& {
new(options): HexclaveServerApp;
getUser([id][, options]): Promise<ServerUser | null>;
useUser([id][, options]): ServerUser;
listUsers([options]): Promise<ServerUser[]>;
useUsers([options]): ServerUser[];
createUser([options]): Promise<ServerUser>;
sendEmail(options): Promise<Result<void, KnownErrors>>;
getTeam(id): Promise<ServerTeam | null>;
useTeam(id): ServerTeam;
listTeams([options]): Promise<ServerTeam[]>;
useTeams([options]): ServerTeam[];
listTeamsPaginated([options]): Promise<{ items: ServerTeam[]; nextCursor: string | null }>;
useTeamsPaginated([options]): { items: ServerTeam[]; nextCursor: string | null };
createTeam([options]): Promise<ServerTeam>;
}
```
## Constructor
Creates a new `HexclaveServerApp` instance.
<MethodLayout>
<MethodContent>
<ContentSection title="Parameters">
<ParamField body="tokenStore" type='"nextjs-cookie" | "cookie" | { accessToken, refreshToken } | Request' required>
Token storage configuration.
</ParamField>
<ParamField body="baseUrl" type="string">
Base URL for the Hexclave API.
</ParamField>
<ParamField body="projectId" type="string">
Project ID.
</ParamField>
<ParamField body="publishableClientKey" type="string">
Publishable client key.
</ParamField>
<ParamField body="secretServerKey" type="string">
Secret server key. Defaults to the `HEXCLAVE_SECRET_SERVER_KEY` environment variable.
</ParamField>
<ParamField body="urls" type="object">
Redirect URL configuration.
</ParamField>
<ParamField body="noAutomaticPrefetch" type="boolean">
Disable automatic prefetching.
</ParamField>
</ContentSection>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare class HexclaveServerApp {
constructor(options: {
tokenStore: "nextjs-cookie" | "cookie" | {
accessToken: string;
refreshToken: string;
} | Request;
baseUrl?: string;
projectId?: string;
publishableClientKey?: string;
secretServerKey?: string;
urls?: object;
noAutomaticPrefetch?: boolean;
});
}
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const hexclaveServerApp = new HexclaveServerApp({
tokenStore: "nextjs-cookie",
urls: {
signIn: "/my-custom-sign-in-page",
},
});
```
</AsideSection>
</MethodAside>
</MethodLayout>
## User Operations
### `hexclaveServerApp.getUser([id], [options])`
<MethodLayout>
<MethodContent>
Enhanced version of `HexclaveClientApp.getUser()` with server permissions.
**Overloads:**
1. `getUser(id: string): Promise<ServerUser | null>` to get a user by ID.
2. `getUser(options?: { or?: "return-null" | "redirect" | "throw" }): Promise<CurrentServerUser | null>` to get the current user.
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function getUser(id: string): Promise<ServerUser | null>;
declare function getUser(options?: {
or?: "return-null" | "redirect" | "throw";
}): Promise<CurrentServerUser | null>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const currentUser = await hexclaveServerApp.getUser();
console.log(currentUser);
const serverUser = await hexclaveServerApp.getUser(
"12345678-1234-1234-1234-123456789abc",
);
console.log(serverUser);
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.useUser([id], [options])`
<MethodLayout>
<MethodContent>
Functionally equivalent to [`getUser()`](#stackserverappgetuserid-options), but as a React hook.
<Info>
This should be used on the server-side only.
</Info>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useUser(
idOrOptions?: string | { or?: "return-null" | "redirect" | "throw" },
options?: { or?: "return-null" | "redirect" | "throw" },
): ServerUser | CurrentServerUser | null;
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.listUsers([options])`
<MethodLayout>
<MethodContent>
Lists all users on the project.
<ContentSection title="Parameters">
<ParamField body="options.cursor" type="string">
The cursor to start the result set from.
</ParamField>
<ParamField body="options.limit" type="number">
Maximum number of items to return. If omitted, all users are returned.
</ParamField>
<ParamField body="options.orderBy" type='"signedUpAt"'>
The field to sort results by.
</ParamField>
<ParamField body="options.desc" type="boolean">
Whether to sort in descending order. Defaults to `false`.
</ParamField>
<ParamField body="options.query" type="string">
Free-text search on the user's display name and emails.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<ServerUser[] & { nextCursor: string | null }>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function listUsers(options?: {
cursor?: string;
limit?: number;
orderBy?: "signedUpAt";
desc?: boolean;
query?: string;
}): Promise<ServerUser[] & { nextCursor: string | null }>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const users = await hexclaveServerApp.listUsers({ limit: 20 });
console.log(users);
if (users.nextCursor) {
const nextPageUsers = await hexclaveServerApp.listUsers({
cursor: users.nextCursor,
limit: 20,
});
console.log(nextPageUsers);
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.useUsers([options])`
<MethodLayout>
<MethodContent>
Functionally equivalent to [`listUsers()`](#stackserverapplistusersoptions), but as a React hook.
<Info>This should be used on the server-side only.</Info>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useUsers(options?: {
cursor?: string;
limit?: number;
orderBy?: "signedUpAt";
desc?: boolean;
query?: string;
}): ServerUser[];
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.createUser([options])`
<MethodLayout>
<MethodContent>
Creates a new user from the server.
<ContentSection title="Parameters">
<ParamField body="options.primaryEmail" type="string">
User's primary email.
</ParamField>
<ParamField body="options.primaryEmailVerified" type="boolean">
Whether the email is verified.
</ParamField>
<ParamField body="options.primaryEmailAuthEnabled" type="boolean">
Whether email auth is enabled.
</ParamField>
<ParamField body="options.password" type="string">
User's password.
</ParamField>
<ParamField body="options.otpAuthEnabled" type="boolean">
Enable OTP or magic-link auth.
</ParamField>
<ParamField body="options.displayName" type="string">
User's display name.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<ServerUser>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function createUser(options?: {
primaryEmail?: string;
primaryEmailVerified?: boolean;
primaryEmailAuthEnabled?: boolean;
password?: string;
otpAuthEnabled?: boolean;
displayName?: string;
}): Promise<ServerUser>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const passwordUser = await hexclaveServerApp.createUser({
primaryEmail: "test@example.com",
primaryEmailAuthEnabled: true,
password: "password123",
});
const magicLinkUser = await hexclaveServerApp.createUser({
primaryEmail: "test@example.com",
primaryEmailVerified: true,
primaryEmailAuthEnabled: true,
otpAuthEnabled: true,
});
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.sendEmail(options)`
<MethodLayout>
<MethodContent>
Send custom emails to users. You can send either custom HTML emails or use predefined templates with variables.
<ContentSection title="Parameters">
<ParamField body="options" type="SendEmailOptions">
Email configuration and content.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<Result<void, KnownErrors>>">
The method returns a `Result` that can include `RequiresCustomEmailServer`, `SchemaError`, and `UserIdDoesNotExist`.
</MethodReturns>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function sendEmail(
options: SendEmailOptions,
): Promise<Result<void, KnownErrors>>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const htmlResult = await hexclaveServerApp.sendEmail({
userIds: ["user-1", "user-2"],
subject: "Welcome to our platform!",
html: "<h1>Welcome!</h1><p>Thanks for joining us.</p>",
});
if (htmlResult.status === "error") {
console.error("Failed to send email:", htmlResult.error);
}
```
```typescript
const templateResult = await hexclaveServerApp.sendEmail({
userIds: ["user-1"],
templateId: "welcome-template",
variables: {
userName: "John Doe",
activationUrl: "https://app.com/activate/token123",
},
});
```
</AsideSection>
</MethodAside>
</MethodLayout>
## Team Management
### `hexclaveServerApp.getTeam(id)`
<MethodLayout>
<MethodContent>
Get a team by its ID.
<ContentSection title="Parameters">
<ParamField body="id" type="string">
Team ID.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<ServerTeam | null>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function getTeam(id: string): Promise<ServerTeam | null>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const team = await hexclaveServerApp.getTeam("team_id_123");
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.useTeam(id)`
<MethodLayout>
<MethodContent>
Functionally equivalent to [`getTeam(id)`](#stackserverappgetteamid), but as a React hook.
<Info>This should be used on the server-side only.</Info>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useTeam(id: string): ServerTeam;
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.listTeams([options])`
<MethodLayout>
<MethodContent>
Lists all teams on the current project.
For cursor-based pagination over teams, see [`listTeamsPaginated`](#stackserverapplistteamspaginatedoptions).
<ContentSection title="Parameters">
<ParamField body="options.orderBy" type='"createdAt"'>
The field to sort results by.
</ParamField>
<ParamField body="options.desc" type="boolean">
Whether to sort in descending order. Defaults to `false`.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<ServerTeam[]>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function listTeams(options?: {
orderBy?: "createdAt";
desc?: boolean;
}): Promise<ServerTeam[]>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const teams = await hexclaveServerApp.listTeams();
console.log(teams);
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.useTeams([options])`
<MethodLayout>
<MethodContent>
Functionally equivalent to [`listTeams()`](#stackserverapplistteamsoptions), but as a React hook.
<Info>This should be used on the server-side only.</Info>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useTeams(options?: {
orderBy?: "createdAt";
desc?: boolean;
}): ServerTeam[];
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.listTeamsPaginated([options])`
<MethodLayout>
<MethodContent>
Lists teams on the current project with cursor-based pagination, optional filtering, and ordering. The returned array carries an extra `nextCursor` property; pass it back as `cursor` to load the next page.
<ContentSection title="Parameters">
<ParamField body="options.cursor" type="string">
Cursor returned as `nextCursor` from a previous response.
</ParamField>
<ParamField body="options.limit" type="number">
Maximum number of items to return. If omitted, all matching teams are returned.
</ParamField>
<ParamField body="options.orderBy" type='"createdAt"'>
The field to sort results by.
</ParamField>
<ParamField body="options.desc" type="boolean">
Whether to sort in descending order. Defaults to `false`.
</ParamField>
<ParamField body="options.query" type="string">
Free-text search on the team's display name (and team ID if the query is a UUID).
</ParamField>
</ContentSection>
<MethodReturns type="Promise<{ items: ServerTeam[]; nextCursor: string | null }>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function listTeamsPaginated(options?: {
cursor?: string;
limit?: number;
orderBy?: "createdAt";
desc?: boolean;
query?: string;
}): Promise<{ items: ServerTeam[]; nextCursor: string | null }>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const teams = await hexclaveServerApp.listTeamsPaginated({ limit: 20 });
console.log(teams);
if (teams.nextCursor) {
const nextPageTeams = await hexclaveServerApp.listTeamsPaginated({
cursor: teams.nextCursor,
limit: 20,
});
console.log(nextPageTeams);
}
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.useTeamsPaginated([options])`
<MethodLayout>
<MethodContent>
Functionally equivalent to [`listTeamsPaginated()`](#stackserverapplistteamspaginatedoptions), but as a React hook.
<Info>This should be used on the server-side only.</Info>
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function useTeamsPaginated(options?: {
cursor?: string;
limit?: number;
orderBy?: "createdAt";
desc?: boolean;
query?: string;
}): { items: ServerTeam[]; nextCursor: string | null };
```
</AsideSection>
</MethodAside>
</MethodLayout>
### `hexclaveServerApp.createTeam([options])`
<MethodLayout>
<MethodContent>
Creates a team without adding a user to it.
<ContentSection title="Parameters">
<ParamField body="options.displayName" type="string">
Team display name.
</ParamField>
<ParamField body="options.profileImageUrl" type="string | null">
Team profile image URL.
</ParamField>
</ContentSection>
<MethodReturns type="Promise<ServerTeam>" />
</MethodContent>
<MethodAside>
<AsideSection title="Signature">
```typescript
declare function createTeam(options?: {
displayName?: string;
profileImageUrl?: string | null;
}): Promise<ServerTeam>;
```
</AsideSection>
<AsideSection title="Examples">
```typescript
const team = await hexclaveServerApp.createTeam({
displayName: "New Team",
profileImageUrl: "https://example.com/profile.jpg",
});
```
</AsideSection>
</MethodAside>
</MethodLayout>