Skip to content

Subscriptions

Subscription patterns determine which events are delivered to a subscriber. Ironflow uses NATS-style wildcards for flexible pattern matching.

Wildcard Syntax

TokenDescriptionExample
*Matches one segment.system.run.*.created
>Matches all remaining segments.events:>

Connection Lifecycle

For real-time subscriptions, the SDK maintains a persistent connection (WebSocket or ConnectRPC stream).

import { ironflow } from "@ironflow/browser";
// 1. Connect to the stream
await ironflow.connect();
// 2. Monitor connection state
const off = ironflow.onConnectionChange((state) => {
console.log(`Connection state: ${state}`); // 'connected', 'reconnecting', etc.
});
// 3. Disconnect when finished
ironflow.disconnect();
off();

Pattern Helpers

Browser (Singleton):

import { ironflow } from "@ironflow/browser";
await ironflow.subscribe("events:order.*", { onEvent: (e) => {} });

Node.js (Instance):

import { createSubscriptionClient } from "@ironflow/node";
const subClient = createSubscriptionClient({
serverUrl: "http://localhost:9123",
apiKey: "...",
});
await subClient.connect();
const sub = await subClient.subscribe("system.run.>", { onEvent: (e) => {} });

Lifecycle & Storage

Regular subscriptions are ephemeral and stored in-memory on the server.

  1. Disconnect: If a client disconnects, the subscription is removed from the server.
  2. Reconnect: SDKs restore the pattern, filter, consumer group, metadata, acknowledgment, backpressure, and namespace options.
  3. Position: The start position depends on how you subscribed.

replay applies only to the initial subscription. Reapplying the same count on every reconnect would repeat an arbitrary historical window. On reconnect:

  • A consumer group resumes from its server-owned durable position.
  • A fan-out subscription with startAfterSequence resumes after the last sequence delivered to the caller. Delivery remains at least once.
  • An unpositioned fan-out subscription starts at the current tail and may miss events published while it was offline.

Use startAfterSequence for positioned fan-out delivery. Do not combine it with replay or a consumer group.

onEvent is not awaited, so advance the cursor only after your own work completes. An async handler runs unsupervised: the next event can be delivered before it settles, and a rejection becomes an unhandled rejection rather than reaching onError. Serialize the handler yourself if the cursor must never run ahead of the work it stands for.

await ironflow.subscribe("events:>", {
startAfterSequence: lastDeliveredSequence,
onEvent: (event) => console.log(event),
});