Skip to main content
Version: 0.1.0

Connection & Authentication

Connect, authenticate, and manage client lifecycle.

RaisinClient

Constructor

new RaisinClient(url: string, options?: ClientOptions)
ParameterTypeDescription
urlstringWebSocket URL (e.g. ws://localhost:8080/ws/myrepo)
optionsClientOptionsOptional configuration
interface ClientOptions {
repository?: string;
tenantId?: string;
defaultBranch?: string;
requestTimeout?: number;
connection?: ConnectionOptions;
tokenStorage?: TokenStorage;
logLevel?: LogLevel;
mode?: 'websocket' | 'http' | 'hybrid';
httpBaseUrl?: string;
}
OptionDefaultDescription
repositoryextracted from URLRepository name. With a bare host URL the client builds the tenant-less /ws/{repository} route internally. With a path URL it overrides the repository extracted from the URL (used for repo-scoped auth endpoints).
tenantIdextracted from URL, else 'default'Optional — you normally never set this. The server resolves the tenant for /ws/{repo} connections; multi-tenant operators address a specific tenant with the /sys/{tenant}/{repo} URL form instead.
defaultBranch'main'Branch used for all operations unless overridden.
requestTimeout30000Per-request timeout in milliseconds. Requests that exceed it reject with RaisinTimeoutError.
connectionLow-level ConnectionOptions: autoReconnect (default true), reconnectOptions, heartbeatInterval (default 30000, 0 disables), heartbeatTimeout (default 5000), protocols, headers (upgrade headers, Node.js only).
tokenStorageMemoryTokenStorageWhere tokens are persisted (see Token Storage).
logLevelLogLevel.InfoLogLevel enum: Silent, Error, Warn, Info, Debug.
mode'websocket'Client mode.
httpBaseUrlderived from WS URLHTTP base URL for identity auth and uploads.

The repository option lets you connect with a bare host URL — new RaisinClient('ws://localhost:8080', { repository: 'myrepo' }) builds the tenant-less /ws/myrepo route internally. Multi-tenant operators can address a specific tenant with the /sys/{tenant}/{repository} URL form instead.

connect()

Establish the WebSocket connection.

await client.connect(): Promise<void>

disconnect()

Close the WebSocket connection.

client.disconnect(): void

database()

Get a database interface for the given repository.

client.database(name: string): Database

The returned Database comes pre-configured with access to the Conversations, Flow, Functions, and inbox-task APIs:

const db = client.database('myapp');

// Conversations — conversational AI
const convo = await db.conversations.create({ participant: '/agents/support' });

// Flow — workflow execution
const result = await db.flow.runAndWait('/flows/process-order', { orderId: '123' });

// Inbox — human-in-the-loop tasks
const { tasks } = await db.inbox.listTasks({ status: 'pending' });
AccessorReturnsReference
db.conversationsConversationManager — list/create/open conversations, streaming, plan actionsChat & Conversations
db.flowFlowClient — run flows over HTTP with SSE streamingFlows
db.flows()FlowsApi — flow execution over the WebSocket connectionFlows
db.functions()FunctionsApi — invoke server-side functionsFunctions
db.inboxInboxApi — list/complete human-in-the-loop tasksFlows

All accessors are lazily created and cached, pre-configured with the correct base URL, repository, and auth manager.


Authentication

authenticate()

Authenticate with admin credentials or a JWT token.

await client.authenticate(credentials: Credentials): Promise<void>

Admin credentials:

await client.authenticate({
username: 'admin',
password: 'your-password'
});

JWT token:

await client.authenticate({
type: 'jwt',
token: 'eyJhbGciOiJIUzI...'
});

loginWithEmail()

Log in an existing user with email and password.

await client.loginWithEmail(
email: string,
password: string,
repository: string
): Promise<IdentityUser>

Returns an IdentityUser with id, email, displayName, and home path.

registerWithEmail()

Register a new user account.

await client.registerWithEmail(
email: string,
password: string,
repository: string,
displayName?: string
): Promise<IdentityUser>

initSession()

Restore a session from a previously stored token.

await client.initSession(
repository: string
): Promise<IdentityUser | null>

Returns the user if a valid stored token exists, or null otherwise.

refreshToken()

Manually refresh the access token.

await client.refreshToken(): Promise<IdentityUser | null>

logout()

Sign out and optionally disconnect.

await client.logout(options?: {
disconnect?: boolean;
reconnect?: boolean;
}): Promise<void>

Session & User Info

isAuthenticated()

client.isAuthenticated(): boolean

isReady()

Returns true when the client is both connected and authenticated.

client.isReady(): boolean

getCurrentUser()

client.getCurrentUser(): CurrentUser | null
interface CurrentUser {
userId: string;
roles?: string[];
anonymous: boolean;
node?: UserNode;
}

getCurrentUserId()

client.getCurrentUserId(): string | null

getCurrentUserPath()

client.getCurrentUserPath(): string | null

getSession()

client.getSession(): {
user: IdentityUser | null;
accessToken: string | null;
} | null

getUser()

Alias for getSession()?.user. Compatible with Supabase patterns.

client.getUser(): IdentityUser | null

State Listeners

onAuthStateChange()

Listen for authentication lifecycle events.

const unsubscribe = client.onAuthStateChange(
callback: (change: AuthStateChange) => void
): () => void
interface AuthStateChange {
event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'
| 'SESSION_EXPIRED' | 'USER_UPDATED';
session: {
user: IdentityUser | null;
accessToken: string | null;
};
}

onConnectionStateChange()

const unsubscribe = client.onConnectionStateChange(
callback: (state: ConnectionState) => void
): () => void

ConnectionState is one of: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'closed'.

onReadyStateChange()

Fires when the combined connected + authenticated state changes.

const unsubscribe = client.onReadyStateChange(
callback: (ready: boolean) => void
): () => void

onReconnected()

Fires after the client automatically reconnects.

const unsubscribe = client.onReconnected(
callback: () => void
): () => void

onUserChange()

Fires when the user's home node is updated.

const unsubscribe = client.onUserChange(
callback: (event: UserChangeEvent) => void
): () => void

Connection Info

isConnected()

client.isConnected(): boolean

getConnectionState()

client.getConnectionState(): ConnectionState

getBranch() / setBranch()

client.getBranch(): string
client.setBranch(branch: string): void

getTenantId()

client.getTenantId(): string

Reconnection & Request Queueing

The client reconnects automatically (exponential backoff) and re-authenticates with the stored token. Requests issued while the connection is re-establishing are queued and flushed after reconnect + re-auth, so brief network blips don't surface as errors. The queue is capped at 100 requests — overflow rejects immediately (Request queue is full).

After a reconnect, active subscriptions are restored with retries; if restoration fails permanently the client emits subscription_restore_failed (see Realtime Subscriptions & Inbox). onReconnected() fires only after connection, auth, and subscription restore have all succeeded.

Failures surface as typed errors:

ErrorThrown when
RaisinTimeoutErrorA request exceeds requestTimeout (carries timeoutMs)
RaisinAuthErrorAuthentication or token refresh fails (carries code, status)
RaisinConnectionErrorThe connection drops unrecoverably

HTTP Client (SSR)

For server-side rendering where WebSocket is not available:

const client = RaisinClient.forSSR('http://localhost:8080', {
tenantId: 'default'
});

// Also available as:
const client = RaisinClient.createHttpClient('http://localhost:8080', options);

The HTTP client supports the same authentication and database methods but communicates over REST instead of WebSocket. Real-time events and flows over WebSocket are not available.


Token Storage

interface TokenStorage {
getAccessToken(): string | null;
setAccessToken(token: string): void;
getRefreshToken(): string | null;
setRefreshToken(token: string): void;
clear(): void;
}

Built-in implementations:

ClassStorageUse case
MemoryTokenStorageIn-memoryDefault, server-side
LocalStorageTokenStoragelocalStorageBrowser persistence

Types

interface IdentityUser {
id: string;
email: string;
displayName?: string;
avatarUrl?: string;
emailVerified?: boolean;
home?: string;
}