Skip to main content
@archie/js-sdk is the core TypeScript SDK for the Archie backend. It is isomorphic, so the same client runs in the browser and in Node.js. Use it when you build a frontend or a server-side script that talks to an Archie project. The React and Node.js SDKs build on this package.

Install

Quick start

Create a client with createClient, then use its modules.
The client exposes these modules:

archie.auth

Sign up, sign in, sessions, and auth events.

archie.graphql

Queries and mutations.

archie.files

Upload, download, and CSV import.

archie.realtime

GraphQL subscriptions and table channels.

archie.notifications

Live in-app notifications and read state.

archie.rest

Custom REST endpoints.

Configuration

Only projectId is required.

Authorization priority

The SDK picks the Authorization header in this order:
  1. External token. If getAccessToken() returns a token, the SDK sends Authorization: Bearer {token}.
  2. User JWT. After signIn, the SDK sends Authorization: Bearer {jwt}.
  3. API key. The SDK sends Authorization: {apiKey} as-is. Examples: 'anon xxxxx', 'Bearer eyJhbG...'.
  4. Nothing. The SDK sends no Authorization header.

External auth

If your app authenticates users elsewhere, such as Auth0, pass the token through getAccessToken. The SDK calls it on every HTTP request and every WebSocket connect. You never need to recreate the client when the token refreshes.
Writes such as mutations require a real user identity. Use a user token, not an anonymous apiKey.

Auth

Use archie.auth for registration, login, session management, auto-refresh, and auth events.
On page load, the SDK restores the session from storage asynchronously. Wait for it before you check auth state:
onAuthStateChange returns an unsubscribe function.
The SDK refreshes tokens automatically when autoRefreshToken is true. You can also refresh manually or fetch the JSON Web Key Set for server-side JWT verification.
auth.exchangeCode({ code }) redeems a single-use, 60-second code for a normal session as the user the code was issued for, with that user’s real roles. Your server issues the code with POST /auth/admin/exchange-code, which requires an admin key. Never call that endpoint from a browser.
An exchange session has no refresh token. It ends when its access token expires, which is 15 minutes by default (the project’s access-token TTL). With autoRefreshToken on, the SDK emits SESSION_EXPIRING 60 seconds before expiry. Get a fresh code and call exchangeCode again to replace the session in place. If nothing replaces it, SIGNED_OUT fires at expiry.
Failures are AuthErrors. Their code is one of EXCHANGE_CODE_INVALID, EXCHANGE_CODE_EXPIRED, EXCHANGE_CODE_ALREADY_USED, EXCHANGE_USER_NOT_FOUND, EXCHANGE_USER_DISABLED, or EXCHANGE_RATE_LIMITED. Branch on code, never on the message text.

Auto-refresh and persistence

When autoRefreshToken is true (default):
  • After sign in, the SDK schedules a token refresh 60 seconds before expiry.
  • On success, it emits TOKEN_REFRESHED and schedules the next refresh.
  • On failure, it calls signOut() automatically.
When persistSession is true (default):
  • The SDK saves the session after every sign in and token refresh.
  • On client creation, it restores the session from storage.
  • If the stored token has expired, it tries a refresh automatically.
  • The storage key format is archie-auth-{projectId}-{environment}.

GraphQL

Use archie.graphql to run queries and mutations against the /graphql endpoint of the Archie API Manager. query() and mutate() return { data, error }. They do not throw for GraphQL-level errors.

Request options

Both methods accept a third parameter with headers and signal.

Raw request

Use request() when you want the data directly and prefer that errors throw a GraphQLError.

Response shape

Files

Use archie.files to upload, download, and manage files through GraphQL multipart uploads.
upload accepts a File, a Blob, or a Uint8Array. The Uint8Array form also works in Node.js.
getUrl builds the URL locally. It makes no network request.

Realtime

Use archie.realtime for WebSocket subscriptions. It uses the graphql-transport-ws protocol, connects lazily, and reconnects automatically.

