@archie/js-sdk
v0.3.1
Published
Archie BAAS - Core isomorphic TypeScript SDK
Readme
@archie/js-sdk
Core TypeScript SDK for the Archie BAAS platform. Isomorphic — works in both browser and Node.js.
Table of Contents
- Installation
- Quick Start
- Configuration
- Auth Module
- GraphQL Module
- Files Module
- Realtime Module
- Notifications Module
- REST Module
- Error Handling
- Retry & Timeout
- Custom Fetch
- Health Check
- Storage Adapters
- TypeScript Types
Installation
npm install @archie/js-sdk
# or
pnpm add @archie/js-sdkQuick Start
import { createClient } from '@archie/js-sdk';
const archie = createClient({
projectId: 'your-project-uuid',
apiKey: 'anon your-api-key',
apiUrl: 'https://your-project.archiecore.com',
environment: 'master',
});
// Sign in
const { session } = await archie.auth.signIn({
email: '[email protected]',
password: 'secret',
});
// Query data
const { data, error } = await archie.graphql.query('{ users { id email } }');Configuration
const archie = createClient({
// Required
projectId: 'your-project-uuid',
// API key — sent as-is in the Authorization header when no user JWT is present.
// Examples: 'anon xxxxx', 'Bearer eyJhbG...', 'custom-prefix token123'
apiKey: 'anon your-api-key',
// Environment (default: 'master')
environment: 'development',
// Base URLs
apiUrl: 'https://example.platform.com',
authUrl: 'https://example.platform.com', // defaults to apiUrl
realtimeUrl: 'https://example.platform.com', // defaults to apiUrl
// Session behavior
autoRefreshToken: true, // auto-refresh JWT before expiry (default: true)
persistSession: true, // persist session in storage (default: true)
// Custom storage adapter (default: localStorage in browser, memory in Node)
storageAdapter: customAdapter,
// Extra headers added to every request
headers: { 'x-custom': 'value' },
// Retry & timeout
timeout: 30000, // request timeout in ms (default: 30000, 0 = disabled)
retries: 3, // max retry attempts for transient errors (default: 0)
retryDelay: 200, // initial backoff delay in ms (default: 200)
// Custom fetch — for testing, proxies, or edge runtimes
fetch: customFetchImpl,
// Logging
debug: false, // enable console logging (default: false)
logger: customLogger, // custom Logger implementation (overrides debug flag)
});| Option | Type | Default | Description |
| ------------------ | ----------------------- | -------------------------- | ---------------------------------------- |
| projectId | string | required | Project UUID |
| apiKey | string | undefined | API key, sent as-is in Authorization |
| getAccessToken | () => string \| null | undefined | External token provider (e.g. Auth0) |
| environment | string | 'master' | Environment name |
| apiUrl | string | 'https://api.archie.dev' | API Manager URL |
| authUrl | string | same as apiUrl | Auth service URL |
| realtimeUrl | string | same as apiUrl | WebSocket URL (auto-converts to ws://) |
| autoRefreshToken | boolean | true | Auto-refresh JWT 60s before expiry |
| persistSession | boolean | true | Persist session in storage |
| storageAdapter | StorageAdapter | auto-detect | Custom storage (localStorage or memory) |
| headers | Record<string,string> | {} | Extra headers on every request |
| timeout | number | 30000 | Request timeout in ms (0 = disabled) |
| retries | number | 0 | Max retry attempts for transient errors |
| retryDelay | number | 200 | Initial backoff delay in ms |
| fetch | typeof fetch | globalThis.fetch | Custom fetch for testing/edge runtimes |
| debug | boolean | false | Enable console logging |
| logger | Logger | noop | Custom logger implementation |
Authorization Priority
The SDK determines the Authorization header using this priority:
- External token (
getAccessToken()returns a token) →Authorization: Bearer {token} - User JWT (after
signIn) →Authorization: Bearer {jwt} - API key (from config) →
Authorization: {apiKey}(sent as-is) - Nothing → no
Authorizationheader
External auth (Auth0, etc.)
If your app authenticates the user elsewhere (e.g. Auth0) and you don't use auth.signIn,
supply the token via getAccessToken. The SDK calls it fresh on every HTTP request and
WebSocket connect, so you never recreate the client when the token refreshes — just keep a
token your app updates out-of-band:
let currentToken: string | null = null; // your app updates this on Auth0 refresh
const archie = createClient({
projectId: 'your-project-uuid',
apiUrl: 'https://your-project.archiecore.com',
environment: 'master',
getAccessToken: () => currentToken, // raw token; the SDK adds the `Bearer ` prefix
});Writes (e.g. mutations) require a real user identity, so use a user token here — not an
anonymous apiKey.
Auth Module
Access via archie.auth. Handles registration, login, session management, auto-refresh, and auth events.
Sign Up
const { userId, message } = await archie.auth.signUp({
email: '[email protected]',
password: 'StrongP@ss1',
firstName: 'Jane', // optional
lastName: 'Doe', // optional
roleId: 'role-uuid', // optional
});
console.log(message); // "Confirmation code sent to email"Confirm Sign Up
After the user receives a verification code by email:
const { session } = await archie.auth.confirmSignUp({
email: '[email protected]',
code: '123456',
});
// User is now signed in — session contains accessToken, refreshToken, userSign In
const { session } = await archie.auth.signIn({
email: '[email protected]',
password: 'secret',
});
console.log(session.user); // { id, email, firstName, lastName, roles }
console.log(session.accessToken); // JWT
console.log(session.expiresAt); // Unix timestamp (seconds)Sign Out
await archie.auth.signOut();
// Clears session, storage, and stops auto-refreshGet Current Session / User
const session = archie.auth.getSession(); // Session | null
const user = archie.auth.getUser(); // User | null
if (user) {
console.log(user.id, user.email, user.roles);
}Wait for Initialization
On page load, the SDK restores the session from storage asynchronously. Wait for it before checking auth state:
await archie.auth.waitForInit();
const user = archie.auth.getUser(); // now guaranteed to be loadedAuth State Changes
const unsubscribe = archie.auth.onAuthStateChange((event, session) => {
// event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED'
switch (event) {
case 'SIGNED_IN':
console.log('Logged in as', session.user.email);
break;
case 'SIGNED_OUT':
console.log('Logged out');
break;
case 'TOKEN_REFRESHED':
console.log('Token refreshed silently');
break;
}
});
// Stop listening
unsubscribe();Password Recovery
// Step 1: Request recovery email
const { message } = await archie.auth.recoverPassword({
email: '[email protected]',
});
// Step 2: Reset password with the code received by email
const { message } = await archie.auth.resetPassword({
email: '[email protected]',
code: '123456',
newPassword: 'NewStr0ngP@ss',
});Manual Token Refresh
Usually handled automatically when autoRefreshToken: true, but can be called manually:
const { session } = await archie.auth.refreshSession();Get JWKS
Fetch the JSON Web Key Set for server-side JWT verification:
const { keys } = await archie.auth.getJWKS();Auto-Refresh Behavior
When autoRefreshToken: true (default):
- After sign in, the SDK schedules a token refresh 60 seconds before expiry
- On refresh success, emits
TOKEN_REFRESHEDand schedules the next refresh - On refresh failure, calls
signOut()automatically
Session Persistence
When persistSession: true (default):
- Session is saved to storage after every sign in and token refresh
- On client creation, the SDK restores the session from storage
- If the stored token is expired, it attempts a refresh automatically
- Storage key format:
archie-auth-{projectId}-{environment}
GraphQL Module
Access via archie.graphql. Execute queries and mutations against the Archie API Manager's /graphql endpoint.
Query
Returns { data, error } — never throws for GraphQL-level errors:
interface User {
id: string;
email: string;
name: string;
}
const { data, error } = await archie.graphql.query<{ users: User[] }>(
'{ users { id email name } }',
);
if (error) {
console.error(error.message, error.code);
} else {
console.log(data.users);
}Query with Variables
const { data, error } = await archie.graphql.query<{ user: User }>(
`query GetUser($id: ID!) {
user(id: $id) { id email name }
}`,
{ id: 'user-123' },
);Mutation
const { data, error } = await archie.graphql.mutate<{ createUser: User }>(
`mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) { id email }
}`,
{ input: { email: '[email protected]', name: 'New User' } },
);Raw Request (Advanced)
For cases where you want the raw data and want errors to throw:
try {
const data = await archie.graphql.request<{ users: User[] }>({
query: '{ users { id email } }',
variables: {},
operationName: 'GetUsers',
});
console.log(data.users); // direct access, no { data, error } wrapper
} catch (err) {
// Throws GraphQLError on failure
}Request Options
Both query() and mutate() accept an optional third parameter:
const controller = new AbortController();
const { data } = await archie.graphql.query(
'{ users { id } }',
{},
{
headers: { 'x-custom': 'value' }, // extra headers for this request
signal: controller.signal, // AbortSignal for cancellation
},
);
// Cancel the request
controller.abort();GraphQL Response Shape
// Success case
{ data: T, error: null }
// Error case (GraphQL-level errors — partial data may exist)
{ data: T | null, error: GraphQLError }
// Network/HTTP error
{ data: null, error: ArchieError }Files Module
Access via archie.files. Upload, download, and manage files via GraphQL multipart uploads.
Upload a File
// From a File input
const input = document.querySelector<HTMLInputElement>('#fileInput');
const file = input.files[0];
const { url, fileId } = await archie.files.upload(file, {
filename: 'photo.jpg',
contentType: 'image/jpeg',
providerType: 's3', // optional — storage provider hint
onProgress: (pct) => console.log(`${pct}% uploaded`), // optional — progress callback
});
console.log(url); // CDN URL of the uploaded file
console.log(fileId); // Unique file ID for download/referenceUpload from a Blob or Uint8Array
// Blob
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });
const result = await archie.files.upload(blob, { filename: 'hello.txt' });
// Uint8Array (works in Node.js too)
const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
const result = await archie.files.upload(bytes, { filename: 'hello.bin' });Upload CSV
Import a CSV file into a database table:
const csvFile = document.querySelector<HTMLInputElement>('#csvInput').files[0];
const { result } = await archie.files.uploadCsv(csvFile, {
tableName: 'products',
transactionality: true, // optional — rollback all on error
limit: 1000, // optional — max rows to import
});
console.log(result.success); // boolean
console.log(result.rowsImported); // number
console.log(result.errors); // any import-level errorsDownload a File
const blob = await archie.files.download('file-id-123');
// In the browser, trigger a download:
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'my-file.pdf';
a.click();
URL.revokeObjectURL(url);Get File URL
Builds the file URL locally, no network request:
const url = archie.files.getUrl('file-id-123');
// → "https://example.platform.com/files?id=file-id-123"Realtime Module
Access via archie.realtime. WebSocket subscriptions using the graphql-transport-ws protocol with lazy connection and auto-reconnect.
Subscribe to a GraphQL Subscription
const sub = archie.realtime.subscribe<{ orderUpdated: Order }>(
`subscription {
orderUpdated { id status total }
}`,
{},
{
onData: (data) => {
console.log('Order updated:', data.orderUpdated);
},
onError: (error) => {
console.error('Subscription error:', error.message);
},
onComplete: () => {
console.log('Subscription ended');
},
},
);
// Later: stop listening
sub.unsubscribe();Subscribe with Variables
const sub = archie.realtime.subscribe(
`subscription OnUserActivity($userId: ID!) {
userActivity(userId: $userId) { action timestamp }
}`,
{ userId: 'user-123' },
{ onData: (data) => console.log(data) },
);Channel-Based API
A higher-level convenience API for table-level event subscriptions:
const channel = archie.realtime.channel('orders');
channel
.on('INSERT', (payload) => {
console.log('New order:', payload);
})
.on('UPDATE', (payload) => {
console.log('Order updated:', payload);
})
.on('DELETE', (payload) => {
console.log('Order deleted:', payload);
})
.on('*', (payload) => {
console.log('Any event:', payload);
});
// Start listening
channel.subscribe();
// Stop listening
channel.unsubscribe();Connection State
// Current state
console.log(archie.realtime.currentState);
// → 'DISCONNECTED' | 'CONNECTING' | 'CONNECTED' | 'RECONNECTING'
// Listen for changes
const unsubscribe = archie.realtime.onConnectionStateChange((state) => {
console.log('WebSocket state:', state);
if (state === 'RECONNECTING') {
showReconnectingBanner();
}
});
unsubscribe();Auto-Reconnect
The WebSocket automatically reconnects with exponential backoff when the connection drops:
- Backoff schedule: 1s → 2s → 4s → 8s → 16s → 30s (max)
- Reconnect counter resets after a successful
connection_ack - The connection closes automatically when the last subscription is unsubscribed
- On
TOKEN_REFRESHED, the connection is re-established with the new credentials
Notifications Module
Access via archie.notifications. Subscribe to live in-app notifications (Pusher-style channels) and manage read state.
Subscribe (live channel)
receiverId is the authenticated user's id — obtainable from archie.auth.getUser()?.id.
const receiverId = archie.auth.getUser()?.id ?? '';
const channel = archie.notifications.subscribe(receiverId, {
onError: (err) => console.error('Notification channel error:', err),
});
// Filter by notification key
channel.on('welcome', (n) => {
toast(n.actionText ?? 'Welcome!');
});
// Receive every notification
channel.on('*', (n) => {
badge.increment();
});
// Clean up on unmount / sign-out
channel.unsubscribe();.on() is chainable:
channel
.on('order_shipped', (n) => showShippingToast(n))
.on('payment_received', () => refreshBalance())
.on('*', () => incrementBadge());List notifications (paginated)
const { items, count, totalCount } = await archie.notifications.list(receiverId, {
unreadOnly: true, // only unread (default: false)
first: 20, // page size
skip: 0, // offset for pagination
orderBy: { createdAt: 'DESC' }, // field-to-direction map (default: { createdAt: 'DESC' })
});| Option | Type | Description |
| --------------- | ------------------------------- | ------------------------------------------------------------------------ |
| unreadOnly | boolean | Return only unread notifications |
| first | number | Page size limit |
| skip | number | Offset for pagination |
| orderBy | Record<string, 'ASC'\|'DESC'> | Field-to-direction map (e.g. { createdAt: 'DESC' }) |
| createdBefore | string | Keyset cursor: return rows older than this ISO createdAt |
| excludeIds | string[] | Tie-safe keyset: loaded ids at the createdBefore timestamp (see below) |
| includeTotal | boolean | Request count/totalCount. Default true; false skips the COUNT |
Returns { items: Notification[]; count: number; totalCount: number }.
Paginating history (infinite scroll)
list supports keyset (cursor-free) backward pagination via createdBefore. Pass the
createdAt of the oldest row you already have to fetch the next older page — robust against
new notifications arriving at the head, and index-efficient at any depth:
const first = await archie.notifications.list(receiverId, { first: 20 });
const oldest = first.items[first.items.length - 1];
const older = await archie.notifications.list(receiverId, {
first: 20,
orderBy: { createdAt: 'DESC' },
createdBefore: oldest.createdAt,
// Tie-safe: don't skip rows that share the cursor's exact `createdAt`. Pass the ids you've
// already loaded at that timestamp (e.g. fan-out notifications inserted in the same transaction
// share one `createdAt`). Omit for the simpler strict-`<` behavior.
excludeIds: first.items.filter((n) => n.createdAt === oldest.createdAt).map((n) => n.id),
// Skip the COUNT aggregate on deep pages; derive `hasMore` from the page fill instead.
includeTotal: false,
});
const hasMore = older.items.length === 20; // full page → more may remain; short page → tailThe
@archie/react-sdkuseNotificationshook does all of this for you (tie-safe cursor,excludeIdstracking, page-fillhasMore). Reach for the raw options only when paginating outside React.
Unread count
const unread = await archie.notifications.getUnreadCount(receiverId);
// → numberMark as read
// Mark a single notification — returns the updated Notification
const updated = await archie.notifications.markAsRead(notificationId);
// Mark all for this receiver — returns count of notifications marked (client-side paginated emulation)
const markedCount = await archie.notifications.markAllAsRead(receiverId);Notification shape
All fields are camelCase — the SDK normalizes backend inconsistencies before delivering them to you.
interface Notification {
id: string;
receiverId: string;
notificationKey: string; // event key, e.g. 'welcome', 'order_shipped'
notificationType?: string | null;
notificationTypeId?: string | null;
actionText?: string | null; // CTA label
actionUrl?: string | null; // CTA destination — validate before rendering (see Security below)
isRead: boolean;
readAt?: string | null; // ISO date
expiresAt?: string | null; // ISO date
metadata?: Record<string, unknown> | null;
params?: Record<string, unknown> | null; // template variables, e.g. { name: 'Ana' }
dedupKey?: string | null;
createdAt: string; // ISO date
updatedAt?: string | null;
}Security & trust model
Authorization is enforced by the Archie backend, 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. Passing a particular receiverId does not grant your client authorization to that receiver's data.
Treat actionUrl as untrusted server-controlled data. Before rendering it as a link (e.g. <a href={n.actionUrl}>), validate the scheme is http: or https:. Never allow javascript: or data: URLs — they enable stored XSS attacks in your application.
// Safe actionUrl rendering
function safeActionUrl(url: string | null | undefined): string | undefined {
if (!url) return undefined;
try {
const { protocol } = new URL(url);
if (protocol === 'http:' || protocol === 'https:') return url;
} catch {
// not a valid URL
}
return undefined;
}
// In JSX
<a href={safeActionUrl(n.actionUrl)}>View</a>metadata and params are untrusted server data. If you deep-merge them into other objects, use a safe merge that guards against prototype-polluting keys (__proto__, constructor, prototype).
REST Module
Access via archie.rest. For consuming custom REST APIs created via the Archie gateway. All standard headers (x-project-id, authorization, environment) are injected automatically.
GET
const products = await archie.rest.get<Product[]>('/api/products');
// With query parameters
const results = await archie.rest.get<Product[]>('/api/products', {
params: { category: 'electronics', limit: '10' },
});
// → GET /api/products?category=electronics&limit=10POST
const created = await archie.rest.post<Product>('/api/products', {
name: 'Widget',
price: 9.99,
});PUT
await archie.rest.put('/api/products/123', {
name: 'Updated Widget',
price: 12.99,
});PATCH
await archie.rest.patch('/api/products/123', { price: 14.99 });DELETE
await archie.rest.delete('/api/products/123');Request Options
All REST methods accept an options parameter:
const controller = new AbortController();
const data = await archie.rest.get('/api/products', {
headers: { 'x-custom': 'value' },
params: { page: '2' },
signal: controller.signal,
});REST Error Handling
REST methods throw ArchieError on non-2xx responses:
try {
await archie.rest.get('/api/products/missing');
} catch (err) {
if (err instanceof ArchieError) {
console.log(err.status); // 404
console.log(err.code); // 'HTTP_404'
console.log(err.message); // server-provided message
}
}Error Handling
The SDK provides a structured error hierarchy. All errors extend ArchieError.
Error Classes
| Class | When | Key Properties |
| -------------- | ------------------------------------------- | ---------------------------------------------- |
| ArchieError | Base class for all SDK errors | message, code, status, details, hint |
| AuthError | Authentication failures (401/403) | Same as ArchieError |
| GraphQLError | GraphQL response errors | path, locations + ArchieError props |
| NetworkError | Network issues (timeout, DNS, disconnected) | hint = "Check your internet..." |
Catching Errors
import { ArchieError, AuthError, GraphQLError, NetworkError } from '@archie/js-sdk';
try {
await archie.auth.signIn({ email: '[email protected]', password: 'wrong' });
} catch (err) {
if (err instanceof AuthError) {
console.log(err.code); // 'AUTH_INVALID_CREDENTIALS'
console.log(err.status); // 401
console.log(err.message); // 'Invalid credentials'
} else if (err instanceof NetworkError) {
console.log(err.hint); // 'Check your internet connection or API URL'
} else if (err instanceof ArchieError) {
console.log(err.code, err.status, err.details);
}
}GraphQL Error Handling
query() and mutate() return errors in the response instead of throwing:
const { data, error } = await archie.graphql.query('{ invalidField }');
if (error) {
console.log(error.message); // 'Cannot query field "invalidField"'
console.log(error.code); // 'GRAPHQL_VALIDATION_FAILED'
console.log(error.path); // ['invalidField']
console.log(error.locations); // [{ line: 1, column: 3 }]
}Auth Error Codes
| Code | Description |
| -------------------------- | ------------------------------------------- |
| AUTH_INVALID_CREDENTIALS | Wrong email/password |
| AUTH_EMAIL_EXISTS | Email already registered |
| AUTH_EMAIL_NOT_VERIFIED | Email confirmation required |
| AUTH_ACCOUNT_LOCKED | Account temporarily locked |
| AUTH_INVALID_CODE | Invalid verification/recovery code |
| AUTH_TOKEN_EXPIRED | Access token has expired |
| AUTH_TOKEN_INVALID | Malformed or revoked token |
| AUTH_NOT_CONFIGURED | Auth not enabled for the project |
| AUTH_WEAK_PASSWORD | Password doesn't meet strength requirements |
Automatic 401 Retry
When a request returns 401:
- The SDK attempts to refresh the token automatically
- If refresh succeeds, the original request is retried with the new token
- If refresh fails, the user is signed out and the error is thrown
This is transparent — your code doesn't need to handle it.
Retry & Timeout
The SDK supports automatic retries with exponential backoff and per-request timeouts.
Configuration
const archie = createClient({
projectId: 'your-project-uuid',
retries: 3, // retry up to 3 times on transient errors
retryDelay: 200, // initial delay: 200ms → 400ms → 800ms (with jitter)
timeout: 15_000, // abort requests after 15 seconds
});Retryable Conditions
The SDK retries automatically on:
| Condition | Status Codes / Errors |
| ---------------- | ------------------------------------- |
| Server errors | 500, 502, 503, 504 |
| Rate limiting | 429 (respects Retry-After header) |
| Network failures | TypeError (DNS, connectivity) |
| Timeouts | TIMEOUT errors |
Non-retryable errors (400, 401, 403, 404, 409, etc.) are thrown immediately.
Backoff Strategy
Exponential with jitter to prevent thundering herd:
delay = min(baseDelay × 2^(attempt-1) + random_jitter, 30s)Timeout Behavior
- When
timeout > 0, each individual request (including retries) is aborted aftertimeoutmilliseconds - Throws
ArchieErrorwithcode: 'TIMEOUT'andstatus: 408 - Set
timeout: 0to disable (no timeout) - User-provided
AbortSignaltakes precedence over timeout
Custom Fetch
Inject a custom fetch implementation for testing, proxies, or edge runtimes:
import { createClient } from '@archie/js-sdk';
// Testing with a mock
const mockFetch = vi.fn().mockResolvedValue(new Response('{}'));
const archie = createClient({
projectId: 'test',
fetch: mockFetch,
});
// Edge runtime (Cloudflare Workers, Deno)
const archie = createClient({
projectId: '...',
fetch: globalThis.fetch, // or a custom implementation
});
// Proxy / logging middleware
const archie = createClient({
projectId: '...',
fetch: async (url, init) => {
console.log('→', init?.method, url);
const response = await globalThis.fetch(url, init);
console.log('←', response.status);
return response;
},
});Health Check
Verify connectivity to the API before performing operations:
const isUp = await archie.ping();
if (isUp) {
console.log('API is reachable');
} else {
console.warn('API is unreachable');
}Returns true if the API responds with a 2xx status, false otherwise. Never throws.
Storage Adapters
The SDK uses a StorageAdapter interface for session persistence. You can provide a custom implementation.
Interface
interface StorageAdapter {
getItem(key: string): string | null | Promise<string | null>;
setItem(key: string, value: string): void | Promise<void>;
removeItem(key: string): void | Promise<void>;
}Built-in Adapters
import { BrowserLocalStorage, MemoryStorage } from '@archie/js-sdk';
// Browser — uses localStorage (default in browser)
const archie = createClient({
projectId: '...',
storageAdapter: new BrowserLocalStorage(),
});
// In-memory — for SSR, tests, or environments without localStorage
const archie = createClient({
projectId: '...',
storageAdapter: new MemoryStorage(),
});Custom Adapter Example (AsyncStorage for React Native)
import AsyncStorage from '@react-native-async-storage/async-storage';
const archie = createClient({
projectId: '...',
storageAdapter: {
getItem: (key) => AsyncStorage.getItem(key),
setItem: (key, value) => AsyncStorage.setItem(key, value),
removeItem: (key) => AsyncStorage.removeItem(key),
},
});TypeScript Types
All types are exported for strong typing in your application.
Core Types
import type { ArchieClientOptions, Session, User } from '@archie/js-sdk';Auth Types
import type {
AuthSignUpParams,
AuthSignInParams,
AuthConfirmParams,
AuthRecoverParams,
AuthResetPasswordParams,
AuthEvent, // 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED'
AuthEventCallback,
} from '@archie/js-sdk';GraphQL Types
import type {
GraphQLResponse, // { data: T | null; error: ArchieError | null }
GraphQLRequestOptions, // { headers?, signal? }
GraphQLRawRequest, // { query, variables?, operationName? }
} from '@archie/js-sdk';File Types
import type {
FileUploadOptions, // { filename?, contentType?, providerType?, onProgress? }
FileUploadResult, // { url: string; fileId: string }
CsvUploadOptions, // { tableName, transactionality?, limit? }
} from '@archie/js-sdk';Realtime Types
import type {
Subscription, // { unsubscribe: () => void }
SubscriptionCallbacks, // { onData, onError?, onComplete? }
RealtimeEvent, // 'INSERT' | 'UPDATE' | 'DELETE' | '*'
RealtimeChannel, // { on, subscribe, unsubscribe }
ConnectionState, // 'CONNECTING' | 'CONNECTED' | 'DISCONNECTED' | 'RECONNECTING'
ConnectionStateCallback,
} from '@archie/js-sdk';REST Types
import type {
RestRequestOptions, // { headers?, params?, signal? }
} from '@archie/js-sdk';Module Interfaces (for DI / Testing)
import type {
IAuthModule,
IGraphQLModule,
IFileModule,
IRealtimeModule,
IRestModule,
IHttpClient,
Logger,
TokenAccessor,
StorageAdapter,
} from '@archie/js-sdk';Module Classes (for advanced typing)
The concrete module implementations are also exported for instanceof checks or advanced use:
import { AuthModule, GraphQLModule, FileModule, RealtimeModule, RestModule } from '@archie/js-sdk';Built-in Loggers
Two logger constants are available for the logger option:
import { consoleLogger, noopLogger } from '@archie/js-sdk';
// Console logger — logs to console.debug/info/warn/error
const archie = createClient({ projectId: '...', logger: consoleLogger });
// Noop logger — silences all logging (default)
const archie = createClient({ projectId: '...', logger: noopLogger });