# @faustine-ai/next reference

`@faustine-ai/next` mounts a Web Agent in a Next.js app, signs the user's identity on the server and runs the adapter's route handler. This page describes version 0.1.5.

## Usage

```bash
npm install @faustine-ai/next @faustine-ai/web-agent
```

The package has two entry points. Import the component from `@faustine-ai/next/client` and everything else from `@faustine-ai/next`, which is for server code.

| Export | Entry point | Works with |
| --- | --- | --- |
| `FaustineAgent` | `@faustine-ai/next/client` | App Router, Pages Router |
| `faustineIdentityToken` | `@faustine-ai/next` | App Router, Pages Router |
| `createRegistry` | `@faustine-ai/next` | App Router |
| `createFaustineHandler` | `@faustine-ai/next` | App Router |
| `withFaustine` | `@faustine-ai/next` | App Router |

Peer dependencies: `next` 14 or later, `react` 18 or later, `@faustine-ai/web-agent` 0.2.0 or later.

## FaustineAgent

A client component that starts the agent once and renders nothing. Render it one time, from the root layout or `pages/_app.tsx`.

```tsx filename="app/faustine-agent.tsx"
'use client';
import { FaustineAgent } from '@faustine-ai/next/client';

export default function Agent({ identityJwt }: { identityJwt?: string | null }) {
  return <FaustineAgent agentId="<AGENT_ID>" identityJwt={identityJwt} />;
}
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `agentId` | `string` | Required | The Web Agent's ID. |
| `env` | `string` | `Production` | The name of the environment to load. Without it, the agent loads Production, or its first environment while it has no Production. |
| `identityJwt` | `string \| null` | None | A token from `faustineIdentityToken`. When set, the component calls `identify({ jwt })`. Without it the visitor is anonymous. The component does not call `logout`: when the user signs out of your app, call `logout` from `@faustine-ai/web-agent`. |
| `debug` | `boolean` | `false` | Opens a debug session for the agent's **Tests** tab. For development and staging builds only. |

The component calls `Faustine.init` from `@faustine-ai/web-agent` in an effect. React Strict Mode runs the effect twice and the second call returns the same instance.

## faustineIdentityToken

```ts
faustineIdentityToken(user: IdentityUser, options?: IdentityTokenOptions): string
```

Signs the identity token for a user with HS256 and returns it. Call it in server code only.

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `user.id` | `string` | Required | Your ID for the user. Becomes the `sub` claim. |
| `user.name` | `string \| null` | None | Shown in the agent's **Monitoring** tab. |
| `user.email` | `string \| null` | None | Shown in the agent's **Monitoring** tab. |
| `options.secret` | `string` | `process.env.FAUSTINE_IDENTITY_SECRET` | The agent's identity secret. |
| `options.expiresIn` | `number` | `3600` | Lifetime of the token in seconds. |

The token has the claims `sub`, `iat` and `exp`, plus `name` and `email` when given. The function throws when there is no secret or no `user.id`.

```ts
import { faustineIdentityToken } from '@faustine-ai/next';

const identityJwt = faustineIdentityToken(
  { id: user.id, name: user.name, email: user.email },
  { expiresIn: 900 },
);
```

## createRegistry

```ts
createRegistry(meta: RegistryMeta, map: Record<string, OperationBinding>): Registry
```

Builds the registry the handler serves. `npx faustine-next init` generates the call in `faustine/registry.ts`. The names are validated when the module loads, so a malformed registry fails the build of your app.

| Parameter | Type | Description |
| --- | --- | --- |
| `meta.webAgent` | `string` | Required. The ID of the Web Agent the registry belongs to. |
| `meta.formatVersion` | `number` | The registry format. `1` in this version, and any other value throws. |
| `map` | `Record<string, OperationBinding>` | One entry per operation. The key is the operation name, `module.action` in camelCase, such as `deals.createDeal`. |

Each binding has these fields.

| Field | Type | Description |
| --- | --- | --- |
| `fn` | `() => Promise<Function> \| Function` | Required. Loads the function on first use, with a dynamic `import()`. |
| `params` | `OperationParam[]` | The function's parameters in order: a name for a plain value, or `{ name, kind }` with `kind` set to `'value'`, `'formData'` or `'prevState'`. |
| `schema` | `() => Promise<OperationSchema> \| OperationSchema` | Loads a validator for the input: an object with `safeParse` or `parse`, such as a Zod schema, or a function that throws. |
| `confirm` | `boolean` | A hint that the agent asks the user before it runs the operation. The portal's setting takes precedence. |

How `params` maps the JSON input to the call:

| `params` | Call |
| --- | --- |
| Absent | `fn(input)` |
| One value parameter | `fn(input)`. An input of the form `{ <name>: value }` with that single key is unwrapped to `value`. |
| One `formData` parameter | `fn(formData)`, built from the input's fields. Arrays repeat the field and objects are sent as JSON strings. |
| Several parameters | `fn(input.a, input.b, …)`, each read by name. |
| A `prevState` parameter | Receives `undefined`. |

The returned `Registry` has `webAgent`, `formatVersion`, `operations` (the names, sorted), `hash` (16 hexadecimal characters) and `bindings`.

## createFaustineHandler

```ts
createFaustineHandler(registry: Registry, options?: FaustineHandlerOptions): { GET, POST }
```

Returns the two functions of the catch-all route handler.

```ts filename="app/api/faustine/[...op]/route.ts"
import { createFaustineHandler } from '@faustine-ai/next'
import registry from '@/faustine/registry'

