Architecture

How the SDK is structured — HttpClient, API clients, token lifecycle, and event streams

0
dependencies
5
client types
fetch
transport
JWT
auth tokens

Layered Design

The SDK is a thin composition of focused clients. MeroJs is the entry point — it owns the HTTP transport and lazily initialises the specialised clients behind property accessors.

Layer 1 — Transport

HttpClient
Web-standards fetch wrapper. Injects Authorization header on every request. Handles 401 by calling the refreshToken hook transparently.
createBrowserHttpClient
Factory used in browser and Tauri apps. Sets credentials: 'omit' automatically when running inside Tauri.

Layer 2 — API Clients

AuthApiClient
Direct HTTP to /api/v1/identity — login, token generation, key management.
AdminApiClient
Direct HTTP to /api/v1/admin — 65+ methods covering contexts, apps, namespaces, groups.
RpcClient
JSON-RPC over HTTP to /api/v1/rpc — executes WASM contract methods.

Layer 3 — Event Streams

SseClient
Server-Sent Events from /api/v1/subscribe. Reconnects automatically. Use this in production.
WsClient
WebSocket alternative. Experimental — logs a warning on first use.

Layer 4 — Token Store

MemoryTokenStore
Ephemeral — tokens lost on page reload. Safe for server-side use.
LocalStorageTokenStore
Persists to localStorage. Constructor takes an optional storage key.

Token Lifecycle

The SDK manages JWT tokens reactively — it never proactively refreshes, only reacts to 401 responses.

1

Authenticate

Call sdk.authenticate() to exchange username + password for an access token and refresh token. Tokens are stored in memory (and in the tokenStore if provided).

2

Request

Every request reads the current access token and injects it as Authorization: Bearer <token>. The JWT exp claim is parsed to track expiry.

3

401 → Refresh

When the server returns 401, the HttpClient calls performTokenRefresh() transparently, retries the original request with the new token, and updates the store. Multiple concurrent 401s are deduplicated via a shared refreshPromise.

// The refresh flow (transparent to callers)
// 1. Request with access_token → 401
// 2. POST /api/v1/identity/refresh-token
// 3. Store new access_token + refresh_token
// 4. Retry original request with new token

SSO Integration

When your app is opened from Calimero Desktop, the desktop process appends auth tokens to the URL hash. The SDK reads them with parseAuthCallback() and bypasses the normal login flow:

// Desktop opens app at:
// https://my-app.example.com/#access_token=...&refresh_token=...&node_url=...&application_id=...&context_id=...&context_identity=...

const auth = parseAuthCallback(window.location.hash);
if (auth) {
  sdk.setTokenData({ access_token: auth.accessToken, refresh_token: auth.refreshToken, expires_at: 0 });
  // expires_at = 0 triggers JWT exp parsing automatically
}

Lazy Initialisation

RpcClient, SseClient, and WsClient are created on first access — no cost if unused:

// Only instantiated when accessed:
sdk.rpc // RpcClient (lazy)
sdk.events // SseClient (lazy)
sdk.ws // WsClient (lazy, experimental)

// Always available:
sdk.auth // AuthApiClient
sdk.admin // AdminApiClient

Zero Dependencies

The SDK is built on Web Platform APIs only:

fetch
HTTP requests — available in browser, Node 18+, Deno, Bun, edge workers
EventSource
SSE client — native browser API, polyfillable for server environments
WebSocket
WS client — available everywhere
AbortController
Request cancellation and timeout signals
atob
Base64 decoding for JWT payload parsing
localStorage
Optional token persistence (browser only)