Channels

The channel API is a shorter way to listen to table-level events. Event names are INSERT, UPDATE, DELETE, and *.

Connection state

When the connection drops, the SDK reconnects with exponential backoff: 1s, 2s, 4s, 8s, 16s, then 30s at most. The counter resets after a successful connection_ack. The connection closes when the last subscription is unsubscribed. On TOKEN_REFRESHED, the SDK reconnects with the new credentials.

Notifications

Use archie.notifications to receive live in-app notifications and manage read state. receiverId is the authenticated user’s id, available from archie.auth.getUser()?.id.

List, count, and mark as read

list supports keyset pagination through createdBefore. Pass the createdAt of the oldest row you already have to fetch the next older page.
The @archie/react-sdk useNotifications hook does all of this for you. Use the raw options when you paginate outside React.

Notification shape

All fields are camelCase. The SDK normalizes backend inconsistencies before it delivers notifications to you.
The Archie backend enforces authorization, not the SDK. receiverId and notification id are request parameters, not a client-side trust boundary. The backend scopes all reads and writes to the authenticated principal.Treat actionUrl as untrusted data. Before you render it as a link, check that the scheme is http: or https:. Reject javascript: and data: URLs, which enable stored XSS.Treat metadata and params as untrusted too. If you deep-merge them into other objects, use a merge that guards against __proto__, constructor, and prototype keys.

REST

Use archie.rest to call custom REST APIs created through the Archie gateway. The SDK injects the standard headers (x-project-id, authorization, environment) for you.
Every method accepts an options object with headers, params, and signal. REST methods throw ArchieError on non-2xx responses.

Error handling

All SDK errors extend ArchieError.
GraphQL errors from query() and mutate() come back in the response:

Auth error codes

A failed auth.* call throws one of two families. Handle both.
  • The server reached a verdict. Examples: wrong password, unverified email, expired code. The SDK always throws an AuthError, even when the backend reports the rejection as an HTTP 200 with a GraphQL errors[] body. err.message carries the backend’s wording and is safe to show the user.
  • The service could not answer. Examples: network failure, timeout, a 5xx or gateway page. These stay NetworkError or ArchieError. Treat them as unavailability (“try again in a moment”), not as a credential problem.
Do not test only for AuthError. A login form that does goes silent whenever the auth service is down. err.code carries the extensions.code value from the server. When the server sends none, it falls back to AUTH_ERROR.

Automatic 401 retry

When a request returns 401, the SDK refreshes the token and retries the original request. If the refresh fails, it signs the user out and throws the error. Your code does not need to handle this.

Retry and timeout

The SDK retries on these conditions: Non-retryable errors (400, 401, 403, 404, 409, and similar) throw immediately. Backoff is exponential with jitter: delay = min(baseDelay × 2^(attempt-1) + random_jitter, 30s). For timeouts:
  • When timeout > 0, each individual request, including retries, aborts after timeout milliseconds.
  • The SDK throws ArchieError with code: 'TIMEOUT' and status: 408.
  • Set timeout: 0 to disable the timeout.
  • A user-provided AbortSignal takes precedence over the timeout.

Custom fetch

Inject your own fetch for testing, proxies, or edge runtimes such as Cloudflare Workers and Deno.

Health check

ping() returns true when the API responds with a 2xx status and false otherwise. It never throws.

Storage adapters

The SDK persists sessions through a StorageAdapter. The default is localStorage in the browser and memory in Node.js.
Two adapters are built in. Use MemoryStorage for SSR, tests, or environments without localStorage.
You can also write your own, for example with AsyncStorage on React Native:

Logging

Two logger constants are available for the logger option. consoleLogger writes to console.debug, console.info, console.warn, and console.error. noopLogger silences all logging and is the default.

TypeScript types

The package exports all of its types.
Use the interfaces for dependency injection and testing. Use the concrete classes for instanceof checks or advanced typing.