@ironflow/browser 0.31.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -6,19 +6,23 @@ This file contains the binding legal terms under which Ironflow is offered.
6
6
  A plain-English summary lives at `docs/explanation/licensing.md`. If the two
7
7
  disagree, this file controls.
8
8
 
9
- > **Lawyer review status:** v1 DIY-substitute. Pending counsel review before
10
- > the first paid customer ships (issue #777). All of the following MUST be
11
- > resolved before this license is published on the public release mirror:
9
+ > **Lawyer review status:** v1 DIY-substitute. The licensor entity is
10
+ > resolved. Three sections below are original prose rather than FSL template
11
+ > text and have not been counsel-reviewed. Review is tracked in issue #777 and
12
+ > is due before the first paid customer ships:
12
13
  >
13
- > - `[LICENSOR_ENTITY]` placeholder filled with the legal entity name
14
- > - "Personal-Use and Evaluation Carve-Out" section reviewed by counsel —
15
- > this is supplemental to the FSL Permitted Purpose and was added to
16
- > match the worked examples in `docs/explanation/licensing.md` per the
17
- > plan body. JetBrains Toolbox + Postman free-tier EULAs were the
18
- > reference for the carve-out shape, but the wording is original prose
19
- > and has not been counsel-reviewed.
20
- > - "Governing Law and Venue" + "Commercial Licensing" sections reviewed
21
- > by counsel — these are original prose, not part of the FSL template.
14
+ > - "Personal-Use and Evaluation Carve-Out" — supplemental to the FSL
15
+ > Permitted Purpose, added to match the worked examples in
16
+ > `docs/explanation/licensing.md` per the plan body. JetBrains Toolbox and
17
+ > Postman free-tier EULAs were the reference for the carve-out shape, but
18
+ > the wording is ours.
19
+ > - "Governing Law and Venue"
20
+ > - "Commercial Licensing"
21
+ >
22
+ > This is a disclosure, not a publication gate. These terms ship on every
23
+ > public release channel today — npm, the Go module proxy, PyPI, the releases
24
+ > mirror and ironflow.run — and an earlier wording of this block claimed
25
+ > otherwise while four releases went out past it.
22
26
  >
23
27
  > **Versioning:** revised terms apply on next install. Each release ships
24
28
  > the LICENSE that was effective at the time the artifact was built.
@@ -36,7 +40,7 @@ FSL-1.1-ALv2
36
40
 
37
41
  ## Notice
38
42
 
39
- Copyright 2026 [LICENSOR_ENTITY]
43
+ Copyright 2026 AEC Office LLC
40
44
 
41
45
  ## Terms and Conditions
42
46
 
package/README.md CHANGED
@@ -19,6 +19,8 @@ This README is the sole reference for coding agents integrating with the browser
19
19
  - [KV Store](#kv-store)
20
20
  - [Config Management](#config-management)
21
21
  - [Auth Management](#auth-management)
22
+ - [Event Schema Registry](#event-schema-registry)
23
+ - [Webhook Source Management](#webhook-source-management)
22
24
  - [Server Inspection](#server-inspection)
23
25
  - [React Integration Patterns](#react-integration-patterns)
24
26
  - [Transport Configuration](#transport-configuration)
@@ -46,8 +48,8 @@ ironflow.configure({
46
48
  environment: 'default', // Default: 'default'. Target environment for isolation.
47
49
  timeout: 30000, // Request timeout in ms (default: 30000)
48
50
  auth: {
49
- apiKey: 'your-api-key', // API key for authentication
50
- token: 'bearer-token', // Alternative: bearer token
51
+ token: 'short-lived-session-token', // Preferred for browser applications
52
+ // apiKey: 'ifkey_...', // Development only; never ship in a browser bundle
51
53
  },
52
54
  reconnect: {
53
55
  enabled: true, // Default: true
@@ -185,6 +187,24 @@ const sub = await ironflow.subscribe('events:order.*', {
185
187
  console.log(sub.lastEvent);
186
188
  ```
187
189
 
190
+ To resume after an exact sequence, use `startAfterSequence` instead of
191
+ `replay`. Do not combine it with a consumer group. The SDK advances the cursor
192
+ after each delivered event and uses it on reconnect. Delivery remains
193
+ at-least-once, so handlers must tolerate a repeated in-flight event.
194
+
195
+ `replay` applies only to the initial subscribe request. Reconnects preserve the
196
+ filter, consumer group, metadata, acknowledgment, backpressure, and namespace
197
+ options but omit the original replay count. A fan-out subscription without a
198
+ cursor reconnects at the current tail and can miss events published while it
199
+ was offline. Use `startAfterSequence` or a consumer group when that gap matters.
200
+
201
+ ```typescript
202
+ await ironflow.subscribe('events:order.*', {
203
+ startAfterSequence: 400,
204
+ onEvent: handleOrder,
205
+ });
206
+ ```
207
+
188
208
  ### Multiple Patterns
189
209
 
190
210
  Subscribe to an array of patterns. Returns a combined subscription that unsubscribes from all at once:
@@ -281,6 +301,19 @@ await sub.term(eventId); // Terminate - do not redeliver
281
301
  sub.unsubscribe();
282
302
  ```
283
303
 
304
+ Create and manage the durable group definition separately from joining it:
305
+
306
+ ```typescript
307
+ const group = await ironflow.consumerGroups.create({
308
+ name: 'order-processors',
309
+ pattern: 'events:order.*',
310
+ });
311
+ const groups = await ironflow.consumerGroups.list();
312
+ const one = await ironflow.consumerGroups.get(group.name);
313
+ await ironflow.consumerGroups.update(group.name, { maxInflight: 50 });
314
+ await ironflow.consumerGroups.delete(group.name);
315
+ ```
316
+
284
317
  Alternatively, use `subscribe` directly with `consumerGroup` and `ackMode` options:
285
318
 
286
319
  ```typescript
@@ -322,6 +355,46 @@ const result = await ironflow.emit(
322
355
  );
323
356
  ```
324
357
 
358
+ Publish to a developer topic without triggering workflow functions:
359
+
360
+ ```typescript
361
+ const published = await ironflow.publish(
362
+ 'notifications',
363
+ { userId: '123', message: 'Hello!' },
364
+ { idempotencyKey: 'notification-123' },
365
+ );
366
+ console.log(published.eventId, published.sequence);
367
+ ```
368
+
369
+ ### Emit and Wait, Batch Emit
370
+
371
+ ```typescript
372
+ // Wait for the triggered run to reach a terminal state.
373
+ // Throws RunFailedError / RunCancelledError if it does not complete.
374
+ const result = await ironflow.emitSync('order.placed', { orderId: '123' }, { timeout: 30000 });
375
+ console.log(result.runId, result.status, result.output, result.durationMs);
376
+
377
+ // One round trip, one EmitResult per event, in order
378
+ const results = await ironflow.triggerBatch([
379
+ { event: 'order.placed', data: { orderId: '1' } },
380
+ { event: 'order.placed', data: { orderId: '2' }, idempotencyKey: 'order-2' },
381
+ ]);
382
+ ```
383
+
384
+ ### Reading Stored Events
385
+
386
+ ```typescript
387
+ // Keyset-paginated page of the event log
388
+ const page = await ironflow.listEvents({ name: 'order.placed', limit: 50 });
389
+ console.log(page.events, page.nextCursor);
390
+
391
+ // One stored event
392
+ const event = await ironflow.getEvent('evt_abc123');
393
+
394
+ // Distinct event names with counts, for pickers and filters
395
+ const { names } = await ironflow.listEventNames();
396
+ ```
397
+
325
398
  ## Offline Writes
326
399
 
327
400
  For apps that keep working with no connection. `createClient()` returns a client
@@ -504,12 +577,12 @@ const run = await ironflow.getRun('run_abc123');
504
577
 
505
578
  console.log(run.id); // 'run_abc123'
506
579
  console.log(run.functionId); // 'process-order'
507
- console.log(run.status); // 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
580
+ console.log(run.status); // 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'paused' | 'waiting_for_capacity' | 'waiting'
508
581
  console.log(run.attempt); // Current attempt number
509
582
  console.log(run.maxAttempts); // Maximum retry attempts
510
583
  console.log(run.input); // Input data
511
584
  console.log(run.output); // Output data (if completed)
512
- console.log(run.error); // Error message (if failed)
585
+ console.log(run.error); // { message, code } (if failed)
513
586
  console.log(run.startedAt); // Date | undefined
514
587
  console.log(run.endedAt); // Date | undefined
515
588
  console.log(run.createdAt); // Date
@@ -544,6 +617,32 @@ const run = await ironflow.resumeRun('run_abc123', 'step-to-resume-from');
544
617
  await ironflow.patchStep('step_xyz789', { correctedValue: 42 }, 'Manual fix');
545
618
  ```
546
619
 
620
+ ### Run Introspection
621
+
622
+ ```typescript
623
+ const { steps, count } = await ironflow.getRunSteps('run_abc123');
624
+ const { entityIds } = await ironflow.getRunStreams('run_abc123');
625
+ ```
626
+
627
+ ### Audit Trail
628
+
629
+ ```typescript
630
+ const trail = await ironflow.getAuditTrail('run_abc123', { eventType: 'step.completed', limit: 50 });
631
+ ```
632
+
633
+ ### Function Lifecycle and Versioning
634
+
635
+ ```typescript
636
+ const fn = await ironflow.getFunction('process-order');
637
+
638
+ await ironflow.updateFunctionStatus('process-order', 'paused'); // pause dispatch
639
+ await ironflow.deleteFunction('process-order');
640
+
641
+ const history = await ironflow.listFunctionHistory('process-order', { limit: 20 });
642
+ const older = await ironflow.getFunctionAtVersion('process-order', 3);
643
+ await ironflow.rollbackFunction('process-order', 3, 'bad concurrency key');
644
+ ```
645
+
547
646
  ### Scoped Injection
548
647
 
549
648
  ```typescript
@@ -757,6 +856,30 @@ if (info) {
757
856
 
758
857
  **Returns:** `Promise<StreamInfo | null>`
759
858
 
859
+ ### List Streams and Read Entity History
860
+
861
+ ```typescript
862
+ const streams = await ironflow.streams.listStreams();
863
+ const history = await ironflow.streams.getEntityHistory('order-123');
864
+ ```
865
+
866
+ ### Snapshots
867
+
868
+ Skip replaying a long stream from version 0 by snapshotting the materialized
869
+ state at a version.
870
+
871
+ ```typescript
872
+ const { snapshotId } = await ironflow.streams.createSnapshot('order-123', {
873
+ entityType: 'order',
874
+ entityVersion: 1000,
875
+ state: materialized,
876
+ });
877
+
878
+ const snap = await ironflow.streams.getSnapshot('order-123');
879
+ // Optional: only consider snapshots at or before a version
880
+ const older = await ironflow.streams.getSnapshot('order-123', { beforeVersion: 500 });
881
+ ```
882
+
760
883
  ### Subscribe to Stream Updates
761
884
 
762
885
  ```typescript
@@ -850,14 +973,39 @@ console.log(status.lastEventSeq); // Last processed sequence number
850
973
  console.log(status.lag); // Number of unprocessed events
851
974
  console.log(status.errorMessage); // Error message if status is 'error'
852
975
  console.log(status.updatedAt); // Date
976
+ ```
977
+
978
+ Projection lifecycle operations such as rebuild, pause, resume, and delete are
979
+ operator concerns and are intentionally not exposed by the Browser SDK.
980
+
981
+ ### Read-Your-Writes
982
+
983
+ `streams.append()` returns no NATS sequence under the transactional outbox, so
984
+ resolve the event ID to a sequence with `waitForEvent`, then wait on it.
853
985
 
854
- // Trigger a rebuild
855
- const result = await ironflow.rebuildProjection('order-stats', {
856
- partition: 'customer-123', // Optional: rebuild specific partition
857
- fromEventId: 'evt_abc', // Optional: rebuild from specific event
858
- dryRun: true, // Optional: validate without rebuilding
986
+ ```typescript
987
+ const { eventId } = await ironflow.streams.append('order-123', event);
988
+
989
+ const wait = await ironflow.waitForEvent(eventId, 'order-detail-view', { timeoutMs: 5000 });
990
+
991
+ await ironflow.waitForProjectionCatchup('order-detail-view', {
992
+ minSeq: wait.targetSeq,
993
+ partition: 'order-123',
994
+ timeoutMs: 5000,
995
+ });
996
+ ```
997
+
998
+ ### Query a SQL Projection
999
+
1000
+ For projections materialized into relational tables (PostgreSQL backend).
1001
+
1002
+ ```typescript
1003
+ const result = await ironflow.querySQLProjection('board', {
1004
+ where: "status = 'OPEN'",
1005
+ orderBy: 'title ASC',
1006
+ limit: 50,
859
1007
  });
860
- console.log(result.status); // 'rebuilding' | 'dry_run_ok'
1008
+ console.log(result.columns, result.rows, result.totalCount);
861
1009
  ```
862
1010
 
863
1011
  ## KV Store
@@ -955,40 +1103,28 @@ watcher.stop();
955
1103
 
956
1104
  ## Config Management
957
1105
 
958
- Centralized configuration management with set, get, patch, list, delete, and real-time watch.
1106
+ Read environment-scoped configuration and watch changes in real time. Config
1107
+ mutations are intentionally limited to trusted server-side and operator clients.
959
1108
 
960
1109
  ```typescript
961
1110
  import { ironflow } from '@ironflow/browser';
962
1111
 
963
1112
  const config = ironflow.configManager();
964
1113
 
965
- // Set a config (full document replacement)
966
- const result = await config.set('app-settings', {
967
- theme: 'dark',
968
- locale: 'en',
969
- maxRetries: 3,
970
- });
971
-
972
1114
  // Get a config by name
973
1115
  const settings = await config.get('app-settings');
974
- console.log(settings.data); // { theme: 'dark', locale: 'en', maxRetries: 3 }
1116
+ console.log(settings.data);
975
1117
  console.log(settings.revision); // Revision number
976
1118
 
977
- // Patch a config (shallow merge)
978
- await config.patch('app-settings', { locale: 'fr' });
979
-
980
1119
  // List all configs
981
1120
  const all = await config.list();
982
1121
  // Returns ConfigEntry[]
983
1122
 
984
- // Delete a config (idempotent)
985
- await config.delete('app-settings');
986
-
987
1123
  // Watch for real-time config changes.
988
1124
  // Subscribes to system.config.{name}.updated. Auto-connects on first call —
989
- // no explicit ironflow.connect() needed. The server emits on set() and
990
- // patch() after the KV write, so cross-tab / CLI / REST-triggered updates
991
- // all reach the subscriber. Payload includes `revision`; drop events whose
1125
+ // no explicit ironflow.connect() needed. Changes made through a trusted SDK,
1126
+ // the CLI, dashboard, or REST API reach the subscriber. Payload includes
1127
+ // `revision`; drop events whose
992
1128
  // revision is lower than the last one you applied to guard against rare
993
1129
  // out-of-order deliveries under retry.
994
1130
  const watcher = await config.watch('app-settings', {
@@ -1037,9 +1173,12 @@ console.log(rotated.key); // New secret
1037
1173
  await ironflow.apiKeys.delete('apikey_abc123');
1038
1174
  ```
1039
1175
 
1040
- ### Organizations (Enterprise)
1176
+ ### Organizations
1041
1177
 
1042
- Requires an Enterprise license. Returns `EnterpriseRequiredError` (HTTP 402) without one.
1178
+ Gated by RBAC, not by a licence tier. Creating an org needs a **platform**
1179
+ credential (`ifplatform_`) — a tenant key gets `403 platform credential
1180
+ required`, because a tenant is pinned to one org (#660). Get/update/delete need
1181
+ `orgs:manage` and are scoped to the caller's own org.
1043
1182
 
1044
1183
  ```typescript
1045
1184
  // Create an organization
@@ -1058,7 +1197,7 @@ const updated = await ironflow.orgs.update('org_abc123', { name: 'Acme Inc' });
1058
1197
  await ironflow.orgs.delete('org_abc123');
1059
1198
  ```
1060
1199
 
1061
- ### Roles (Enterprise)
1200
+ ### Roles
1062
1201
 
1063
1202
  ```typescript
1064
1203
  // Create a role
@@ -1082,11 +1221,14 @@ await ironflow.roles.assignPolicy('role_xyz789', 'policy_abc');
1082
1221
  // Remove a policy from a role
1083
1222
  await ironflow.roles.removePolicy('role_xyz789', 'policy_abc');
1084
1223
 
1224
+ // List policies assigned to a role
1225
+ const assignedPolicies = await ironflow.roles.listPolicies('role_xyz789');
1226
+
1085
1227
  // Delete a role
1086
1228
  await ironflow.roles.delete('role_xyz789');
1087
1229
  ```
1088
1230
 
1089
- ### Policies (Enterprise)
1231
+ ### Policies
1090
1232
 
1091
1233
  ```typescript
1092
1234
  // Create a policy
@@ -1114,6 +1256,73 @@ const updated = await ironflow.policies.update('policy_abc', {
1114
1256
  await ironflow.policies.delete('policy_abc');
1115
1257
  ```
1116
1258
 
1259
+ ### Rotating Credentials at Runtime
1260
+
1261
+ `setAuth` swaps the credential in place. Every request path reads `config.auth`
1262
+ at send time, so the next request picks it up; an already-open subscription
1263
+ keeps the credentials it connected with until it reconnects.
1264
+
1265
+ ```typescript
1266
+ ironflow.setAuth({ token: refreshedSession.accessToken });
1267
+ ```
1268
+
1269
+ ## Event Schema Registry
1270
+
1271
+ Server-side JSON Schema registry for event contracts.
1272
+
1273
+ ```typescript
1274
+ await ironflow.schemas.register({
1275
+ name: 'order.placed',
1276
+ version: 2,
1277
+ schema: { type: 'object', properties: { orderId: { type: 'string' } } },
1278
+ });
1279
+
1280
+ const all = await ironflow.schemas.list();
1281
+ const latest = await ironflow.schemas.get('order.placed');
1282
+ const v1 = await ironflow.schemas.getVersion('order.placed', 1);
1283
+ await ironflow.schemas.delete('order.placed', 1);
1284
+
1285
+ // Dry-run a server-side upcast
1286
+ const out = await ironflow.schemas.testUpcast({
1287
+ eventName: 'order.placed',
1288
+ fromVersion: 1,
1289
+ toVersion: 2,
1290
+ data: { orderId: '123' },
1291
+ });
1292
+ ```
1293
+
1294
+ ## Webhook Source Management
1295
+
1296
+ Manage the server-side webhook registry the dashboard and delivery tracking
1297
+ read. Operator surface — an app that only receives webhooks does not need it.
1298
+
1299
+ ```typescript
1300
+ // ingestToken is returned only here and on rotate (ADR 0048) — capture it now.
1301
+ const source = await ironflow.webhooks.create({
1302
+ name: 'Stripe production',
1303
+ eventPrefix: 'stripe',
1304
+ });
1305
+
1306
+ const sources = await ironflow.webhooks.listSources();
1307
+ const current = await ironflow.webhooks.getSource(source.id);
1308
+
1309
+ // Full-replace, not patch: omitted fields are cleared server-side.
1310
+ await ironflow.webhooks.updateSource({
1311
+ id: current.id,
1312
+ name: 'Stripe production (EU)',
1313
+ expectedUpdatedAt: current.updatedAt,
1314
+ });
1315
+
1316
+ // graceSeconds is tri-state: omit = server default, 0 = instant cutover, N = seconds.
1317
+ await ironflow.webhooks.rotateSecret({ id: source.id, verifySecret: 'whsec_new' });
1318
+ await ironflow.webhooks.expireSecretPrev(source.id);
1319
+ await ironflow.webhooks.disableSignatureVerification({ id: source.id, graceSeconds: 0 });
1320
+ await ironflow.webhooks.rotateIngestToken(source.id);
1321
+
1322
+ const { deliveries } = await ironflow.webhooks.listDeliveries({ sourceId: source.id, limit: 25 });
1323
+ await ironflow.webhooks.deleteSource(source.id);
1324
+ ```
1325
+
1117
1326
  ## Server Inspection
1118
1327
 
1119
1328
  ```typescript
@@ -1136,6 +1345,17 @@ const caps = await ironflow.getCapabilities();
1136
1345
  console.log(caps.transports); // ['connectrpc', 'websocket']
1137
1346
  console.log(caps.features); // ['kv', 'projections', 'entity-streams', ...]
1138
1347
  console.log(caps.version); // Server version
1348
+
1349
+ // Query the environment-wide audit stream
1350
+ const auditPage = await ironflow.listAuditEvents({ eventType: 'run.failed', limit: 50 });
1351
+
1352
+ // Provision a tenant and initial administrator key. Both tenant calls
1353
+ // require the `users:manage` permission; 403 otherwise.
1354
+ const tenant = await ironflow.tenants.provision({ orgName: 'Acme' });
1355
+ const tenants = await ironflow.tenants.list();
1356
+
1357
+ // Active subscription count — for leak audits; 0 when not configured
1358
+ console.log(ironflow.getActiveSubscriptionCount());
1139
1359
  ```
1140
1360
 
1141
1361
  ## React Integration Patterns
@@ -1310,11 +1530,15 @@ import { ironflow } from '@ironflow/browser';
1310
1530
  ironflow.configure({
1311
1531
  serverUrl: process.env.NEXT_PUBLIC_IRONFLOW_URL ?? 'http://localhost:9123',
1312
1532
  auth: {
1313
- apiKey: process.env.NEXT_PUBLIC_IRONFLOW_API_KEY,
1533
+ token: session.accessToken,
1314
1534
  },
1315
1535
  });
1316
1536
  ```
1317
1537
 
1538
+ Obtain `session.accessToken` from a trusted authentication backend. Do not put
1539
+ an `ifkey_` environment key in a `NEXT_PUBLIC_*` variable or browser bundle.
1540
+ Development builds warn when an `ifkey_` credential is configured.
1541
+
1318
1542
  ## Transport Configuration
1319
1543
 
1320
1544
  The browser client supports two transport protocols for real-time subscriptions:
@@ -1341,7 +1565,10 @@ ironflow.configure({
1341
1565
  });
1342
1566
  ```
1343
1567
 
1344
- The WebSocket URL is derived from `serverUrl` by replacing `http://` with `ws://` and `https://` with `wss://`.
1568
+ The WebSocket URL is derived from `serverUrl` by replacing `http://` with
1569
+ `ws://` and `https://` with `wss://`. Authentication is sent as WebSocket
1570
+ subprotocol metadata, not as a `token=` query parameter, so credentials do not
1571
+ appear in ordinary proxy access logs.
1345
1572
 
1346
1573
  ### Advanced: Custom Transport
1347
1574
 
@@ -1359,7 +1586,7 @@ import {
1359
1586
 
1360
1587
  // Create a transport manually
1361
1588
  const options: TransportOptions = {
1362
- auth: { apiKey: 'my-key' },
1589
+ auth: { token: session.accessToken },
1363
1590
  autoReconnect: true,
1364
1591
  reconnectDelay: 1000,
1365
1592
  maxReconnectDelay: 30000,
@@ -1389,13 +1616,14 @@ import {
1389
1616
  RunCancelledError, // agents.invoke: terminal run cancellation
1390
1617
  AgentInvokeTimeoutError, // agents.invoke: local timeoutMs elapsed
1391
1618
  NoRunCreatedError, // agents.invoke: server returned no runIds
1619
+ QueueFullError, // offline queue at 500 writes or 5 MB
1392
1620
  } from '@ironflow/browser';
1393
1621
  ```
1394
1622
 
1395
1623
  Additionally, the REST request helper maps HTTP status codes to specific error types. Import these (and `MemoryCatchupTimeoutError` for `agents.readMemory`) from `@ironflow/core`:
1396
1624
 
1397
1625
  - **401** -> `UnauthenticatedError` -- missing or invalid credentials
1398
- - **402** -> `EnterpriseRequiredError` -- enterprise license required
1626
+ - **402** -> `EnterpriseRequiredError` -- legacy. Ironflow ships a single tier (ADR 0015) and the server no longer returns 402; the mapping is retained for compatibility
1399
1627
  - **403** -> `UnauthorizedError` -- insufficient permissions
1400
1628
 
1401
1629
  ### Error Utilities
@@ -1452,29 +1680,45 @@ Requires native `fetch`, `WebSocket`, and `AbortController` support.
1452
1680
 
1453
1681
  The package re-exports the following types from `@ironflow/core` for convenience:
1454
1682
 
1455
- **Run types:** `Run`, `RunStatus`, `RunInfo`, `ListRunsOptions`, `ListRunsResult`
1683
+ **Run types:** `Run`, `RunStatus`, `RunInfo`, `ListRunsOptions`, `ListRunsResult`, `RunStep`, `RunStepsResult`, `RunStreamsResult`
1684
+
1685
+ **Function types:** `FunctionStatus`, `RegisteredFunction`, `FunctionChangeType`, `FunctionHistoryEntry`, `ListFunctionHistoryOptions`, `ListFunctionHistoryResult`
1686
+
1687
+ **Event types:** `IronflowEvent`, `EmitOptions`, `EmitResult`, `TriggerBatchEvent`, `StoredEvent`, `ListEventsOptions`, `ListEventsResult`, `EventNameCount`, `ListEventNamesOptions`, `ListEventNamesResult`
1456
1688
 
1457
- **Event types:** `IronflowEvent`, `EmitOptions`, `EmitResult`
1689
+ **Pub/Sub types:** `PublishOptions`, `PublishResult`
1458
1690
 
1459
- **Invoke/Trigger types:** `InvokeResult`, `TriggerSyncOptions`, `TriggerSyncResult`
1691
+ **Invoke/Trigger types:** `InvokeResult`, `TriggerResult` (deprecated alias), `TriggerSyncOptions`, `TriggerSyncResult`
1460
1692
 
1461
1693
  **Subscription types:** `SubscribeOptions`, `Subscription`, `AckableSubscription`, `SubscriptionEvent`, `SubscriptionErrorInfo`, `SubscriptionCallbacks`, `ConnectionState`, `AckHandle`
1462
1694
 
1463
- **Consumer group types:** `ConsumerGroup`, `ConsumerGroupConfig`, `ConsumerGroupStatus`, `AckMode`, `BackpressureMode`
1695
+ **Consumer group types:** `ConsumerGroup`, `ConsumerGroupConfig`, `ConsumerGroupStatus`, `AckMode`, `BackpressureMode`, `UpdateConsumerGroupInput`
1464
1696
 
1465
- **Entity stream types:** `AppendEventInput`, `AppendOptions`, `AppendResult`, `ReadStreamOptions`, `StreamEvent`, `StreamInfo`, `EntitySubscribeOptions`
1697
+ **Entity stream types:** `AppendEventInput`, `AppendOptions`, `AppendResult`, `ReadStreamOptions`, `StreamEvent`, `StreamInfo`, `EntitySubscribeOptions`, `StreamListEntry`, `EntityHistoryEntry`
1466
1698
 
1467
1699
  **Projection types:** `ProjectionStatusInfo`, `ProjectionStateResult`
1468
1700
 
1701
+ **Audit types:** `AuditEvent`, `AuditTrailResult`, `GetAuditTrailOptions`, `ListAuditEventsOptions`
1702
+
1703
+ **Webhook management types:** `WebhookSource`, `CreateWebhookSourceInput`, `UpdateWebhookSourceInput`, `RotateWebhookSecretInput`, `DisableWebhookSignatureVerificationInput`, `WebhookDelivery`, `ListWebhookDeliveriesOptions`
1704
+
1705
+ **Tenant types:** `Tenant`, `ProvisionTenantInput`, `ProvisionTenantResult`
1706
+
1469
1707
  **KV types:** `KVBucketConfig`, `KVBucketInfo`, `KVEntry`, `KVPutResult`, `KVListKeysResult`, `KVListBucketsResult`, `KVWatchEvent`, `KVWatchCallbacks`, `KVWatchOptions`, `KVWatcher`
1470
1708
 
1471
- **Config types:** `ConfigResponse`, `ConfigEntry`, `ConfigSetResult`, `ConfigWatchCallbacks`, `ConfigWatchEvent`
1709
+ **Config types:** `ConfigResponse`, `ConfigEntry`, `ConfigWatchCallbacks`, `ConfigWatchEvent`
1710
+
1711
+ **Browser-specific types:** `IronflowClient` (type only — construct through `ironflow` or `createClient()`), `IronflowConfig`, `IronflowConfigOptions`, `ReconnectConfig`, `VisibilityConfig`, `AuthConfig`, `BrowserSubscribeOptions`, `SubscriptionGroup`, `Transport`, `TransportCallbacks`, `TransportFactory`, `TransportOptions`
1712
+
1713
+ **Agent types:** `AgentsNamespace`, `AgentInvokeOptions`, `AgentInvokeResult`, `AgentProgressEvent`, `AgentStepEvent`, `AgentSubscribeCallbacks`
1714
+
1715
+ **Offline queue types:** `CreateClientOptions`, `OfflineQueueConfig`, `QueueApi`, `QueuedWriteResult`, `QueuedWrite`, `QueuedWriteKind`, `DeadLetteredWrite`, `QueueState`, `QueueStats`, `WriteStatus`, `WriteLostReason`
1472
1716
 
1473
- **Browser-specific types:** `IronflowConfig`, `IronflowConfigOptions`, `ReconnectConfig`, `VisibilityConfig`, `AuthConfig`, `BrowserSubscribeOptions`, `SubscriptionGroup`, `Transport`, `TransportCallbacks`, `TransportFactory`, `TransportOptions`
1717
+ **Logger:** `Logger`
1474
1718
 
1475
- **Utilities:** `patterns`, `DEFAULT_SERVER_URL`, `DEFAULT_WS_URL`, `DEFAULT_TIMEOUTS`, `getServerUrl`, `getWebSocketUrl`, `DEFAULT_CONFIG`, `mergeConfig`
1719
+ **Utilities:** `patterns`, `DEFAULT_SERVER_URL`, `DEFAULT_WS_URL`, `DEFAULT_TIMEOUTS`, `getServerUrl`, `getWebSocketUrl`, `DEFAULT_CONFIG`, `mergeConfig`, `createWebSocketTransport`, `createConnectRPCTransport`, `queueDbName`
1476
1720
 
1477
- **Classes:** `BrowserKVClient`, `BrowserKVBucketHandle`, `BrowserConfigClient`, `SubscriptionManager`
1721
+ **Classes:** `BrowserKVClient`, `BrowserKVBucketHandle`, `BrowserConfigClient`, `SubscriptionManager`, `OfflineClient`, `createClient`
1478
1722
 
1479
1723
  ## Links
1480
1724