@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 +17 -13
- package/README.md +289 -45
- package/dist/client.d.ts +49 -49
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +329 -97
- package/dist/client.js.map +1 -1
- package/dist/config-client.d.ts +3 -14
- package/dist/config-client.d.ts.map +1 -1
- package/dist/config-client.js +3 -24
- package/dist/config-client.js.map +1 -1
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kv.d.ts.map +1 -1
- package/dist/kv.js +2 -4
- package/dist/kv.js.map +1 -1
- package/dist/subscription.d.ts +1 -0
- package/dist/subscription.d.ts.map +1 -1
- package/dist/subscription.js +64 -13
- package/dist/subscription.js.map +1 -1
- package/dist/transport/connectrpc.d.ts +1 -0
- package/dist/transport/connectrpc.d.ts.map +1 -1
- package/dist/transport/connectrpc.js +51 -30
- package/dist/transport/connectrpc.js.map +1 -1
- package/dist/transport/types.d.ts +4 -4
- package/dist/transport/types.d.ts.map +1 -1
- package/dist/transport/websocket.d.ts +7 -0
- package/dist/transport/websocket.d.ts.map +1 -1
- package/dist/transport/websocket.js +158 -37
- package/dist/transport/websocket.js.map +1 -1
- package/dist/websocket-auth.d.ts +11 -0
- package/dist/websocket-auth.d.ts.map +1 -0
- package/dist/websocket-auth.js +29 -0
- package/dist/websocket-auth.js.map +1 -0
- package/package.json +2 -2
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.
|
|
10
|
-
>
|
|
11
|
-
>
|
|
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
|
-
> -
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
>
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
>
|
|
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
|
|
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
|
-
|
|
50
|
-
|
|
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); //
|
|
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
|
-
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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.
|
|
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
|
-
|
|
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);
|
|
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.
|
|
990
|
-
//
|
|
991
|
-
//
|
|
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
|
|
1176
|
+
### Organizations
|
|
1041
1177
|
|
|
1042
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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: {
|
|
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` --
|
|
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
|
-
**
|
|
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`, `
|
|
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
|
-
**
|
|
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
|
|