CRISP partnersSDK methods

createAccountSync()

Create a typed account-data store with realtime refreshes.

Recommended browser helper. Construction does no I/O; start in a lifecycle/effect. Loaders call your authenticated backend. Stop on logout and create a new store on account switch. Never perform balance arithmetic from repeated events.

events workflow · All SDK methods

Import and runtime

@crisp-trade/partner-sdk/realtime — browser-safe; calls your authenticated backend, never the Partner API with secret credentials.

Client setup and shared behavior

Arguments

ArgumentPresenceReleased TypeScript type
optionsRequired
AccountSyncOptions<L>

Named types are expanded under “Exact released types” below. Parameters are in call order; optional does not imply nullable.

Example

Example IDs and intent keys are illustrative. Replace them with authenticated account resources and your persisted intent. Browser route names are example routes you implement on your own backend.

import { createAccountSync } from '@crisp-trade/partner-sdk/realtime';
const store = createAccountSync({
  getSession: async (signal) => {
    const response = await fetch('/api/realtime/session', { signal });
    if (!response.ok) throw new Error('Session unavailable');
    return response.json();
  },
  loaders: {
    funding: async (signal) => {
      const response = await fetch('/api/account/funding', { signal });
      if (!response.ok) throw new Error('Funding unavailable');
      return response.json();
    },
  },
});
const unsubscribe = store.subscribe(() => console.log(store.getSnapshot()));
const stop = store.start();
// On unmount/logout:
stop();
unsubscribe();

Returns

The exact return type is shown below; this helper does not use the ordinary HTTP response wrapper.

Return type
{
    start: () => () => void;
    stop: () => void | undefined;
    refresh: (resources?: readonly AccountResource[]) => Promise<void>;
    getSnapshot: () => AccountSyncSnapshot<L>;
    getServerSnapshot: () => AccountSyncSnapshot<L>;
    subscribe: (listener: () => void) => () => void;
}

Errors and lifecycle

Errors and retry policy. Financial uncertainty requires recovery with the original intent, never a new key. Realtime helpers must be stopped on logout/account switch.

Exact released types

Extracted from the shipped SDK 0.13.0, not separately maintained signatures.

Full signature
createAccountSync<L extends AccountLoaders>(options: AccountSyncOptions<L>): {
    start: () => () => void;
    stop: () => void | undefined;
    refresh: (resources?: readonly AccountResource[]) => Promise<void>;
    getSnapshot: () => AccountSyncSnapshot<L>;
    getServerSnapshot: () => AccountSyncSnapshot<L>;
    subscribe: (listener: () => void) => () => void;
}
AccountLoaders
export type AccountLoaders = Partial<Record<AccountResource, (signal: AbortSignal) => Promise<unknown>>>;
AccountResource
export type AccountResource = typeof accountResources[number];
AccountSyncOptions
export interface AccountSyncOptions<L extends AccountLoaders> {
    /** Authenticated partner backend returns only the short-lived account session. */
    getSession: (signal: AbortSignal) => Promise<RealtimeSession>;
    /** Read-only loaders. Return data; let this store publish it after lifecycle checks. */
    loaders: L;
    /** Defaults to sessionStorage, with per-instance memory fallback. null = memory only. */
    storage?: Pick<Storage, "getItem" | "setItem"> | null;
    signal?: AbortSignal;
    callbackTimeoutMs?: number;
    createSocket?: WatchOptions["createSocket"];
}
RealtimeSession
export type RealtimeSession = {
    endpoint: string;
    protocol: string;
    token: string;
    expiresAt: string;
    cursorKey: string;
};
WatchOptions
export interface WatchOptions {
    /** Call your authenticated BFF, never CRISP with partner credentials. */
    getSession: (signal: AbortSignal) => Promise<RealtimeSession>;
    loadCursor: (key: string, signal: AbortSignal) => Promise<string | null>;
    saveCursor: (key: string, cursor: string, signal: AbortSignal) => Promise<void>;
    onInvalidate: (event: Invalidation, signal: AbortSignal) => Promise<void>;
    onResync: (signal: AbortSignal) => Promise<void>;
    /** Optional batched delivery. Replaces onInvalidate when supplied. */
    onInvalidateBatch?: (events: readonly Invalidation[], signal: AbortSignal) => Promise<void>;
    /** Runs after each handshake, before replay callbacks. */
    onReady?: (signal: AbortSignal) => Promise<void>;
    onConnectionChange?: (state: "connecting" | "connected" | "reconnecting" | "stopped") => void;
    /** Pass signals to fetch and check before committing UI/cursor side effects. */
    signal?: AbortSignal;
    callbackTimeoutMs?: number;
    handshakeTimeoutMs?: number;
    onError?: (error: Error) => void;
    createSocket?: (endpoint: string, protocols: string[]) => Socket;
}
Invalidation
export type Invalidation = {
    id: string;
    cursor: string;
    type: string;
    occurredAt: string;
};
Socket
type Socket = Pick<WebSocket, "addEventListener" | "send" | "close">;
AccountSyncSnapshot
export interface AccountSyncSnapshot<L extends AccountLoaders> {
    readonly connection: ConnectionState;
    readonly refreshing: boolean;
    readonly stale: boolean;
    readonly data: AccountData<L>;
    readonly lastUpdatedAt: string | null;
    readonly error: string | null;
}
ConnectionState
export type ConnectionState = "idle" | "connecting" | "connected" | "reconnecting" | "stopped";
AccountData
export type AccountData<L extends AccountLoaders> = {
    readonly [K in keyof L]?: L[K] extends (...args: never[]) => Promise<infer T> ? T : never;
};
CRISP Partner Documentation