export const { GET, POST } = createFaustineHandler(registry)
```

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `env` | `string` | `process.env.FAUSTINE_ENV`, then `Production` | The environment whose served version decides which operations are enabled. |
| `manifestTtlMs` | `number` | `60000` | How long the list of enabled operations is reused before the handler asks Faustine again. |
| `buildSha` | `string \| null` | Read from the environment | The commit of the build. See [Next.js on Faustine](https://docs.faustine.ai/technologies/nextjs/). |
| `onRun` | `(info) => void` | None | Called after each `POST` with `{ operation, ok, ms, status }`, for your own logging. |

### `GET /api/faustine/manifest`

Answers what the build serves. Any other `GET` path answers `404`.

| Field | Description |
| --- | --- |
| `webAgent` | The Web Agent ID in the registry. |
| `formatVersion` | The registry format. |
| `registryHash` | The registry's hash. |
| `buildSha` | The commit of the build, or `null`. |
| `operations` | The bound operations: `{ op, schema, confirm }` for each. |
| `enabled` | The bound operations the agent can call at that moment, or `null` when Faustine could not be reached. |
| `served` | `ok`, `none` when the served version enables no adapter operation, or `unreachable`. |

### `POST /api/faustine/<operation>`

Runs the bound function with the JSON body as input. An empty body is an empty object. If the binding has a `schema`, the function receives the validated value.

| Status | Body | When |
| --- | --- | --- |
| `200` | `{ ok: true, result }` | The function returned. `result` is `null` when it returned nothing. |
| `200` | `{ ok: true, result: null, kind: "redirect", url, permanent }` | The function called `redirect()`. |
| `200` | `{ ok: true, result: null, kind: "notFound" }` | The function called `notFound()`. |
| `400` | `{ error: "invalid_json" }` | The body is not JSON. |
| `403` | `{ error: "origin" }` | The `Origin` header names another host. |
| `403` | `{ error: "operation_disabled" }` | The operation is not enabled in the served version. |
| `404` | `{ error: "unknown_operation" }` | The operation is not in the registry. |
| `422` | `{ error: "invalid_input", issues }` | The `schema` rejected the input. |
| `500` | `{ error: "operation_failed" }` | The function threw. `message` is the error's message. |
| `503` | `{ error: "manifest_unavailable" }` | Faustine could not be reached to confirm what is enabled. |

Every error body also has a `message`. Every response has the `x-faustine-registry` header with the registry hash, and `x-faustine-build` when the build's commit is known.

When a request to Faustine fails, the handler reuses the last list of enabled operations for up to 10 times `manifestTtlMs`.

## withFaustine

```ts
withFaustine(nextConfig?: NextConfig): NextConfig
```

Wraps the Next.js config and sets `env.FAUSTINE_BUILD_SHA` to the commit of the build. It reads the first of these variables that is set: `FAUSTINE_BUILD_SHA`, `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`, `CF_PAGES_COMMIT_SHA`, `COMMIT_REF`, `SOURCE_VERSION`. With none set it returns the config unchanged.

```ts filename="next.config.ts"
import type { NextConfig } from 'next';
import { withFaustine } from '@faustine-ai/next';

const nextConfig: NextConfig = {};

export default withFaustine(nextConfig);
```

## Environment variables

| Variable | Read by | Description |
| --- | --- | --- |
| `FAUSTINE_IDENTITY_SECRET` | `faustineIdentityToken` | The agent's identity secret. Server only. |
| `FAUSTINE_ENV` | `createFaustineHandler` | The environment whose enabled operations the handler serves. Default `Production`. |
| `FAUSTINE_BUILD_SHA` | `withFaustine`, `createFaustineHandler` | The commit of the build, when the hosting platform does not set one of the variables above. |

## Other exports

The server entry point also exports the types `OperationBinding`, `OperationFn`, `OperationName`, `OperationParam`, `OperationParamKind`, `OperationSchema`, `Registry`, `RegistryMeta`, `FaustineHandlerOptions`, `ManifestResponse`, `ServedManifest`, `IdentityUser` and `IdentityTokenOptions`. The client entry point exports the type `FaustineAgentProps`.

## Next steps

- [faustine-next CLI](https://docs.faustine.ai/reference/faustine-next-cli/): the generator that writes the registry and the route handler.
- [The Faustine adapter for Next.js](https://docs.faustine.ai/web-agents/nextjs-adapter/): how the registry and the handler fit together.
- [JavaScript API](https://docs.faustine.ai/reference/javascript-api/): the `init` and `identify` calls the component makes, and `logout`, which you call yourself.
