React
@everscribe/components-react is the React adapter for the embeddable audit-trail UI. <AuditTrail /> mounts in any React 18+ app and renders a live, scoped view of your end-user's audit trail.
Source: packages/react
Install
npm install @everscribe/components-react @everscribe/components-styles
Peer dependencies: react >=18, react-dom >=18. The styles package ships the default CSS theme — install it alongside.
Quickstart
import { AuditTrail } from "@everscribe/components-react";
import "@everscribe/components-styles/default.css";
export function AuditPage() {
return <AuditTrail tokenEndpoint="/api/embed-token" />;
}
tokenEndpoint is a route on your server (not Everscribe's) that returns { token }. The component fetches it on mount, holds it in memory, and re-fetches from the same endpoint on 401. Your project API key never touches the browser. See Overview → Minting tokens for the backend side.
If your React app and backend share an origin, a relative path (/api/embed-token) works too.
Already have a token
If you'd rather control the initial fetch yourself — explicit loading states, integration with an auth context, or a token already in hand — pass it as the token prop:
import { useEffect, useState } from "react";
import { AuditTrail } from "@everscribe/components-react";
import "@everscribe/components-styles/default.css";
export function AuditPage() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
fetch("/api/embed-token", { credentials: "include" })
.then((r) => r.json())
.then(({ token }) => setToken(token));
}, []);
if (!token) return <div>Loading…</div>;
return <AuditTrail token={token} tokenEndpoint="/api/embed-token" />;
}
Pass tokenEndpoint (or onTokenExpired) alongside token so refresh on 401 still works.
If you pass none of token, tokenEndpoint, or onTokenExpired, the component renders a configuration error.
Props
At least one of token, tokenEndpoint, or onTokenExpired is required.
| Prop | Type | Default | Notes |
|---|---|---|---|
token |
string |
— | Embed JWT. If omitted, the component fetches one via tokenEndpoint/onTokenExpired on mount. |
tokenEndpoint |
string |
— | URL on your backend returning { token }. Used for the initial fetch (when token is omitted) and for refresh on 401. Sent with credentials: 'include'. |
onTokenExpired |
() => Promise<string> |
— | Custom token-fetch callback. Takes precedence over tokenEndpoint. |
apiBase |
string |
https://api.everscribe.io/v1/embed |
Base URL for read endpoints. Override for local dev or self-hosted. |
pageSize |
number |
25 |
Events per page. |
pollInterval |
number |
5000 |
Poll cadence in ms. <= 0 disables polling. Below 1000 is clamped with a console.warn. |
theme |
'light' | 'dark' |
'light' |
Switches the CSS-variable theme. |
defaultTimeRange |
'24h' | '7d' | '30d' | 'all' |
'all' |
Initial time-range preset for the filters panel. |
className |
string |
— | Merged onto the root element. |
style |
CSSProperties |
— | Inline style on the root. Use to override CSS variables at runtime. |
onError |
(err: Error) => void |
— | Observability hook for fetch errors. |
Persistence
Column visibility and filter state persist to localStorage automatically and restore on mount. Two keys are written, both namespaced by the token's project ID (sub claim) and tenant ID (tenant_id claim, or _ when unset):
audit-trail:cols:{sub}:{tenant_id}— list of hidden columns. Stored as hidden so future-added columns appear by default for returning users.audit-trail:filters:{sub}:{tenant_id}— active filter state: time range, column filters, free-text inputs, DSL query, last NLP echo.
Behavior:
- Restored once the token bootstrap resolves and the JWT is parsed.
- Swapping the
tokenprop to a different project re-restores from that project's storage. - localStorage failures (private browsing, quota exceeded, malformed JSON) are silently swallowed.
- Token claims that restrict columns (
columnsclaim set) take precedence over restored hidden columns.
SSR / Next.js
Marked 'use client' — drop into a Server Component tree as-is. The detail drawer portals to document.body after hydration; persistence useEffects only fire client-side, so they have no SSR side effects.
What next
- Overview — token model, refresh chain, claim-driven UI, rate limits
- Styles — theming via CSS variables
- Embed Tokens — the security model