@ironflow/browser
Browser client for Ironflow. Provides real-time subscriptions, workflow triggers, and event emission for web applications.
Installation
Section titled “Installation”The package is public on npm and installs without authentication. For building from source, see the Local Development guide.
npm install @ironflow/browserQuick Start
Section titled “Quick Start”import { ironflow } from '@ironflow/browser';
// Configure once at app startupironflow.configure({ serverUrl: 'http://localhost:9123',});
// Subscribe to eventsconst sub = await ironflow.subscribe('events:order.*', { onEvent: (event) => console.log('Order:', event),});
// Invoke a functionconst run = await ironflow.invoke('process-order', { data: { orderId: '123' },});
// Emit eventsawait ironflow.emit('order.approved', { orderId: '123' }, { version: 1 });
// Cleanupsub.unsubscribe();Client
Section titled “Client”configure
Section titled “configure”Configure the singleton client. Call once at app startup.
ironflow.configure({ // Server URL (required) serverUrl: 'https://ironflow.example.com',
// Transport: 'connectrpc' (default) or 'websocket' transport: 'connectrpc',
// Authentication (optional for local development) // Use the environment API key from the Ironflow dashboard auth: { apiKey: 'your-environment-api-key', // or token: 'your-jwt-token', },
// Reconnection settings reconnect: { enabled: true, // Enable auto-reconnect (default: true) maxAttempts: 10, // Max reconnection attempts (default: 10) backoff: { initial: 1000, // Initial delay in ms (default: 1000) max: 30000, // Max delay in ms (default: 30000) multiplier: 2, // Backoff multiplier (default: 2) }, },
// Tab visibility handling visibility: { pauseOnHidden: true, // Pause subscriptions when tab hidden (default: true) reconnectOnVisible: true, // Reconnect when tab visible (default: true) },
// Custom logger (optional) logger: console, // or false to disable logging
// Request timeout in ms (optional) timeout: 30000,});Connection Management
Section titled “Connection Management”connect
Section titled “connect”Manually connect to the server.
await ironflow.connect();disconnect
Section titled “disconnect”Disconnect from the server.
ironflow.disconnect();onConnectionChange
Section titled “onConnectionChange”Listen for connection state changes.
const unsubscribe = ironflow.onConnectionChange((state) => { // state: 'connecting' | 'connected' | 'disconnected' | 'reconnecting' console.log('Connection state:', state);});
// Stop listeningunsubscribe();Event Emission
Section titled “Event Emission”Emit an event.
// Basic emitawait ironflow.emit('order.approved', { orderId: '123', approvedBy: 'user@example.com',});
// With optionsawait ironflow.emit('order.approved', { orderId: '123' }, { version: 2, // Event schema version (default: 1) idempotencyKey: 'unique-key', // Deduplication key});emitSync
Section titled “emitSync”Emit an event and wait for the triggered run to complete. Calls TriggerSync, which blocks until the run finishes or the timeout elapses.
Throws RunFailedError if the run fails, RunCancelledError if it is cancelled.
const result = await ironflow.emitSync('order.placed', { orderId: '123' });console.log(result.output); // Run outputconsole.log(result.runId); // Run IDconsole.log(result.functionId); // Function that was triggeredconsole.log(result.status); // 'completed'console.log(result.durationMs); // Wall-clock duration
// With custom timeout (default: 30 000 ms)const resultWithTimeout = await ironflow.emitSync('order.placed', { orderId: '123' }, { timeout: 60000,});Run Management
Section titled “Run Management”invoke
Section titled “invoke”Invoke a function by function ID.
// Basic invokeconst run = await ironflow.invoke('process-order', { data: { orderId: '123' },});
console.log(run.runIds); // IDs of created runsconsole.log(run.eventId); // ID of the stored event
// Type-safe invoke (TInput — the input payload)interface Input { orderId: string }
const run = await ironflow.invoke<Input>('process-order', { data: { orderId: '123' },});getRun
Section titled “getRun”Get run status.
const run = await ironflow.getRun('run_abc123');
console.log(run.status); // Run statusconsole.log(run.attempt); // Current attempt numberconsole.log(run.output); // Output (if completed)console.log(run.error); // Error (if failed)console.log(run.startedAt); // Start time (if started)console.log(run.endedAt); // End time (if finished)listRuns
Section titled “listRuns”List runs with filters.
const runs = await ironflow.listRuns({ functionId: 'process-order', // Filter by function status: 'running', // Filter by status limit: 50, // Max results cursor: 'abc123', // Pagination cursor});
console.log(runs.runs); // Array of runsconsole.log(runs.nextCursor); // Next page cursorcancelRun
Section titled “cancelRun”Cancel a running workflow.
await ironflow.cancelRun('run_abc123');Scoped Injection
Section titled “Scoped Injection”Pause running workflows, inspect step outputs, inject modifications, and resume:
// Pause at next step boundaryawait ironflow.pauseRun("run_abc123");
// Get paused state with completed stepsconst state = await ironflow.getPausedState("run_abc123");for (const step of state.steps) { console.log(step.name, step.output, step.injected);}
// Inject modified outputconst result = await ironflow.injectStepOutput( "run_abc123", "step_xyz", { corrected: true }, "Fix calculation");
// Resume with injected dataawait ironflow.resumeRun("run_abc123");Time-Travel Debugging
Section titled “Time-Travel Debugging”Inspect historical run state at any timestamp. Requires recording: true on the function.
// Get run state at a specific point in timeconst snapshot = await ironflow.getRunStateAt("run_abc123", "2024-01-15T10:30:00Z");console.log("Status at that time:", snapshot.status);for (const step of snapshot.steps) { console.log(step.name, step.status, step.patched);}
// Get full timeline of audit events for a runconst events = await ironflow.getRunTimeline("run_abc123");for (const evt of events) { console.log(evt.timestamp, evt.eventType, evt.summary, evt.significant);}
// Get a specific step's output at a point in timeconst stepOutput = await ironflow.getStepOutputAt( "run_abc123", "step_xyz", "2024-01-15T10:30:00Z");console.log(stepOutput.output, stepOutput.patched, stepOutput.injected);Projections
Section titled “Projections”getProjection
Section titled “getProjection”Get the current state of a projection.
const result = await ironflow.getProjection<OrderStats>('order-stats');console.log(result.state); // Typed projection stateconsole.log(result.name); // Projection nameconsole.log(result.partition); // Partition key (or '__global__')console.log(result.version); // Event sequence versionconsole.log(result.lastEventId); // ID of the last processed eventconsole.log(result.lastEventTime); // Timestamp of the last processed event (Date)console.log(result.mode); // 'managed' | 'external'
// With partitionconst resultWithPartition = await ironflow.getProjection('order-stats', { partition: 'customer-123',});listProjections
Section titled “listProjections”List all registered projections with their operational status.
const projections = await ironflow.listProjections();for (const p of projections) { console.log(p.name, p.status, p.mode, p.lag);}getProjectionStatus
Section titled “getProjectionStatus”Get the operational status of a single projection.
const status = await ironflow.getProjectionStatus('order-stats');console.log(status.status); // 'active' | 'rebuilding' | 'paused' | 'error'console.log(status.mode); // 'managed' | 'external'console.log(status.lastEventSeq); // Last processed event sequence numberconsole.log(status.lag); // Number of unprocessed eventsconsole.log(status.errorMessage); // Error message (if status === 'error')console.log(status.updatedAt); // Timestamp of last status update (Date)rebuildProjection
Section titled “rebuildProjection”Trigger a full rebuild of a projection from the beginning of the event stream.
const result = await ironflow.rebuildProjection('order-stats');console.log(result.status); // e.g. 'rebuilding'
// With optionsawait ironflow.rebuildProjection('order-stats', { partition: 'customer-123', // Rebuild a specific partition only fromEventId: 'evt-abc', // Start replay from this event ID dryRun: true, // Validate without making changes});subscribeToProjection
Section titled “subscribeToProjection”Subscribe to real-time state updates for a projection.
const sub = await ironflow.subscribeToProjection<OrderStats>('order-stats', { onUpdate: (state, event) => { console.log('New state:', state); console.log('Triggered by event:', event.id, event.name); }, onError: (error) => console.error(error),});
// With partition and replayconst subWithPartition = await ironflow.subscribeToProjection('order-stats', { onUpdate: (state) => console.log(state),}, { partition: 'customer-123', replay: 1, // Replay the latest update on connect});
// Cleanupsub.unsubscribe();querySQLProjection
Section titled “querySQLProjection”Query a SQL-backed projection table with optional filtering, ordering, and pagination.
const result = await ironflow.querySQLProjection('board', { where: "status = 'OPEN'", orderBy: 'title ASC', limit: 50, offset: 0,});
console.log(result.columns); // Column namesconsole.log(result.rows); // Array of string[] rowsconsole.log(result.totalCount); // Total matching rows (before limit)Subscriptions
Section titled “Subscriptions”subscribe
Section titled “subscribe”Subscribe to events matching a pattern.
// Basic subscriptionconst sub = await ironflow.subscribe('events:order.*', { onEvent: (event) => console.log(event), onError: (error) => console.error(error), onStateChange: (state) => console.log(state),});
// Type-safe subscriptioninterface OrderEvent { orderId: string; amount: number;}
const sub = await ironflow.subscribe<OrderEvent>('events:order.*', { onEvent: (event) => { // event.data is typed as OrderEvent console.log(event.data.orderId); },});
// With optionsconst sub = await ironflow.subscribe('events:*', { onEvent: (e) => console.log(e), replay: 10, // Replay last N events on connect trackState: true, // Enable .lastEvent access filter: 'event.data.amount > 100', // CEL filter expression backpressure: 'buffer', // 'buffer' (default) | 'drop' | 'block'});
// Access last event (when trackState is true)console.log(sub.lastEvent);
// Unsubscribesub.unsubscribe();Pattern Syntax
Section titled “Pattern Syntax”| Pattern | Description |
|---|---|
events:order.* | All order events |
events:order.created | Specific event |
events:* | All events |
system.run.* | All run updates |
system.run.{runId}.* | Specific run updates |
system.run.{runId}.step.{stepId} | Specific step updates |
Multiple Patterns
Section titled “Multiple Patterns”const sub = await ironflow.subscribe( ['system.run.*', 'events:order.*', 'events:payment.*'], { onEvent: (event) => console.log(event), });Manual Acknowledgment
Section titled “Manual Acknowledgment”import type { AckableSubscription } from '@ironflow/core';
const sub = await ironflow.subscribe('events:*', { onEvent: async (event) => { if (!event.eventId) return;
try { await processEvent(event); await sub.ack(event.eventId); // Acknowledge } catch { await sub.nak(event.eventId); // Negative ack - redeliver } }, ackMode: 'manual',}) as AckableSubscription;Subscription Groups
Section titled “Subscription Groups”Manage multiple subscriptions together.
const group = ironflow.subscriptionGroup();
group.add('system.run.abc123.*', { onEvent: (e) => console.log('Run:', e),});
group.add('events:payment.*', { onEvent: (e) => console.log('Payment:', e),});
// Unsubscribe all at oncegroup.unsubscribeAll();KV Store
Section titled “KV Store”ironflow.kv()
Section titled “ironflow.kv()”Get a KV client for bucket management and key operations:
const kv = ironflow.kv();createBucket
Section titled “createBucket”const info = await kv.createBucket({ name: "sessions", description: "User session data", ttlSeconds: 3600, maxValueSize: 65536, history: 3,});deleteBucket
Section titled “deleteBucket”await kv.deleteBucket("sessions");listBuckets
Section titled “listBuckets”const buckets = await kv.listBuckets();for (const b of buckets) { console.log(`${b.name}: ${b.values} keys, ${b.bytes} bytes`);}getBucketInfo
Section titled “getBucketInfo”const info = await kv.getBucketInfo("sessions");// info.name, info.values, info.bytes, info.history, info.created_atBucket Handle
Section titled “Bucket Handle”Get a bucket handle for key operations:
const bucket = kv.bucket("sessions");const entry = await bucket.get("user:123");// entry.key, entry.value, entry.revision, entry.created_at, entry.operationUnconditional write. Returns the new revision:
const { revision } = await bucket.put("user:123", { name: "Alice" });create (If-Not-Exists)
Section titled “create (If-Not-Exists)”Write only if the key does not exist. Throws on conflict (HTTP 412):
const { revision } = await bucket.create("user:123", { name: "Alice" });update (Compare-and-Swap)
Section titled “update (Compare-and-Swap)”Write only if the revision matches. Throws on mismatch (HTTP 412):
const { revision } = await bucket.update("user:123", newValue, entry.revision);delete
Section titled “delete”Soft-delete (tombstone):
await bucket.delete("user:123");Permanently remove key and all history:
await bucket.purge("user:123");listKeys
Section titled “listKeys”List keys with optional wildcard filter:
const keys = await bucket.listKeys("user.*");// Pass no argument for all keysWatch for real-time key changes via WebSocket (browser SDK only):
const watcher = bucket.watch({ onUpdate: (event) => { console.log(`${event.key} ${event.operation}: rev ${event.revision}`); }, onError: (err) => console.error(err), onClose: () => console.log("Watch ended"),}, { key: "user.*" });
// Stop watchingwatcher.stop();See the KV Store Guide for detailed usage patterns.
Config Management
Section titled “Config Management”ironflow.configManager()
Section titled “ironflow.configManager()”Get a config client for environment-scoped configuration:
const config = ironflow.configManager();Full replacement of a config document:
const { revision } = await config.set("app-settings", { theme: "dark", maxRetries: 3,});const entry = await config.get("app-settings");// entry.name, entry.data, entry.revision, entry.updatedAtShallow merge — only specified keys are updated:
const { revision } = await config.patch("app-settings", { maxRetries: 5, timeout: 30,});const configs = await config.list();for (const entry of configs) { console.log(`${entry.name}: rev ${entry.revision}`);}delete
Section titled “delete”Delete a config. Idempotent — succeeds silently if the config does not exist.
await config.delete("app-settings");Watch for real-time config changes via WebSocket:
const watcher = await config.watch("feature-flags", { onUpdate: (event) => { // event: ConfigWatchEvent ({ type: "config_update", name, data, revision, updatedAt }) console.log("Config updated:", event.data); console.log("New revision:", event.revision); }, onError: (err) => console.error("Watch error:", err),});
// `watcher` is a Subscription — call unsubscribe() to stop watching.watcher.unsubscribe();See the Config Management Guide for detailed usage patterns.
Entity Streams
Section titled “Entity Streams”streams.append
Section titled “streams.append”Appends an event to an entity stream.
const result = await ironflow.streams.append("order-123", { name: "order.item_added", data: { itemId: "item-789" }, entityType: "order",}, { expectedVersion: 4 });
// result.entityVersion = 5// result.eventId = "evt-..."streams.read
Section titled “streams.read”Reads events from an entity stream.
const { events, totalCount } = await ironflow.streams.read("order-123", { fromVersion: 1, limit: 50, direction: "forward",});streams.getInfo
Section titled “streams.getInfo”Returns stream metadata, or null if no events have been written to this stream yet.
const info = await ironflow.streams.getInfo("order-123");// info.entityId, info.entityType, info.version, info.eventCount// info is null for streams with no events — safe to pass expectedVersion: 0 to append()Returns: Promise<StreamInfo | null>
streams.createSnapshot
Section titled “streams.createSnapshot”Save a materialized state snapshot at a specific stream version. Snapshots enable efficient rebuilds by avoiding replaying all events from the beginning.
const { snapshotId } = await ironflow.streams.createSnapshot("order-123", { entityType: "order", entityVersion: 42, // The stream version this snapshot represents state: { status: "OPEN", total: 99.99 }, // The materialized state});console.log(snapshotId); // Unique snapshot identifierstreams.getSnapshot
Section titled “streams.getSnapshot”Retrieve the latest snapshot at or before a given stream version.
const snapshot = await ironflow.streams.getSnapshot("order-123");// Optionally limit to snapshots before a specific version:const snapshotBeforeVersion = await ironflow.streams.getSnapshot("order-123", { beforeVersion: 50,});
console.log(snapshot.snapshotId); // Snapshot identifierconsole.log(snapshot.entityId); // Entity IDconsole.log(snapshot.entityType); // Entity typeconsole.log(snapshot.entityVersion); // Stream version this snapshot representsconsole.log(snapshot.state); // The materialized state objectconsole.log(snapshot.createdAt); // ISO 8601 creation timestampConsumer Groups
Section titled “Consumer Groups”Join a consumer group for load-balanced event processing.
const sub = await ironflow.joinConsumerGroup( 'order-processors', // Group name 'events:order.*', // Pattern { onEvent: async (event) => { try { await processOrder(event); await sub.ack(event.eventId!); } catch { await sub.nak(event.eventId!, 5000); // redeliver after 5s } }, });Functions & Workers
Section titled “Functions & Workers”listFunctions
Section titled “listFunctions”List all registered functions in the current environment.
const functions = await ironflow.listFunctions();for (const fn of functions) { console.log(fn.id, fn.name);}listWorkers
Section titled “listWorkers”List connected pull-mode workers.
const workers = await ironflow.listWorkers();for (const worker of workers) { console.log(worker.id, worker.status);}Audit Trail
Section titled “Audit Trail”getAuditTrail
Section titled “getAuditTrail”Get the audit trail for a specific run, including all state transitions and step events.
const result = await ironflow.getAuditTrail('run-abc123');for (const event of result.events) { console.log(event.eventType, event.createdAt); console.log(event.stepId, event.payload);}console.log(result.totalCount);console.log(result.nextCursor); // Pagination cursor
// With filtersconst result = await ironflow.getAuditTrail('run-abc123', { eventType: 'step.completed', fromTimestamp: '2024-01-01T00:00:00Z', toTimestamp: '2024-02-01T00:00:00Z', limit: 100, cursor: result.nextCursor,});Each AuditEvent has:
id— Unique event IDrunId— Associated run IDfunctionId— Function that owns the runstepId— Step ID (if step-level event)eventType— Event type string (e.g.'step.completed','run.failed')payload— Event-specific datametadata— Optional string key-value metadatacreatedAt— ISO 8601 timestamp
Event Schema Registry
Section titled “Event Schema Registry”Manage event schemas and test upcast transformations. Requires appropriate API key permissions.
schemas.register
Section titled “schemas.register”Register a new event schema or a new version of an existing one.
const schema = await ironflow.schemas.register({ name: 'order.placed', version: 2, schema: { type: 'object', properties: { orderId: { type: 'string' }, totalCents: { type: 'integer' }, }, required: ['orderId', 'totalCents'], },});schemas.list
Section titled “schemas.list”List all registered event schemas.
const schemas = await ironflow.schemas.list();for (const s of schemas) { console.log(s.name, s.version);}schemas.get
Section titled “schemas.get”Get the latest version of an event schema by name.
const schema = await ironflow.schemas.get('order.placed');console.log(schema.version, schema.schema);schemas.getVersion
Section titled “schemas.getVersion”Get a specific version of an event schema.
const schema = await ironflow.schemas.getVersion('order.placed', 1);schemas.delete
Section titled “schemas.delete”Delete a specific version of an event schema.
await ironflow.schemas.delete('order.placed', 1);schemas.testUpcast
Section titled “schemas.testUpcast”Test an upcast transformation from one schema version to another without persisting anything.
const result = await ironflow.schemas.testUpcast({ eventName: 'order.placed', fromVersion: 1, toVersion: 2, data: { orderId: '123', total: 99.99 },});console.log(result.output); // Transformed event dataWebhooks
Section titled “Webhooks”Manage webhook sources and inspect delivery history. Requires appropriate API key permissions.
webhooks.create
Section titled “webhooks.create”Register a new webhook source.
const source = await ironflow.webhooks.create({ id: 'stripe', // Unique source identifier eventPrefix: 'stripe', // Events will be emitted as 'stripe.*' verifyHeader: 'stripe-signature', // Header containing the signature verifyAlgorithm: 'hmac-sha256', // Signature algorithm verifySecret: 'whsec_...', // Webhook signing secret metadata: { env: 'production' }, // Optional metadata});webhooks.listSources
Section titled “webhooks.listSources”List all registered webhook sources.
const sources = await ironflow.webhooks.listSources();for (const s of sources) { console.log(s.id, s.eventPrefix, s.sourceType);}webhooks.deleteSource
Section titled “webhooks.deleteSource”Delete a webhook source by ID.
await ironflow.webhooks.deleteSource('stripe');webhooks.listDeliveries
Section titled “webhooks.listDeliveries”List webhook delivery records with optional filtering.
const { deliveries, totalCount } = await ironflow.webhooks.listDeliveries({ sourceId: 'stripe', // Filter by source status: 'failed', // 'pending' | 'delivered' | 'failed' limit: 50, offset: 0,});
for (const d of deliveries) { console.log(d.id, d.sourceId, d.status, d.error);}Admin: API Keys
Section titled “Admin: API Keys”Manage API keys for the current environment. Requires admin permissions.
apiKeys.create
Section titled “apiKeys.create”const key = await ironflow.apiKeys.create({ name: 'ci-runner' });console.log(key.key); // The raw API key — shown only onceconsole.log(key.id); // Key ID for future operationsapiKeys.list
Section titled “apiKeys.list”const keys = await ironflow.apiKeys.list();for (const k of keys) { console.log(k.id, k.name, k.createdAt);}apiKeys.get
Section titled “apiKeys.get”const key = await ironflow.apiKeys.get('ak_abc123');apiKeys.delete
Section titled “apiKeys.delete”await ironflow.apiKeys.delete('ak_abc123');apiKeys.rotate
Section titled “apiKeys.rotate”Rotate an existing key, revoking the old secret and issuing a new one.
const rotated = await ironflow.apiKeys.rotate('ak_abc123');console.log(rotated.key); // New raw secret — shown only onceAdmin: Organizations
Section titled “Admin: Organizations”Manage organizations. Requires admin permissions. Enterprise feature.
orgs.create
Section titled “orgs.create”const org = await ironflow.orgs.create({ name: 'Acme Corp' });orgs.list
Section titled “orgs.list”const orgs = await ironflow.orgs.list();orgs.get
Section titled “orgs.get”const org = await ironflow.orgs.get('org_abc123');orgs.update
Section titled “orgs.update”const org = await ironflow.orgs.update('org_abc123', { name: 'Acme Inc' });orgs.delete
Section titled “orgs.delete”await ironflow.orgs.delete('org_abc123');Admin: Roles
Section titled “Admin: Roles”Manage RBAC roles. Requires admin permissions. Enterprise feature.
roles.create
Section titled “roles.create”const role = await ironflow.roles.create({ name: 'editor', org_id: 'org_abc123',});roles.list
Section titled “roles.list”const roles = await ironflow.roles.list(); // All rolesconst orgRoles = await ironflow.roles.list('org_abc123'); // Scoped to orgroles.get
Section titled “roles.get”const role = await ironflow.roles.get('role_abc123');roles.update
Section titled “roles.update”const role = await ironflow.roles.update('role_abc123', { name: 'reviewer' });roles.delete
Section titled “roles.delete”await ironflow.roles.delete('role_abc123');roles.assignPolicy
Section titled “roles.assignPolicy”Attach a policy to a role.
await ironflow.roles.assignPolicy('role_abc123', 'policy_xyz');roles.removePolicy
Section titled “roles.removePolicy”Detach a policy from a role.
await ironflow.roles.removePolicy('role_abc123', 'policy_xyz');Admin: Policies
Section titled “Admin: Policies”Manage authorization policies. Requires admin permissions. Enterprise feature.
policies.create
Section titled “policies.create”const policy = await ironflow.policies.create({ name: 'allow-read', effect: 'allow', actions: 'read', resources: '*', org_id: 'org_abc123',});policies.list
Section titled “policies.list”const policies = await ironflow.policies.list(); // All policiesconst orgPolicies = await ironflow.policies.list('org_abc123'); // Scoped to orgpolicies.get
Section titled “policies.get”const policy = await ironflow.policies.get('policy_abc123');policies.update
Section titled “policies.update”const policy = await ironflow.policies.update('policy_abc123', { actions: 'read,write',});policies.delete
Section titled “policies.delete”await ironflow.policies.delete('policy_abc123');Admin: Users
Section titled “Admin: Users”Manage dashboard users. Requires admin permissions. Enterprise feature.
users.create
Section titled “users.create”const user = await ironflow.users.create({ email: 'alice@example.com', password: 'secret', roles: ['admin'],});users.list
Section titled “users.list”const users = await ironflow.users.list();users.get
Section titled “users.get”const user = await ironflow.users.get('user_abc123');users.update
Section titled “users.update”const user = await ironflow.users.update('user_abc123', { name: 'Alice' });users.delete
Section titled “users.delete”await ironflow.users.delete('user_abc123');Admin: Tenants
Section titled “Admin: Tenants”List tenants. Enterprise feature.
tenants.list
Section titled “tenants.list”const tenants = await ironflow.tenants.list();for (const t of tenants) { console.log(t.id, t.name);}Server Introspection
Section titled “Server Introspection”detectTransport
Section titled “detectTransport”Auto-detect the best transport.
const transport = await ironflow.detectTransport();// Returns 'connectrpc' | 'websocket'Error Handling
Section titled “Error Handling”// Error types originate from @ironflow/core (also re-exported by @ironflow/browser)import { IronflowError, ConnectionError, SubscriptionError, isRetryable} from '@ironflow/core';
ironflow.subscribe('events:*', { onEvent: (e) => console.log(e), onError: (error) => { if (error instanceof ConnectionError) { console.log('Connection lost, will auto-reconnect'); } else if (error instanceof SubscriptionError) { console.log('Subscription error:', error.message); }
if (isRetryable(error)) { // Error is transient, will be retried } },});
// Global error handlerironflow.onError((error) => { reportToSentry(error);});React Integration
Section titled “React Integration”Example custom hook for subscriptions:
import { useState, useEffect } from 'react';import { ironflow, IronflowEvent } from '@ironflow/browser';
function useSubscription<T>(pattern: string) { const [events, setEvents] = useState<IronflowEvent<T>[]>([]);
useEffect(() => { const subPromise = ironflow.subscribe<T>(pattern, { onEvent: (event) => setEvents(prev => [...prev, event]), }); return () => { subPromise.then((sub) => sub.unsubscribe()); }; }, [pattern]);
return events;}
// Usagefunction OrderList() { const orders = useSubscription<OrderData>('events:order.*');
return ( <ul> {orders.map(order => ( <li key={order.id}>{order.data.orderId}</li> ))} </ul> );}Connection Status Hook
Section titled “Connection Status Hook”function useConnectionStatus() { const [status, setStatus] = useState<ConnectionState>('disconnected');
useEffect(() => { const unsubscribe = ironflow.onConnectionChange(setStatus); return unsubscribe; }, []);
return status;}Requirements
Section titled “Requirements”- Chrome 80+
- Firefox 75+
- Safari 13.1+
- Edge 80+
See Also
Section titled “See Also”- JavaScript SDK Overview
- Node Package - Server-side SDK
- Core Package - Shared types and utilities
- Events & Pub/Sub Guide - Detailed subscription patterns
- Event Sourcing Guide - Entity streams and versioning
- KV Store Guide - Key-value storage
- Config Management Guide - Environment-scoped configuration