JavaScript client
npm install @getstead/client@0.2.0The package exports SteadClient, SteadAuth, SteadApiError, applyEvent, isTerminal, and their TypeScript types. It works with standard Fetch and streaming response bodies. React bindings are a separate package.
SteadClient
Section titled “SteadClient”import { SteadClient } from '@getstead/client';
export function connect(token: string | (() => Promise<string>)) { return new SteadClient({ url: 'https://api.getstead.dev', token });}| Constructor option | Meaning |
|---|---|
url |
API base URL. Use https://api.getstead.dev. |
token |
Bearer string or sync/async function returning one. Customer token in frontend; project secret only on trusted backends. |
reconnectDelayMs |
Initial stream retry delay; default 250 ms. |
maxReconnectDelayMs |
Backoff ceiling; default 5000 ms. |
maxConnectAttempts |
Consecutive attempts without stream progress; default 20. Infinity opts into unlimited retries. |
fetch |
Optional Fetch implementation. |
All request methods below accept an optional final options object with signal?: AbortSignal. Aborting the HTTP request does not cancel an acknowledged run.
| Method | Authority and result |
|---|---|
startRun(scenario, options?) |
Customer or project. Returns { run, outcome }. Customer scenario accepts agent, optional input, async, conversationId. |
cancelRun(runId, options?) |
Customer’s own run or project. Returns { run: { id, status, cancelRequestedAt } }. |
resolveApproval(approvalId, decision, options?) |
Project only. Decision is 'approved' or 'denied'; returns { approval }. |
exchangeToken(externalId, options?) |
Project only. Returns { token, expiresAt, endUser: { id, externalId } }. |
createConversation(agent, { key?, signal? }?) |
Customer only. Returns { conversation: { id, created } }. |
listConversationMessages(id, { cursor?, limit?, signal? }?) |
Customer’s own conversation. Returns { messages, nextCursor? }. |
select<Row>(table, { where?, limit?, signal? }?) |
Customer only. Returns { rows: Row[], rowCount }. The generic describes your data; it does not validate it at runtime. |
streamRun(runId, options?) |
Project’s run or customer’s own run. Returns a RunStream immediately. |
Successful JSON responses also carry the wire’s ok: true. outcome contains status and may include approvalId or failure. Customer run summaries expose id, endUserId, and status; project summaries additionally include agent ID, timestamps, budget, spend, and recovery/cancellation details. Dollar totals are decimal strings in run summaries.
For project starts, StartRunScenario requires the server’s scenario contract: agent, endUser, and steps, with optional budget, tools, and async. To resume, send resume without redefining the program. Version 0.2.0’s TypeScript steps type represents tool steps; use the HTTP contract for project scenarios containing model steps. Customer starts do not need to send steps.
RunStream
Section titled “RunStream”Options: lastEventId?: number resumes after that sequence, signal closes the local stream on abort, connect: false defers dialing, and maxConnectAttempts overrides the client setting.
The stream implements AsyncIterable<RunStreamItem> and provides:
| Member | Contract |
|---|---|
state |
Stable snapshot with runStatus, approvalId, lastEventId, connection, and error. |
done |
Promise resolving when the stream ends or is closed; rejects on permanent refusal or exhausted retries. Local close need not mean the run is terminal. |
subscribe(listener) |
Notify on state changes; returns an unsubscribe function. |
connect() |
Start a deferred connection; idempotent. |
close() |
Stop watching. Does not cancel the server run. |
Iterator items have one of two shapes:
type Item = | { kind: 'event'; seq: number; type: string; payload: Record<string, unknown> } | { kind: 'model-delta'; stepIndex: number; text: string };Durable events resume by sequence. Temporary deltas do not replay; use completed results to reconcile displayed text. The local iterator buffer is bounded; if you need full history later, open a stream from your saved durable cursor. Handle both connection failures and terminal run failures.
SteadAuth
Section titled “SteadAuth”Constructor: { url, projectId, sessionToken?, onSessionToken?, fetch? }. url must use HTTPS, except loopback HTTP development; it cannot contain credentials, query, or fragment. projectId is a UUID. onSessionToken(token | undefined) lets your app persist or clear the signed customer session.
| Method | Parameters and behavior |
|---|---|
signUp({ name, email, password, callbackURL }) |
Register and request verification. Resolves void. |
signIn({ email, password }) |
Obtain the customer session. Clears a previous session before signing in. |
signOut() |
Clear locally and request server sign-out. |
sendVerificationEmail(email, callbackURL) |
Request a new verification email. |
requestPasswordReset(email, redirectTo) |
Request a password reset email. |
resetPassword(token, newPassword) |
Complete reset and clear the local session. |
getToken() |
Return a customer token, cached until 30 seconds before expiry; coalesces simultaneous refreshes. Pass this method directly as SteadClient.token. |
Auth requests have a 30-second timeout, omit ambient cookies, and refuse redirects. Callbacks must use an allowed application origin. See the authentication guide for a complete flow and storage tradeoffs.
Errors
Section titled “Errors”SteadApiError extends Error and has code: string, status: number, and message. HTTP refusal codes come from the server. Non-JSON responses become internal errors. Transport failures may be ordinary Fetch errors rather than SteadApiError.
import { SteadApiError } from '@getstead/client';
export function describeFailure(error: unknown): string { if (error instanceof SteadApiError) { return `${error.status} ${error.code}: ${error.message}`; } return error instanceof Error ? error.message : 'Request failed';}Render errors as text, not HTML. Preserve an opaque request reference when reporting a server failure, but remove credentials and private payloads.
Vite integration
Section titled “Vite integration”The package’s /vite export prevents dependency prebundling from breaking stream parsing:
import { defineConfig } from 'vite';import { getsteadClient } from '@getstead/client/vite';
export default defineConfig({ plugins: [getsteadClient()] });Keep your other Vite plugins as well. The starter already includes this configuration.
State helpers and types
Section titled “State helpers and types”applyEvent(state, seq, type, payload) mutates a FoldState (runStatus, approvalId, lastEventId) from a durable event. Unknown event types advance the cursor without inventing a status. isTerminal(status) recognizes completed, failed, budget-exceeded, and cancelled.
Exported types include SteadClientOptions, SteadToken, SteadAuthOptions, RequestOptions, StartRunScenario, StartRunResult, RunSummary, EndUserRunSummary, CancelRunResult, ResolveApprovalResult, ExchangeTokenResult, CreateConversationResult, ConversationMessage, ListConversationMessagesResult, SelectResult, FoldState, RunStream, RunStreamItem, RunStreamOptions, RunStreamState, RunStatus, and ConnectionStatus.