@ironflow/core 0.7.0 → 0.8.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.
Files changed (3) hide show
  1. package/README.md +1865 -101
  2. package/dist/schemas.d.ts +5 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,181 +1,1945 @@
1
1
  # @ironflow/core
2
2
 
3
- Shared types, schemas, constants, and utilities for the Ironflow JavaScript SDK.
3
+ Shared types, Zod schemas, error classes, constants, and utilities for the Ironflow JavaScript SDK. This package is the foundation that both `@ironflow/browser` and `@ironflow/node` depend on. It contains zero platform-specific code and runs in any JavaScript environment.
4
4
 
5
- > **Note:** You typically don't need to install this package directly. It's automatically included as a dependency of `@ironflow/browser` and `@ironflow/node`.
5
+ **This is a private npm package.** External npm docs are not available. Use this README as the sole reference.
6
+
7
+ - Source: `sdk/js/core/src/`
8
+ - Entry point: `@ironflow/core` (re-exports everything from `index.ts`)
9
+ - Sub-path exports: `@ironflow/core/schemas`, `@ironflow/core/protocol`, `@ironflow/core/gen`
10
+ - Runtime dependency: `zod` (v4+)
11
+ - Optional dependencies: `@bufbuild/protobuf`, `@connectrpc/connect` (only for `/gen` sub-path)
12
+
13
+ Docs: <https://github.com/sahina/ironflow/tree/main/docs>
14
+
15
+ ---
16
+
17
+ ## Table of Contents
18
+
19
+ 1. [Installation](#installation)
20
+ 2. [Branded Types](#branded-types)
21
+ 3. [Function Types](#function-types)
22
+ 4. [Event Types](#event-types)
23
+ 5. [Step Types](#step-types)
24
+ 6. [Run Types](#run-types)
25
+ 7. [Subscription Types](#subscription-types)
26
+ 8. [Entity Stream Types](#entity-stream-types)
27
+ 9. [Pub/Sub Types](#pubsub-types)
28
+ 10. [KV Types](#kv-types)
29
+ 11. [Config Types](#config-types)
30
+ 12. [Auth Types](#auth-types)
31
+ 13. [Audit Types](#audit-types)
32
+ 14. [Webhook Types](#webhook-types)
33
+ 15. [Projection Types](#projection-types)
34
+ 16. [Error Classes](#error-classes)
35
+ 17. [Schemas](#schemas)
36
+ 18. [Protocol Types](#protocol-types)
37
+ 19. [Constants](#constants)
38
+ 20. [Utilities](#utilities)
39
+ 21. [Upcasters](#upcasters)
40
+ 22. [Logger](#logger)
41
+ 23. [SecretsClient](#secretsclient)
42
+
43
+ ---
6
44
 
7
45
  ## Installation
8
46
 
9
- ```bash
10
- npm install @ironflow/core
47
+ ```bash
48
+ npm install @ironflow/core
49
+ ```
50
+
51
+ Most users do not install this package directly. It is included as a dependency of `@ironflow/browser` (browser client, subscriptions) and `@ironflow/node` (worker, serve, projections), both of which re-export core types.
52
+
53
+ ---
54
+
55
+ ## Branded Types
56
+
57
+ Branded types provide compile-time type safety for ID strings. A `RunId` cannot be accidentally passed where a `FunctionId` is expected.
58
+
59
+ ```typescript
60
+ import type {
61
+ RunId, FunctionId, StepId, EventId, JobId, WorkerId, SubscriptionId,
62
+ Branded,
63
+ } from '@ironflow/core';
64
+
65
+ import {
66
+ createRunId, createFunctionId, createStepId,
67
+ createEventId, createJobId, createWorkerId, createSubscriptionId,
68
+ } from '@ironflow/core';
69
+ ```
70
+
71
+ ### Factory Functions
72
+
73
+ Each factory casts a plain string to the branded type at zero runtime cost:
74
+
75
+ ```typescript
76
+ const runId: RunId = createRunId('run_abc123');
77
+ const fnId: FunctionId = createFunctionId('my-workflow');
78
+ const stepId: StepId = createStepId('step_001');
79
+ const eventId: EventId = createEventId('evt_xyz');
80
+ const jobId: JobId = createJobId('job_456');
81
+ const workerId: WorkerId = createWorkerId('wkr_789');
82
+ const subId: SubscriptionId = createSubscriptionId('sub_012');
83
+ ```
84
+
85
+ ### Branded Helper
86
+
87
+ You can create your own branded types:
88
+
89
+ ```typescript
90
+ type OrderId = Branded<string, 'OrderId'>;
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Function Types
96
+
97
+ ### FunctionConfig
98
+
99
+ Full configuration for a workflow function.
100
+
101
+ ```typescript
102
+ import type { FunctionConfig } from '@ironflow/core';
103
+
104
+ interface FunctionConfig<TEventSchema extends z.ZodType = z.ZodType> {
105
+ /** Unique function identifier */
106
+ id: string;
107
+ /** Display name for the function */
108
+ name?: string;
109
+ /** Event triggers that invoke this function */
110
+ triggers: Trigger[];
111
+ /** Retry configuration for failed steps */
112
+ retry?: RetryConfig;
113
+ /** Function timeout in milliseconds (default: 600000 = 10 minutes) */
114
+ timeout?: number;
115
+ /** Concurrency control configuration */
116
+ concurrency?: ConcurrencyConfig;
117
+ /** Execution mode: "push" for serverless, "pull" for workers */
118
+ mode?: ExecutionMode;
119
+ /** JSON path for actor-based sticky routing */
120
+ actorKey?: string;
121
+ /** Zod schema for type-safe event validation */
122
+ schema?: TEventSchema;
123
+ /** Secret names this function requires (resolved by engine at execution time) */
124
+ secrets?: string[];
125
+ /** Default timeout for all step.run() calls ("30s", "5m", "1h") */
126
+ stepTimeout?: string;
127
+ /** Enable audit recording for this function */
128
+ recording?: boolean;
129
+ /** Retention period for audit events ("7d", "30d", "90d", "forever") */
130
+ recordingRetention?: string;
131
+ }
132
+ ```
133
+
134
+ ### Trigger
135
+
136
+ ```typescript
137
+ interface Trigger {
138
+ /** Event name pattern to match (e.g., "order.placed") */
139
+ event: string;
140
+ /** Optional CEL expression for filtering */
141
+ expression?: string;
142
+ /** Cron schedule expression (e.g., "0 9 * * *" for 9am daily) */
143
+ cron?: string;
144
+ }
145
+ ```
146
+
147
+ ### RetryConfig
148
+
149
+ ```typescript
150
+ interface RetryConfig {
151
+ /** Maximum number of retry attempts (default: 3) */
152
+ maxAttempts?: number;
153
+ /** Initial delay between retries in ms (default: 1000) */
154
+ initialDelayMs?: number;
155
+ /** Backoff multiplier (default: 2.0) */
156
+ backoffFactor?: number;
157
+ /** Maximum delay between retries in ms (default: 300000) */
158
+ maxDelayMs?: number;
159
+ }
160
+ ```
161
+
162
+ ### ConcurrencyConfig
163
+
164
+ ```typescript
165
+ interface ConcurrencyConfig {
166
+ /** Maximum concurrent executions */
167
+ limit: number;
168
+ /** JSON path for grouping (e.g., "event.data.customerId") */
169
+ key?: string;
170
+ }
171
+ ```
172
+
173
+ ### ExecutionMode
174
+
175
+ ```typescript
176
+ type ExecutionMode = "push" | "pull";
177
+ ```
178
+
179
+ - `"push"` -- HTTP POST to serverless functions (Next.js, Lambda). For tasks under 10 seconds.
180
+ - `"pull"` -- gRPC/HTTP polling for long-running workers. No timeout limits.
181
+
182
+ ### FunctionContext
183
+
184
+ Context object passed to every function handler.
185
+
186
+ ```typescript
187
+ interface FunctionContext<TEvent = unknown> {
188
+ /** The triggering event */
189
+ event: IronflowEvent<TEvent>;
190
+ /** Step execution client */
191
+ step: StepClient;
192
+ /** Run information */
193
+ run: RunInfo;
194
+ /** Logger instance */
195
+ logger: Logger;
196
+ /** Resolved environment secrets (read-only) */
197
+ secrets: SecretsClient;
198
+ }
199
+ ```
200
+
201
+ ### FunctionHandler and IronflowFunction
202
+
203
+ ```typescript
204
+ type FunctionHandler<TEvent = unknown, TResult = unknown> = (
205
+ ctx: FunctionContext<TEvent>
206
+ ) => Promise<TResult>;
207
+
208
+ interface IronflowFunction<TEvent = unknown, TResult = unknown> {
209
+ config: FunctionConfig;
210
+ handler: FunctionHandler<TEvent, TResult>;
211
+ }
212
+ ```
213
+
214
+ Usage (typically via `@ironflow/node`'s `createFunction()`):
215
+
216
+ ```typescript
217
+ import { createFunction } from '@ironflow/node';
218
+
219
+ const myWorkflow = createFunction({
220
+ id: 'process-order',
221
+ triggers: [{ event: 'order.placed' }],
222
+ retry: { maxAttempts: 5 },
223
+ concurrency: { limit: 10, key: 'event.data.customerId' },
224
+ mode: 'pull',
225
+ secrets: ['STRIPE_KEY'],
226
+ stepTimeout: '30s',
227
+ }, async ({ event, step, logger, secrets }) => {
228
+ const charge = await step.run('charge', async () => {
229
+ return stripe.charges.create({ amount: event.data.amount });
230
+ });
231
+ return { chargeId: charge.id };
232
+ });
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Event Types
238
+
239
+ ### IronflowEvent
240
+
241
+ ```typescript
242
+ interface IronflowEvent<T = unknown> {
243
+ /** Unique event ID */
244
+ id: string;
245
+ /** Event name (e.g., "order.placed") */
246
+ name: string;
247
+ /** Event schema version */
248
+ version: number;
249
+ /** Event payload data */
250
+ data: T;
251
+ /** Event timestamp */
252
+ timestamp: Date;
253
+ /** Optional idempotency key for deduplication */
254
+ idempotencyKey?: string;
255
+ /** Event source (e.g., "webhook", "sdk", "api") */
256
+ source?: string;
257
+ /** Additional metadata */
258
+ metadata?: Record<string, unknown>;
259
+ }
260
+ ```
261
+
262
+ ### EventSource Constants
263
+
264
+ ```typescript
265
+ import { EventSource } from '@ironflow/core';
266
+
267
+ EventSource.API // "api"
268
+ EventSource.CRON // "cron"
269
+ EventSource.WEBHOOK // "webhook"
270
+ ```
271
+
272
+ ### EventFilter
273
+
274
+ Used with `step.waitForEvent()`.
275
+
276
+ ```typescript
277
+ interface EventFilter {
278
+ /** Event name to wait for */
279
+ event: string;
280
+ /** JSON path for matching (e.g., "data.orderId") */
281
+ match?: string;
282
+ /** Timeout duration (default: "7d") */
283
+ timeout?: Duration;
284
+ }
285
+ ```
286
+
287
+ ### EmitOptions and EmitResult
288
+
289
+ ```typescript
290
+ interface EmitOptions {
291
+ /** Event schema version (default 1) */
292
+ version?: number;
293
+ /** Optional deduplication key */
294
+ idempotencyKey?: string;
295
+ /** Optional metadata (headers, etc.) */
296
+ metadata?: Record<string, unknown>;
297
+ /** Namespace (default: "default") */
298
+ namespace?: string;
299
+ }
300
+
301
+ interface EmitResult {
302
+ /** IDs of runs created by this event */
303
+ runIds: string[];
304
+ /** ID of the stored event */
305
+ eventId: string;
306
+ }
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Step Types
312
+
313
+ ### StepClient
314
+
315
+ The durable step execution interface. All methods are memoized -- on retry, previously completed steps return their stored result without re-executing.
316
+
317
+ ```typescript
318
+ interface StepClient {
319
+ /**
320
+ * Execute a step with memoization.
321
+ * Use for any non-idempotent operation (API calls, payments, emails).
322
+ */
323
+ run<T>(name: string, fn: () => Promise<T>, options?: StepRunOptions): Promise<T>;
324
+
325
+ /**
326
+ * Durable sleep. Worker can restart; workflow resumes after duration.
327
+ * @param duration - "1h", "30m", "7d" or milliseconds as number
328
+ */
329
+ sleep(name: string, duration: Duration): Promise<void>;
330
+
331
+ /**
332
+ * Durable sleep until a specific time.
333
+ * @param until - Date object or ISO 8601 string
334
+ */
335
+ sleepUntil(name: string, until: Date | string): Promise<void>;
336
+
337
+ /**
338
+ * Wait for an external event. Used for human-in-the-loop and async callbacks.
339
+ */
340
+ waitForEvent<T = unknown>(name: string, filter: EventFilter): Promise<IronflowEvent<T>>;
341
+
342
+ /**
343
+ * Execute multiple branches in parallel.
344
+ * "failFast" (default): first failure cancels pending branches.
345
+ * "allSettled": all branches complete, errors in results.
346
+ */
347
+ parallel<T extends unknown[]>(
348
+ name: string,
349
+ branches: { [K in keyof T]: (step: StepClient) => Promise<T[K]> },
350
+ options?: ParallelOptions
351
+ ): Promise<T>;
352
+
353
+ /** allSettled overload -- results contain T[K] | Error */
354
+ parallel<T extends unknown[]>(
355
+ name: string,
356
+ branches: { [K in keyof T]: (step: StepClient) => Promise<T[K]> },
357
+ options: ParallelOptions & { onError: "allSettled" }
358
+ ): Promise<{ [K in keyof T]: T[K] | Error }>;
359
+
360
+ /**
361
+ * Map over items executing steps in parallel.
362
+ */
363
+ map<T, R>(
364
+ name: string,
365
+ items: T[],
366
+ fn: (item: T, step: StepClient, index: number) => Promise<R>,
367
+ options?: ParallelOptions
368
+ ): Promise<R[]>;
369
+
370
+ /**
371
+ * Register a compensation handler (Saga pattern).
372
+ * On failure, compensations run in reverse order.
373
+ */
374
+ compensate(stepName: string, fn: () => Promise<void>): void;
375
+
376
+ /**
377
+ * Invoke another function and wait for its result (durable).
378
+ * Target function must have no event triggers.
379
+ */
380
+ invoke<T = unknown>(
381
+ functionId: string,
382
+ input?: unknown,
383
+ options?: { timeout?: string }
384
+ ): Promise<T>;
385
+
386
+ /**
387
+ * Fire-and-forget invoke. Returns the child run ID immediately.
388
+ */
389
+ invokeAsync(functionId: string, input?: unknown): Promise<{ runId: string }>;
390
+
391
+ /**
392
+ * Publish to a developer pub/sub topic (durable, memoized).
393
+ * Does NOT trigger workflow functions -- use emit for that.
394
+ */
395
+ publish(topic: string, data: unknown): Promise<PublishResult>;
396
+ }
397
+ ```
398
+
399
+ ### StepRunOptions
400
+
401
+ ```typescript
402
+ interface StepRunOptions {
403
+ /** Timeout for this step ("30s", "5m", "1h"). Overrides function-level stepTimeout. */
404
+ timeout?: string;
405
+ }
406
+ ```
407
+
408
+ ### Duration
409
+
410
+ ```typescript
411
+ type Duration = string | number;
412
+ // String: "1s", "30s", "5m", "2h", "7d"
413
+ // Number: milliseconds
414
+ ```
415
+
416
+ ### ParallelOptions
417
+
418
+ ```typescript
419
+ interface ParallelOptions {
420
+ /** Maximum concurrent branches (default: unlimited) */
421
+ concurrency?: number;
422
+ /** Error handling: "failFast" (default) or "allSettled" */
423
+ onError?: "failFast" | "allSettled";
424
+ }
425
+ ```
426
+
427
+ ---
428
+
429
+ ## Run Types
430
+
431
+ ### RunStatus
432
+
433
+ ```typescript
434
+ type RunStatus = "pending" | "running" | "completed" | "failed" | "cancelled" | "paused";
435
+ ```
436
+
437
+ ### RunInfo
438
+
439
+ Minimal run context passed inside `FunctionContext`.
440
+
441
+ ```typescript
442
+ interface RunInfo {
443
+ id: string;
444
+ functionId: string;
445
+ attempt: number;
446
+ startedAt: Date;
447
+ }
448
+ ```
449
+
450
+ ### Run
451
+
452
+ Full run details returned by API queries.
453
+
454
+ ```typescript
455
+ interface Run {
456
+ id: string;
457
+ functionId: string;
458
+ eventId: string;
459
+ status: RunStatus;
460
+ attempt: number;
461
+ maxAttempts: number;
462
+ input?: unknown;
463
+ output?: unknown;
464
+ error?: { message: string; code?: string };
465
+ startedAt?: Date;
466
+ endedAt?: Date;
467
+ createdAt: Date;
468
+ updatedAt: Date;
469
+ }
470
+ ```
471
+
472
+ ### ListRunsOptions and ListRunsResult
473
+
474
+ ```typescript
475
+ interface ListRunsOptions {
476
+ functionId?: string;
477
+ status?: RunStatus;
478
+ limit?: number;
479
+ cursor?: string;
480
+ }
481
+
482
+ interface ListRunsResult {
483
+ runs: Run[];
484
+ nextCursor?: string;
485
+ totalCount: number;
486
+ }
487
+ ```
488
+
489
+ ### TriggerResult, TriggerSyncOptions, TriggerSyncResult
490
+
491
+ ```typescript
492
+ interface TriggerResult {
493
+ runIds: string[];
494
+ eventId: string;
495
+ }
496
+
497
+ interface TriggerSyncOptions {
498
+ /** Maximum wait time in ms (default: 30000) */
499
+ timeout?: number;
500
+ }
501
+
502
+ interface TriggerSyncResult {
503
+ runId: string;
504
+ functionId: string;
505
+ status: RunStatus;
506
+ output?: unknown;
507
+ error?: { message: string; code?: string };
508
+ durationMs: number;
509
+ }
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Subscription Types
515
+
516
+ ### SubscribeOptions
517
+
518
+ ```typescript
519
+ interface SubscribeOptions {
520
+ /** Number of historical events to replay (0 = no replay) */
521
+ replay?: number;
522
+ /** Include event metadata (timestamp, sequence) */
523
+ includeMetadata?: boolean;
524
+ /** CEL expression for content-based filtering */
525
+ filter?: string;
526
+ /** Namespace for the subscription (default: "default") */
527
+ namespace?: string;
528
+ /** Consumer group to join for load-balanced delivery */
529
+ consumerGroup?: string;
530
+ /** Acknowledgment mode for consumer group (default: "auto") */
531
+ ackMode?: AckMode;
532
+ /** Backpressure handling mode (default: "buffer") */
533
+ backpressure?: BackpressureMode;
534
+ }
535
+ ```
536
+
537
+ ### AckMode, BackpressureMode, AckType
538
+
539
+ ```typescript
540
+ type AckMode = "auto" | "manual";
541
+ type BackpressureMode = "drop" | "block" | "buffer";
542
+ type AckType = "ack" | "nak" | "term";
543
+ ```
544
+
545
+ ### SubscriptionEvent
546
+
547
+ ```typescript
548
+ interface SubscriptionEvent<T = unknown> {
549
+ /** Event topic (e.g., "system.run.abc123.updated") */
550
+ topic: string;
551
+ /** Event payload data */
552
+ data: T;
553
+ /** Event metadata (if includeMetadata was true) */
554
+ meta?: EventMetadata;
555
+ /** Event ID (for consumer group ack/nak/term) */
556
+ eventId?: string;
557
+ }
558
+ ```
559
+
560
+ ### EventMetadata
561
+
562
+ ```typescript
563
+ interface EventMetadata {
564
+ timestamp: string; // ISO 8601
565
+ sequence?: number; // Stream sequence number
566
+ }
567
+ ```
568
+
569
+ ### Subscription
570
+
571
+ ```typescript
572
+ interface Subscription {
573
+ id: string;
574
+ pattern: string;
575
+ connectionState: ConnectionState;
576
+ lastEvent?: SubscriptionEvent<unknown>;
577
+ unsubscribe(): void;
578
+ }
579
+ ```
580
+
581
+ ### AckableSubscription
582
+
583
+ Extends `Subscription` with manual acknowledgment methods for consumer groups.
584
+
585
+ ```typescript
586
+ interface AckableSubscription extends Subscription {
587
+ ack(eventId: string): Promise<void>;
588
+ nak(eventId: string, delay?: number): Promise<void>;
589
+ term(eventId: string): Promise<void>;
590
+ }
591
+ ```
592
+
593
+ ### AckHandle
594
+
595
+ ```typescript
596
+ interface AckHandle {
597
+ ack(): void;
598
+ nak(): void;
599
+ }
600
+ ```
601
+
602
+ ### ConnectionState
603
+
604
+ ```typescript
605
+ type ConnectionState = "connecting" | "connected" | "disconnected" | "reconnecting";
606
+ ```
607
+
608
+ ### SubscriptionCallbacks
609
+
610
+ ```typescript
611
+ interface SubscriptionCallbacks<T = unknown> {
612
+ onEvent?: (event: SubscriptionEvent<T>) => void;
613
+ onError?: (error: SubscriptionErrorInfo) => void;
614
+ onStateChange?: (state: ConnectionState) => void;
615
+ }
616
+ ```
617
+
618
+ ### SubscriptionErrorInfo
619
+
620
+ ```typescript
621
+ interface SubscriptionErrorInfo {
622
+ subscriptionId?: string;
623
+ code: string;
624
+ message: string;
625
+ retrying?: boolean;
626
+ }
627
+ ```
628
+
629
+ ### BufferConfig
630
+
631
+ ```typescript
632
+ interface BufferConfig {
633
+ size: number;
634
+ strategy: "drop-oldest" | "drop-newest" | "block";
635
+ }
636
+ ```
637
+
638
+ ### ConsumerGroupConfig and ConsumerGroup
639
+
640
+ ```typescript
641
+ interface ConsumerGroupConfig {
642
+ name: string;
643
+ pattern: string;
644
+ namespace?: string; // default: "default"
645
+ filterExpr?: string; // CEL expression
646
+ ackMode?: AckMode; // default: "auto"
647
+ backpressure?: BackpressureMode; // default: "buffer"
648
+ maxInflight?: number; // default: 100
649
+ maxRedeliveries?: number; // default: 3
650
+ redeliverDelayMs?: number; // default: 5000
651
+ metadata?: Record<string, unknown>;
652
+ }
653
+
654
+ interface ConsumerGroup {
655
+ id: string;
656
+ namespace: string;
657
+ name: string;
658
+ pattern: string;
659
+ filterExpr?: string;
660
+ ackMode: AckMode;
661
+ backpressure: BackpressureMode;
662
+ maxInflight: number;
663
+ maxRedeliveries: number;
664
+ redeliverDelayMs: number;
665
+ metadata?: Record<string, unknown>;
666
+ status: ConsumerGroupStatus;
667
+ memberCount: number;
668
+ createdAt: Date;
669
+ updatedAt: Date;
670
+ }
671
+
672
+ type ConsumerGroupStatus = "active" | "paused" | "deleted";
673
+ ```
674
+
675
+ ---
676
+
677
+ ## Entity Stream Types
678
+
679
+ Entity streams implement event sourcing per entity with optimistic concurrency.
680
+
681
+ ### AppendEventInput
682
+
683
+ ```typescript
684
+ interface AppendEventInput {
685
+ /** Event name (e.g., "order.created") */
686
+ name: string;
687
+ /** Event payload data */
688
+ data: Record<string, unknown>;
689
+ /** Entity type (e.g., "order", "user") */
690
+ entityType: string;
691
+ }
692
+ ```
693
+
694
+ ### AppendOptions
695
+
696
+ ```typescript
697
+ interface AppendOptions {
698
+ /** Expected entity version for optimistic concurrency control (-1 to skip) */
699
+ expectedVersion?: number;
700
+ /** Idempotency key to prevent duplicate appends */
701
+ idempotencyKey?: string;
702
+ /** Event schema version (default: 1) */
703
+ version?: number;
704
+ }
705
+ ```
706
+
707
+ ### AppendResult
708
+
709
+ ```typescript
710
+ interface AppendResult {
711
+ entityVersion: number;
712
+ eventId: string;
713
+ }
714
+ ```
715
+
716
+ ### ReadStreamOptions
717
+
718
+ ```typescript
719
+ interface ReadStreamOptions {
720
+ /** Start reading from this version (inclusive, default: 0) */
721
+ fromVersion?: number;
722
+ /** Maximum number of events to return (0 = all) */
723
+ limit?: number;
724
+ /** Read direction (default: "forward") */
725
+ direction?: "forward" | "backward";
726
+ }
727
+ ```
728
+
729
+ ### StreamEvent
730
+
731
+ ```typescript
732
+ interface StreamEvent {
733
+ id: string;
734
+ name: string;
735
+ data: Record<string, unknown>;
736
+ entityVersion: number;
737
+ version: number; // Schema version
738
+ timestamp: string; // ISO 8601
739
+ source?: string;
740
+ metadata?: Record<string, unknown>;
741
+ }
742
+ ```
743
+
744
+ ### StreamInfo
745
+
746
+ ```typescript
747
+ interface StreamInfo {
748
+ entityId: string;
749
+ entityType: string;
750
+ version: number;
751
+ eventCount: number;
752
+ createdAt: string;
753
+ updatedAt: string;
754
+ }
755
+ ```
756
+
757
+ ### EntitySubscribeOptions
758
+
759
+ ```typescript
760
+ interface EntitySubscribeOptions {
761
+ /** Entity type (e.g., "order") -- required to construct NATS subject pattern */
762
+ entityType: string;
763
+ onEvent: (event: StreamEvent) => void;
764
+ onError?: (error: Error) => void;
765
+ /** Number of historical events to replay from NATS stream (0 = live only) */
766
+ replay?: number;
767
+ }
768
+ ```
769
+
770
+ ---
771
+
772
+ ## Pub/Sub Types
773
+
774
+ Developer pub/sub for topic-based messaging. Unlike `emit()`, publishing to a topic does NOT trigger workflow functions.
775
+
776
+ ### PublishOptions
777
+
778
+ ```typescript
779
+ interface PublishOptions {
780
+ idempotencyKey?: string;
781
+ }
782
+ ```
783
+
784
+ ### PublishResult
785
+
786
+ ```typescript
787
+ interface PublishResult {
788
+ eventId: string;
789
+ sequence: number; // JetStream sequence number
790
+ }
791
+ ```
792
+
793
+ ### TopicInfo
794
+
795
+ ```typescript
796
+ interface TopicInfo {
797
+ name: string;
798
+ messageCount: number;
799
+ consumerCount: number;
800
+ firstMessageAt?: string;
801
+ lastMessageAt?: string;
802
+ }
803
+ ```
804
+
805
+ ### TopicStats
806
+
807
+ ```typescript
808
+ interface TopicStats {
809
+ name: string;
810
+ messageCount: number;
811
+ consumerCount: number;
812
+ lag: number;
813
+ firstSeq: number;
814
+ lastSeq: number;
815
+ }
816
+ ```
817
+
818
+ ---
819
+
820
+ ## KV Types
821
+
822
+ Key-value store backed by NATS JetStream KV.
823
+
824
+ ### KVBucketConfig
825
+
826
+ ```typescript
827
+ interface KVBucketConfig {
828
+ name: string;
829
+ description?: string;
830
+ ttlSeconds?: number; // 0 = no expiry
831
+ maxValueSize?: number; // bytes
832
+ maxBytes?: number; // total bucket size in bytes
833
+ history?: number; // historical values per key (default: 1)
834
+ }
835
+ ```
836
+
837
+ ### KVBucketInfo
838
+
839
+ ```typescript
840
+ interface KVBucketInfo {
841
+ name: string;
842
+ description?: string;
843
+ ttl_seconds?: number;
844
+ values: number;
845
+ bytes: number;
846
+ history: number;
847
+ created_at: string;
848
+ }
849
+ ```
850
+
851
+ ### KVEntry
852
+
853
+ ```typescript
854
+ interface KVEntry {
855
+ key: string;
856
+ value: unknown; // raw bytes as base64 or string
857
+ revision: number;
858
+ created_at: string;
859
+ operation: string; // "put" or "delete"
860
+ }
861
+ ```
862
+
863
+ ### KVPutResult
864
+
865
+ ```typescript
866
+ interface KVPutResult {
867
+ revision: number;
868
+ }
869
+ ```
870
+
871
+ ### KVListKeysResult
872
+
873
+ ```typescript
874
+ interface KVListKeysResult {
875
+ keys: string[];
876
+ count: number;
877
+ }
878
+ ```
879
+
880
+ ### KVListBucketsResult
881
+
882
+ ```typescript
883
+ interface KVListBucketsResult {
884
+ buckets: KVBucketInfo[];
885
+ count: number;
886
+ }
887
+ ```
888
+
889
+ ### KVWatchEvent
890
+
891
+ ```typescript
892
+ interface KVWatchEvent {
893
+ type: "kv_update";
894
+ key: string;
895
+ value: string;
896
+ revision: number;
897
+ operation: "put" | "delete";
898
+ bucket: string;
899
+ }
900
+ ```
901
+
902
+ ### KVWatchCallbacks
903
+
904
+ ```typescript
905
+ interface KVWatchCallbacks {
906
+ onUpdate: (event: KVWatchEvent) => void;
907
+ onError?: (error: Error) => void;
908
+ onClose?: () => void;
909
+ }
910
+ ```
911
+
912
+ ### KVWatchOptions
913
+
914
+ ```typescript
915
+ interface KVWatchOptions {
916
+ /** Key pattern to watch (e.g., "user.*", "session.>"). Empty = all keys. */
917
+ key?: string;
918
+ }
919
+ ```
920
+
921
+ ### KVWatcher
922
+
923
+ ```typescript
924
+ interface KVWatcher {
925
+ stop: () => void;
926
+ }
927
+ ```
928
+
929
+ ---
930
+
931
+ ## Config Types
932
+
933
+ Environment-scoped configuration management built on the KV store.
934
+
935
+ ### ConfigResponse
936
+
937
+ ```typescript
938
+ interface ConfigResponse {
939
+ name: string;
940
+ data: Record<string, unknown>;
941
+ revision: number;
942
+ updatedAt: string;
943
+ }
944
+ ```
945
+
946
+ ### ConfigEntry
947
+
948
+ Summary (without full data), used in list responses.
949
+
950
+ ```typescript
951
+ interface ConfigEntry {
952
+ name: string;
953
+ revision: number;
954
+ updatedAt: string;
955
+ }
956
+ ```
957
+
958
+ ### ConfigSetResult
959
+
960
+ ```typescript
961
+ interface ConfigSetResult {
962
+ name: string;
963
+ revision: number;
964
+ }
965
+ ```
966
+
967
+ ### ConfigWatchCallbacks
968
+
969
+ ```typescript
970
+ interface ConfigWatchCallbacks {
971
+ onEvent: (config: ConfigResponse) => void;
972
+ onError?: (error: Error) => void;
973
+ }
974
+ ```
975
+
976
+ ---
977
+
978
+ ## Auth Types
979
+
980
+ Types for API key, organization, role, and policy management.
981
+
982
+ ### API Keys
983
+
984
+ ```typescript
985
+ interface APIKey {
986
+ id: string;
987
+ name: string;
988
+ key_prefix: string;
989
+ role_ids?: string[];
990
+ created_at: string;
991
+ expires_at?: string;
992
+ last_used_at?: string;
993
+ }
994
+
995
+ interface APIKeyWithSecret extends APIKey {
996
+ /** Full API key -- only returned on creation */
997
+ key: string;
998
+ }
999
+
1000
+ interface CreateAPIKeyInput {
1001
+ name: string;
1002
+ env_id?: string;
1003
+ role_ids?: string[];
1004
+ expires_in?: string;
1005
+ }
1006
+ ```
1007
+
1008
+ ### Organizations
1009
+
1010
+ ```typescript
1011
+ interface Organization {
1012
+ id: string;
1013
+ name: string;
1014
+ created_at: string;
1015
+ updated_at: string;
1016
+ }
1017
+
1018
+ interface CreateOrgInput {
1019
+ name: string;
1020
+ }
1021
+
1022
+ interface UpdateOrgInput {
1023
+ name?: string;
1024
+ }
1025
+ ```
1026
+
1027
+ ### Roles
1028
+
1029
+ ```typescript
1030
+ interface Role {
1031
+ id: string;
1032
+ org_id: string;
1033
+ name: string;
1034
+ is_default: boolean;
1035
+ created_at: string;
1036
+ }
1037
+
1038
+ interface CreateRoleInput {
1039
+ name: string;
1040
+ org_id: string;
1041
+ }
1042
+
1043
+ interface UpdateRoleInput {
1044
+ name?: string;
1045
+ }
1046
+ ```
1047
+
1048
+ ### Policies
1049
+
1050
+ ```typescript
1051
+ interface Policy {
1052
+ id: string;
1053
+ org_id: string;
1054
+ name: string;
1055
+ effect: "allow" | "deny";
1056
+ actions: string;
1057
+ resources: string;
1058
+ condition?: string;
1059
+ created_at: string;
1060
+ updated_at: string;
1061
+ }
1062
+
1063
+ interface CreatePolicyInput {
1064
+ name: string;
1065
+ effect: "allow" | "deny";
1066
+ actions: string;
1067
+ resources: string;
1068
+ condition?: string;
1069
+ org_id: string;
1070
+ }
1071
+
1072
+ interface UpdatePolicyInput {
1073
+ name?: string;
1074
+ effect?: "allow" | "deny";
1075
+ actions?: string;
1076
+ resources?: string;
1077
+ condition?: string;
1078
+ }
1079
+ ```
1080
+
1081
+ ---
1082
+
1083
+ ## Audit Types
1084
+
1085
+ Audit trail for function execution recording (enterprise feature).
1086
+
1087
+ ```typescript
1088
+ interface AuditEvent {
1089
+ id: string;
1090
+ runId: string;
1091
+ functionId: string;
1092
+ stepId?: string;
1093
+ eventType: string;
1094
+ payload: Record<string, unknown>;
1095
+ metadata?: Record<string, string>;
1096
+ createdAt: string;
1097
+ }
1098
+
1099
+ interface GetAuditTrailOptions {
1100
+ eventType?: string;
1101
+ fromTimestamp?: string;
1102
+ toTimestamp?: string;
1103
+ limit?: number;
1104
+ cursor?: string;
1105
+ }
1106
+
1107
+ interface AuditTrailResult {
1108
+ events: AuditEvent[];
1109
+ totalCount: number;
1110
+ nextCursor?: string;
1111
+ }
1112
+ ```
1113
+
1114
+ ---
1115
+
1116
+ ## Webhook Types
1117
+
1118
+ Types for defining webhook sources that transform inbound HTTP requests into Ironflow events.
1119
+
1120
+ ```typescript
1121
+ interface WebhookRequest {
1122
+ body: string;
1123
+ headers: Record<string, string>;
1124
+ }
1125
+
1126
+ interface WebhookEvent {
1127
+ name: string;
1128
+ data: unknown;
1129
+ idempotencyKey?: string;
1130
+ }
1131
+
1132
+ interface WebhookConfig {
1133
+ id: string;
1134
+ /** Verify the webhook signature. Return the parsed payload or throw. */
1135
+ verify: (req: WebhookRequest) => unknown | Promise<unknown>;
1136
+ /** Transform the verified payload into an Ironflow event. */
1137
+ transform: (payload: unknown) => WebhookEvent | Promise<WebhookEvent>;
1138
+ }
1139
+
1140
+ interface IronflowWebhook {
1141
+ config: WebhookConfig;
1142
+ }
11
1143
  ```
12
1144
 
13
- ## Quick Start
1145
+ ---
1146
+
1147
+ ## Projection Types
14
1148
 
15
- ### Types
1149
+ Projections build read models from event streams.
1150
+
1151
+ ### ProjectionMode and ProjectionStatus
16
1152
 
17
1153
  ```typescript
18
- import type {
19
- // IDs (branded types)
20
- RunId, FunctionId, StepId, EventId, JobId, WorkerId,
1154
+ type ProjectionMode = "managed" | "external";
1155
+ // "managed": pure reducer, state stored by Ironflow
1156
+ // "external": side-effect handler, you manage storage
21
1157
 
22
- // Functions & execution
23
- FunctionConfig, FunctionContext, FunctionHandler, IronflowFunction,
24
- Trigger, RetryConfig, ConcurrencyConfig,
1158
+ type ProjectionStatus = "active" | "rebuilding" | "paused" | "error";
1159
+ ```
1160
+
1161
+ ### ProjectionConfig
1162
+
1163
+ ```typescript
1164
+ interface ProjectionConfig<TState = unknown, TEvent = unknown> {
1165
+ /** Unique projection name */
1166
+ name: string;
1167
+ /** Event names to subscribe to (supports wildcards like "order.*") */
1168
+ events: string[];
1169
+ /** Execution mode -- auto-detected from initialState if omitted */
1170
+ mode?: ProjectionMode;
1171
+ /** Handler function */
1172
+ handler: ManagedProjectionHandler<TState, TEvent> | ExternalProjectionHandler<TEvent>;
1173
+ /** Initial state factory (required for managed, absent for external) */
1174
+ initialState?: () => TState;
1175
+ /** JSONPath for partition key extraction (e.g., "$.data.customerId") */
1176
+ partitionKey?: string;
1177
+ /** Max retries per event (default 3) */
1178
+ maxRetries?: number;
1179
+ /** Batch size for polling (default 100) */
1180
+ batchSize?: number;
1181
+ }
1182
+ ```
25
1183
 
26
- // Events & runs
27
- IronflowEvent, Run, RunStatus, EmitOptions, ListRunsOptions,
1184
+ ### ProjectionContext
1185
+
1186
+ ```typescript
1187
+ interface ProjectionContext {
1188
+ event: { id: string; name: string; seq: number; timestamp: Date };
1189
+ projection: { name: string; version: number };
1190
+ logger: Logger;
1191
+ }
1192
+ ```
28
1193
 
29
- // Steps
30
- StepClient, Duration, ParallelOptions,
1194
+ ### Handlers
31
1195
 
32
- // Subscriptions
33
- Subscription, SubscribeOptions, AckableSubscription,
34
- ConsumerGroup, ConsumerGroupConfig,
1196
+ ```typescript
1197
+ /** Managed: pure reducer. Returns new state. */
1198
+ type ManagedProjectionHandler<TState = unknown, TEvent = unknown> = (
1199
+ state: TState,
1200
+ event: TEvent & { name: string; data: unknown },
1201
+ ctx: ProjectionContext
1202
+ ) => TState;
35
1203
 
36
- // Entity streams (event sourcing)
37
- AppendEventInput, AppendOptions, AppendResult,
38
- ReadStreamOptions, StreamEvent, StreamInfo,
1204
+ /** External: side effects. Return void or Promise<void>. */
1205
+ type ExternalProjectionHandler<TEvent = unknown> = (
1206
+ event: TEvent & { name: string; data: unknown },
1207
+ ctx: ProjectionContext
1208
+ ) => void | Promise<void>;
1209
+ ```
39
1210
 
40
- // Projections
41
- ProjectionConfig, ProjectionContext, ProjectionStatus,
42
- ManagedProjectionHandler, ExternalProjectionHandler,
1211
+ ### IronflowProjection
43
1212
 
44
- // KV store
45
- KVBucketConfig, KVBucketInfo, KVEntry, KVPutResult,
1213
+ ```typescript
1214
+ interface IronflowProjection<TState = unknown, TEvent = unknown> {
1215
+ config: ProjectionConfig<TState, TEvent>;
1216
+ }
1217
+ ```
46
1218
 
47
- // Config management
48
- ConfigResponse, ConfigEntry, ConfigSetResult,
1219
+ ### ProjectionStatusInfo
49
1220
 
50
- // Logger
51
- Logger, LogLevel,
52
- } from '@ironflow/core';
1221
+ ```typescript
1222
+ interface ProjectionStatusInfo {
1223
+ name: string;
1224
+ status: ProjectionStatus;
1225
+ mode: ProjectionMode;
1226
+ lastEventSeq: number;
1227
+ lag: number;
1228
+ errorMessage?: string;
1229
+ updatedAt: Date;
1230
+ }
1231
+ ```
1232
+
1233
+ ### ProjectionStateResult
1234
+
1235
+ ```typescript
1236
+ interface ProjectionStateResult<TState = unknown> {
1237
+ name: string;
1238
+ partition: string;
1239
+ state: TState;
1240
+ lastEventId: string;
1241
+ lastEventTime: Date;
1242
+ version: number;
1243
+ mode: ProjectionMode;
1244
+ }
1245
+ ```
1246
+
1247
+ ### GetProjectionOptions and RebuildProjectionOptions
1248
+
1249
+ ```typescript
1250
+ interface GetProjectionOptions {
1251
+ partition?: string;
1252
+ }
1253
+
1254
+ interface RebuildProjectionOptions {
1255
+ partition?: string;
1256
+ fromEventId?: string;
1257
+ dryRun?: boolean;
1258
+ }
1259
+ ```
1260
+
1261
+ ### ProjectionSubscriptionCallbacks
1262
+
1263
+ ```typescript
1264
+ interface ProjectionSubscriptionCallbacks<TState = unknown> {
1265
+ onUpdate: (state: TState, event: { id: string; name: string }) => void;
1266
+ onError?: (error: Error) => void;
1267
+ }
1268
+ ```
1269
+
1270
+ Usage example (via `@ironflow/node`):
1271
+
1272
+ ```typescript
1273
+ import { createProjection } from '@ironflow/node';
1274
+
1275
+ const orderStats = createProjection({
1276
+ name: 'order-stats',
1277
+ events: ['order.placed', 'order.cancelled'],
1278
+ initialState: () => ({ total: 0, cancelled: 0 }),
1279
+ handler: (state, event) => {
1280
+ if (event.name === 'order.placed') return { ...state, total: state.total + 1 };
1281
+ if (event.name === 'order.cancelled') return { ...state, cancelled: state.cancelled + 1 };
1282
+ return state;
1283
+ },
1284
+ });
53
1285
  ```
54
1286
 
55
- ### Schemas (Zod)
1287
+ ---
1288
+
1289
+ ## Error Classes
56
1290
 
57
- Runtime validation schemas for all API request/response types:
1291
+ All errors extend `IronflowError`. Each has a `code` string and a `retryable` boolean.
58
1292
 
59
1293
  ```typescript
60
1294
  import {
61
- RunStatusSchema,
62
- PushRequestSchema,
63
- TriggerResponseSchema,
64
- RunResponseSchema,
65
- ListRunsResponseSchema,
66
- JobAssignmentSchema,
67
- WSServerMessageSchema,
68
- parseAndValidate,
69
- validate,
1295
+ IronflowError, ConnectionError, SubscriptionError, TimeoutError,
1296
+ ValidationError, SchemaValidationError, SignatureError,
1297
+ FunctionNotFoundError, RunNotFoundError, StepError, NonRetryableError,
1298
+ NotConfiguredError, InvokeError, InvokeTimeoutError, StepTimeoutError,
1299
+ UnauthenticatedError, EnterpriseRequiredError, UnauthorizedError,
1300
+ isRetryable, isIronflowError, toError,
1301
+ } from '@ironflow/core';
1302
+ ```
1303
+
1304
+ ### IronflowError (base class)
1305
+
1306
+ ```typescript
1307
+ class IronflowError extends Error {
1308
+ readonly code: string;
1309
+ readonly retryable: boolean;
1310
+ readonly details?: Record<string, unknown>;
1311
+
1312
+ constructor(message: string, options?: {
1313
+ code?: string; // default: "UNKNOWN_ERROR"
1314
+ retryable?: boolean; // default: false
1315
+ details?: Record<string, unknown>;
1316
+ cause?: Error;
1317
+ });
1318
+ }
1319
+ ```
1320
+
1321
+ ### Error Reference Table
1322
+
1323
+ | Class | Code | Retryable | When Thrown |
1324
+ |---|---|---|---|
1325
+ | `ConnectionError` | `CONNECTION_LOST` | true | WebSocket/HTTP connection lost |
1326
+ | `SubscriptionError` | `SUBSCRIPTION_ERROR` | true | Subscription setup or delivery failure |
1327
+ | `TimeoutError` | `TIMEOUT` | true | HTTP request or sync trigger timeout |
1328
+ | `ValidationError` | `VALIDATION_ERROR` | false | Invalid input data |
1329
+ | `SchemaValidationError` | `VALIDATION_ERROR` | false | Zod schema validation failure |
1330
+ | `SignatureError` | `SIGNATURE_INVALID` | false | Invalid webhook signature |
1331
+ | `FunctionNotFoundError` | `FUNCTION_NOT_FOUND` | false | Function ID not in registry |
1332
+ | `RunNotFoundError` | `RUN_NOT_FOUND` | false | Run ID not found in store |
1333
+ | `StepError` | `STEP_FAILED` | true | Step execution failure (has `stepId`, `stepName`) |
1334
+ | `NonRetryableError` | `NON_RETRYABLE` | false | Permanent failure, skip retries |
1335
+ | `NotConfiguredError` | `NOT_CONFIGURED` | false | Client used before `configure()` |
1336
+ | `InvokeError` | `INVOKE_FAILED` | false | `step.invoke()` target failed (has `functionId`, `childRunId`) |
1337
+ | `InvokeTimeoutError` | `INVOKE_FAILED` | false | `step.invoke()` timed out (has `timeoutMs`) |
1338
+ | `StepTimeoutError` | `STEP_TIMEOUT` | true | `step.run()` exceeded its timeout (has `stepName`, `timeout`) |
1339
+ | `UnauthenticatedError` | `UNAUTHENTICATED` | false | No/invalid API key (HTTP 401) |
1340
+ | `EnterpriseRequiredError` | `ENTERPRISE_REQUIRED` | false | Enterprise license needed (HTTP 402) |
1341
+ | `UnauthorizedError` | `UNAUTHORIZED` | false | Insufficient permissions (HTTP 403) |
1342
+
1343
+ ### Utility Functions
1344
+
1345
+ ```typescript
1346
+ // Check if an error is retryable (also returns true for fetch TypeErrors)
1347
+ isRetryable(error: unknown): boolean
1348
+
1349
+ // Type guard for IronflowError
1350
+ isIronflowError(error: unknown): error is IronflowError
1351
+
1352
+ // Normalize any thrown value to an Error instance
1353
+ toError(error: unknown): Error
1354
+ ```
1355
+
1356
+ Usage:
1357
+
1358
+ ```typescript
1359
+ try {
1360
+ await client.trigger('order.placed', { amount: 100 });
1361
+ } catch (err) {
1362
+ if (isRetryable(err)) {
1363
+ // Safe to retry
1364
+ }
1365
+ if (err instanceof FunctionNotFoundError) {
1366
+ console.error(`Function ${err.functionId} not registered`);
1367
+ }
1368
+ }
1369
+ ```
1370
+
1371
+ ---
1372
+
1373
+ ## Schemas
1374
+
1375
+ Zod schemas for runtime validation of API responses, WebSocket messages, and webhook payloads. All schemas are exported from `@ironflow/core` or the `@ironflow/core/schemas` sub-path.
1376
+
1377
+ ### Validation Helpers
1378
+
1379
+ ```typescript
1380
+ import { parseAndValidate, validate, RunResponseSchema } from '@ironflow/core';
1381
+
1382
+ // Parse JSON string and validate against schema
1383
+ // Throws SchemaValidationError on failure
1384
+ const run = parseAndValidate(RunResponseSchema, jsonString, 'GetRun response');
1385
+
1386
+ // Validate already-parsed data against schema
1387
+ // Throws SchemaValidationError on failure
1388
+ const run = validate(RunResponseSchema, parsedData, 'GetRun response');
1389
+ ```
1390
+
1391
+ ### Available Schemas
1392
+
1393
+ **Run & Status:**
1394
+ - `RunStatusSchema` -- `z.enum(["pending", "running", "completed", "failed", "cancelled", "paused"])`
1395
+
1396
+ **Push Request (serve.ts):**
1397
+ - `PushRequestSchema` -- Full push mode request from engine to SDK
1398
+ - `PushRequestEventSchema` -- Event portion of push request
1399
+ - `CompletedStepSchema` -- Memoized step from previous execution
1400
+ - `ResumeContextSchema` -- Resume context for sleep/waitForEvent/invoke
1401
+
1402
+ **API Responses:**
1403
+ - `TriggerResponseSchema` -- `{ runIds?, eventId }`
1404
+ - `TriggerSyncResultItemSchema` -- Individual sync trigger result
1405
+ - `TriggerSyncResponseSchema` -- `{ results?, eventId }`
1406
+ - `RunResponseSchema` -- Full run details
1407
+ - `ListRunsResponseSchema` -- `{ runs?, nextCursor?, totalCount? }`
1408
+ - `RegisterFunctionResponseSchema` -- `{ created? }`
1409
+ - `HealthResponseSchema` -- `{ status }`
1410
+ - `ErrorResponseSchema` -- `{ code?, message? }`
1411
+ - `EmptyResponseSchema` -- `{}`
1412
+
1413
+ **Consumer Groups:**
1414
+ - `AckModeSchema` -- `z.enum(["ACK_MODE_AUTO", "ACK_MODE_MANUAL", "ACK_MODE_UNSPECIFIED"])`
1415
+ - `BackpressureModeSchema`
1416
+ - `ConsumerGroupStatusSchema`
1417
+ - `ConsumerGroupResponseSchema`
1418
+ - `ListConsumerGroupsResponseSchema`
1419
+
1420
+ **Worker Job Assignment:**
1421
+ - `JobAssignmentSchema` -- Full job assignment for pull-mode workers
1422
+ - `JobEventSchema`, `JobCompletedStepSchema`, `JobContextSchema`
1423
+
1424
+ **WebSocket Messages:**
1425
+ - `WSServerMessageSchema` -- Discriminated union of all server messages
1426
+ - `WSEventMessageSchema` -- Event delivery
1427
+ - `WSSubscriptionResultSchema` -- Subscribe confirmation
1428
+ - `WSSubscriptionErrorSchema` -- Subscription error
1429
+ - `WSErrorSchema` -- General error
1430
+ - `EventMetadataSchema`
1431
+
1432
+ **Audit:**
1433
+ - `AuditEventSchema`
1434
+
1435
+ ### Inferred Types
1436
+
1437
+ ```typescript
1438
+ import type {
1439
+ ValidatedPushRequest,
1440
+ ValidatedRunResponse,
1441
+ ValidatedJobAssignment,
1442
+ ValidatedWSServerMessage,
70
1443
  } from '@ironflow/core';
1444
+ ```
1445
+
1446
+ These are `z.infer<>` types derived from the corresponding schemas.
1447
+
1448
+ ---
1449
+
1450
+ ## Protocol Types
1451
+
1452
+ Low-level protocol types for SDK authors building custom transports. Import from `@ironflow/core` or `@ironflow/core/protocol`.
1453
+
1454
+ ### Push Mode (HTTP)
1455
+
1456
+ ```typescript
1457
+ interface PushRequest {
1458
+ run_id: string;
1459
+ function_id: string;
1460
+ attempt: number;
1461
+ event: {
1462
+ id: string; name: string; data: unknown; timestamp: string;
1463
+ version?: number; idempotency_key?: string; source?: string;
1464
+ metadata?: Record<string, unknown>;
1465
+ };
1466
+ steps: CompletedStep[];
1467
+ resume?: ResumeContext;
1468
+ }
1469
+
1470
+ interface PushResponse {
1471
+ status: "completed" | "yielded" | "failed";
1472
+ steps: StepResult[];
1473
+ result?: unknown;
1474
+ error?: {
1475
+ message: string; code?: string; step_id?: string;
1476
+ retryable: boolean; stack?: string;
1477
+ };
1478
+ yield?: YieldInfo;
1479
+ }
1480
+
1481
+ interface CompletedStep {
1482
+ id: string; name: string;
1483
+ status: "completed" | "failed" | "timed_out";
1484
+ output?: unknown; error?: string;
1485
+ }
1486
+
1487
+ interface ResumeContext {
1488
+ step_id: string;
1489
+ type: "sleep" | "wait_for_event" | "invoke_function" | "invoke_function_async";
1490
+ data?: unknown;
1491
+ }
1492
+
1493
+ interface StepResult {
1494
+ id: string; name: string;
1495
+ type: "invoke" | "sleep" | "wait_for_event" | "compensate";
1496
+ status: "completed" | "failed";
1497
+ started_at: string; ended_at?: string; duration_ms?: number;
1498
+ output?: unknown;
1499
+ error?: { message: string; retryable: boolean; stack?: string };
1500
+ compensation_for?: string;
1501
+ }
1502
+ ```
1503
+
1504
+ ### Yield Types
1505
+
1506
+ ```typescript
1507
+ type YieldInfo = SleepYield | WaitEventYield | InvokeFunctionYield | InvokeFunctionAsyncYield;
1508
+
1509
+ interface SleepYield { step_id: string; type: "sleep"; until: string; }
1510
+ interface WaitEventYield { step_id: string; type: "wait_for_event"; event_filter: { event: string; match?: string; timeout?: string; }; }
1511
+ interface InvokeFunctionYield { step_id: string; type: "invoke_function"; function_id: string; input?: unknown; invoke_timeout_ms?: number; }
1512
+ interface InvokeFunctionAsyncYield { step_id: string; type: "invoke_function_async"; function_id: string; input?: unknown; }
1513
+ ```
1514
+
1515
+ ### WebSocket Protocol
1516
+
1517
+ **Client to server:**
1518
+
1519
+ ```typescript
1520
+ interface WSSubscribeRequest {
1521
+ type: "subscribe";
1522
+ subscription: {
1523
+ pattern: string;
1524
+ options?: {
1525
+ replay?: number; includeMetadata?: boolean; filter?: string;
1526
+ consumerGroup?: string; ackMode?: AckMode;
1527
+ backpressure?: BackpressureMode; namespace?: string;
1528
+ };
1529
+ };
1530
+ }
71
1531
 
72
- const status = RunStatusSchema.parse(rawStatus);
73
- const run = parseAndValidate(rawData, RunResponseSchema);
1532
+ interface WSUnsubscribeRequest { type: "unsubscribe"; subscriptionId: string; }
1533
+ interface WSAckRequest { type: "ack"; eventId: string; ackType: AckType; redeliverDelay?: number; }
1534
+
1535
+ type WSClientMessage = WSSubscribeRequest | WSUnsubscribeRequest | WSAckRequest;
1536
+ ```
1537
+
1538
+ **Server to client:**
1539
+
1540
+ ```typescript
1541
+ interface WSSubscriptionResult {
1542
+ type: "subscription_result";
1543
+ results: Array<{ pattern: string; status: "ok" | "error"; subscriptionId?: string; code?: string; message?: string; }>;
1544
+ }
1545
+ interface WSEventMessage { type: "event"; subscriptionId: string; topic: string; data: unknown; meta?: EventMetadata; eventId?: string; }
1546
+ interface WSSubscriptionError { type: "subscription_error"; subscriptionId: string; code: string; message: string; retrying: boolean; }
1547
+ interface WSError { type: "error"; code: string; message: string; }
1548
+
1549
+ type WSServerMessage = WSSubscriptionResult | WSEventMessage | WSSubscriptionError | WSError;
1550
+ ```
1551
+
1552
+ ### Retry Types
1553
+
1554
+ ```typescript
1555
+ interface RetryEvent { attempt: number; maxAttempts: number; error: Error; delayMs: number; }
1556
+ interface RetryInfo { eventId: string; attempt: number; maxAttempts: number; delayMs?: number; }
1557
+
1558
+ interface ClientRetryConfig {
1559
+ maxAttempts?: number; // default: 3
1560
+ initialDelayMs?: number; // default: 100
1561
+ maxDelayMs?: number; // default: 10000
1562
+ backoffMultiplier?: number; // default: 2.0
1563
+ connectionRetryDelayMs?: number; // default: 2000
1564
+ onRetry?: (event: RetryEvent) => void;
1565
+ }
74
1566
  ```
75
1567
 
76
- ### Constants
1568
+ ---
1569
+
1570
+ ## Constants
77
1571
 
78
1572
  ```typescript
79
1573
  import {
80
- DEFAULT_SERVER_URL,
1574
+ DEFAULT_PORT, // 9123
1575
+ DEFAULT_HOST, // "localhost"
1576
+ DEFAULT_SERVER_URL, // "http://localhost:9123"
1577
+ DEFAULT_WS_URL, // "ws://localhost:9123/ws"
1578
+ DEFAULT_ENVIRONMENT, // "default"
1579
+
1580
+ DEFAULT_TIMEOUTS,
1581
+ // { CLIENT: 30_000, FUNCTION: 600_000, TRIGGER_SYNC: 30_000 }
1582
+
1583
+ DEFAULT_RETRY,
1584
+ // { MAX_ATTEMPTS: 3, INITIAL_DELAY_MS: 1000, BACKOFF_FACTOR: 2.0, MAX_DELAY_MS: 300_000 }
1585
+
1586
+ DEFAULT_CLIENT_RETRY,
1587
+ // { MAX_ATTEMPTS: 3, INITIAL_DELAY_MS: 100, BACKOFF_MULTIPLIER: 2.0,
1588
+ // MAX_DELAY_MS: 10_000, CONNECTION_RETRY_DELAY_MS: 2_000 }
1589
+
1590
+ DEFAULT_WORKER,
1591
+ // { MAX_CONCURRENT_JOBS: 10, HEARTBEAT_INTERVAL_MS: 30_000, RECONNECT_DELAY_MS: 5_000 }
1592
+
1593
+ DEFAULT_RECONNECT,
1594
+ // { ENABLED: true, MAX_ATTEMPTS: 10, INITIAL_DELAY_MS: 1_000,
1595
+ // MAX_DELAY_MS: 30_000, MULTIPLIER: 2 }
1596
+
1597
+ ENV_VARS,
1598
+ // { SERVER_URL: "IRONFLOW_SERVER_URL", SIGNING_KEY: "IRONFLOW_SIGNING_KEY",
1599
+ // API_KEY: "IRONFLOW_API_KEY", LOG_LEVEL: "IRONFLOW_LOG_LEVEL" }
1600
+
1601
+ STEP_TYPES,
1602
+ // { INVOKE: "invoke", SLEEP: "sleep", WAIT_FOR_EVENT: "wait_for_event" }
1603
+
81
1604
  STEP_STATUS,
1605
+ // { COMPLETED: "completed", FAILED: "failed", WAITING: "waiting" }
1606
+
82
1607
  RUN_STATUS,
83
- ENV_VARS,
1608
+ // { PENDING: "pending", RUNNING: "running", COMPLETED: "completed",
1609
+ // FAILED: "failed", CANCELLED: "cancelled", PAUSED: "paused" }
1610
+
84
1611
  API_ENDPOINTS,
85
- getServerUrl,
86
- getWebSocketUrl,
1612
+ // ConnectRPC paths: TRIGGER, TRIGGER_SYNC, GET_RUN, LIST_RUNS, CANCEL_RUN,
1613
+ // RETRY_RUN, REGISTER_FUNCTION, HEALTH, EMIT, CREATE_CONSUMER_GROUP,
1614
+ // GET_CONSUMER_GROUP, LIST_CONSUMER_GROUPS, DELETE_CONSUMER_GROUP
1615
+
1616
+ TIMING,
1617
+ // { POLL_INTERVAL_MS: 1000, ERROR_RETRY_DELAY_MS: 5000,
1618
+ // RECONNECT_DELAY_MS: 1000, WS_CLOSE_NORMAL: 1000 }
1619
+
1620
+ ACK_TYPES,
1621
+ // { ACK: "ack", NAK: "nak", TERM: "term" }
1622
+
1623
+ ERROR_CODES,
1624
+ // FUNCTION_NOT_FOUND, VALIDATION_ERROR, SIGNATURE_INVALID, NETWORK_ERROR,
1625
+ // SERVER_ERROR, TIMEOUT_ERROR, CONNECTION_LOST, CONNECTION_REFUSED,
1626
+ // SUBSCRIPTION_ERROR, NOT_CONFIGURED
1627
+
1628
+ HEADERS,
1629
+ // { ENVIRONMENT: "X-Ironflow-Environment" }
1630
+
1631
+ WS_MESSAGE_TYPES,
1632
+ // { SUBSCRIBE, UNSUBSCRIBE, ACK, EVENT, SUBSCRIPTION_RESULT,
1633
+ // SUBSCRIPTION_ERROR, ERROR }
1634
+
1635
+ HTTP_HEADERS,
1636
+ // { CONTENT_TYPE_JSON: "application/json" }
1637
+
1638
+ JSON_HEADERS,
1639
+ // { "Content-Type": "application/json" }
1640
+
1641
+ getServerUrl, // () => string (reads IRONFLOW_SERVER_URL or returns default)
1642
+ getWebSocketUrl, // (serverUrl?) => string (converts http->ws, appends /ws)
87
1643
  } from '@ironflow/core';
88
1644
  ```
89
1645
 
90
- ### Error Classes
1646
+ ### Environment Variables
1647
+
1648
+ | Variable | Purpose |
1649
+ |---|---|
1650
+ | `IRONFLOW_SERVER_URL` | Server URL (default: `http://localhost:9123`) |
1651
+ | `IRONFLOW_SIGNING_KEY` | Webhook signature verification key |
1652
+ | `IRONFLOW_API_KEY` | API key for authenticated requests |
1653
+ | `IRONFLOW_LOG_LEVEL` | Log level: `debug`, `info`, `warn`, `error`, `silent` |
1654
+
1655
+ ---
1656
+
1657
+ ## Utilities
91
1658
 
92
1659
  ```typescript
93
1660
  import {
94
- IronflowError,
95
- ConnectionError,
96
- StepError,
97
- NonRetryableError,
98
- TimeoutError,
99
- ValidationError,
100
- FunctionNotFoundError,
101
- RunNotFoundError,
102
- isRetryable,
103
- isIronflowError,
104
- toError,
1661
+ parseDuration, calculateBackoff, sleep, createDeferred,
1662
+ generateId, safeJsonParse, isObject, deepMerge,
105
1663
  } from '@ironflow/core';
1664
+ ```
1665
+
1666
+ ### parseDuration
1667
+
1668
+ Convert a duration string to milliseconds.
1669
+
1670
+ ```typescript
1671
+ parseDuration('30s'); // 30000
1672
+ parseDuration('5m'); // 300000
1673
+ parseDuration('2h'); // 7200000
1674
+ parseDuration('7d'); // 604800000
1675
+ parseDuration('500ms'); // 500
1676
+ parseDuration(1000); // 1000 (passthrough)
1677
+ // Throws Error for invalid format
1678
+ ```
1679
+
1680
+ ### calculateBackoff
1681
+
1682
+ ```typescript
1683
+ calculateBackoff(
1684
+ attempt: number, // 1-based attempt number
1685
+ initialDelay: number, // initial delay in ms
1686
+ maxDelay: number, // maximum delay cap in ms
1687
+ multiplier?: number // default: 2
1688
+ ): number;
1689
+
1690
+ calculateBackoff(1, 1000, 30000); // 1000
1691
+ calculateBackoff(2, 1000, 30000); // 2000
1692
+ calculateBackoff(3, 1000, 30000); // 4000
1693
+ calculateBackoff(10, 1000, 30000); // 30000 (capped)
1694
+ ```
106
1695
 
107
- if (isRetryable(error)) {
108
- // Safe to retry
1696
+ ### sleep
1697
+
1698
+ ```typescript
1699
+ await sleep(1000); // sleep 1 second
1700
+ ```
1701
+
1702
+ ### createDeferred
1703
+
1704
+ Create a promise with externally accessible resolve/reject.
1705
+
1706
+ ```typescript
1707
+ interface Deferred<T> {
1708
+ promise: Promise<T>;
1709
+ resolve: (value: T) => void;
1710
+ reject: (error: Error) => void;
109
1711
  }
1712
+
1713
+ const deferred = createDeferred<string>();
1714
+ // later:
1715
+ deferred.resolve('done');
1716
+ // or:
1717
+ deferred.reject(new Error('failed'));
1718
+ // consumer:
1719
+ const result = await deferred.promise;
1720
+ ```
1721
+
1722
+ ### generateId
1723
+
1724
+ ```typescript
1725
+ const id = generateId(); // e.g., "m1abc23-x4y5z6"
1726
+ ```
1727
+
1728
+ ### safeJsonParse
1729
+
1730
+ Returns `undefined` on parse failure instead of throwing.
1731
+
1732
+ ```typescript
1733
+ safeJsonParse('{"a":1}'); // { a: 1 }
1734
+ safeJsonParse('invalid'); // undefined
1735
+ ```
1736
+
1737
+ ### isObject
1738
+
1739
+ Type guard for non-null, non-array objects.
1740
+
1741
+ ```typescript
1742
+ isObject({}); // true
1743
+ isObject(null); // false
1744
+ isObject([]); // false
1745
+ isObject('string'); // false
1746
+ ```
1747
+
1748
+ ### deepMerge
1749
+
1750
+ Recursively merge two objects. Source values overwrite target values; nested objects are merged.
1751
+
1752
+ ```typescript
1753
+ deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
1754
+ // { a: 1, b: { c: 2, d: 3 } }
110
1755
  ```
111
1756
 
112
1757
  ### Pattern Helpers
113
1758
 
114
- Pre-built NATS subscription patterns for common use cases:
1759
+ Pre-built subscription patterns using NATS-style wildcards (`*` = single token, `>` = one or more tokens at end).
115
1760
 
116
1761
  ```typescript
117
1762
  import { patterns } from '@ironflow/core';
118
1763
 
119
- patterns.allRuns(); // 'system.run.>'
120
- patterns.run(runId); // Run-specific events
121
- patterns.runLifecycle(runId); // Run lifecycle only (created, completed, failed)
122
- patterns.runSteps(runId); // Step events for a run
123
- patterns.allFunctions(); // 'system.function.>'
124
- patterns.function(functionId); // Function-specific events
125
- patterns.userEvent('order.*'); // User event patterns
126
- patterns.allUserEvents(); // All user events
1764
+ // System events
1765
+ patterns.allRuns(); // "system.run.>"
1766
+ patterns.run('run_abc'); // "system.run.run_abc.>"
1767
+ patterns.runLifecycle('run_abc');// "system.run.run_abc.*"
1768
+ patterns.runSteps('run_abc'); // "system.run.run_abc.step.>"
1769
+ patterns.allFunctions(); // "system.function.>"
1770
+ patterns.function('my-fn'); // "system.function.my-fn.>"
1771
+
1772
+ // User events
1773
+ patterns.userEvent('order.*'); // "events:order.*"
1774
+ patterns.allUserEvents(); // "events:>"
1775
+
1776
+ // Developer pub/sub topics
1777
+ patterns.topic('notifications'); // "topic:notifications"
1778
+ patterns.allTopics(); // "topic:>"
1779
+
1780
+ // Secrets
1781
+ patterns.allSecrets(); // "system.secret.*"
1782
+ patterns.secret('db-password'); // "system.secret.db-password.*"
1783
+ patterns.secretAction('updated');// "system.secret.*.updated"
127
1784
  ```
128
1785
 
129
- ### Event Versioning (Upcasters)
1786
+ ---
1787
+
1788
+ ## Upcasters
1789
+
1790
+ Upcasters transform event data between schema versions. They run SDK-side when reading events.
130
1791
 
131
- Migrate event data between schema versions:
1792
+ ### Low-Level: UpcasterRegistry
132
1793
 
133
1794
  ```typescript
134
- import { createUpcasterRegistry, defineEvent, createEventDefinitionRegistry } from '@ironflow/core';
1795
+ import { createUpcasterRegistry, type UpcasterFn } from '@ironflow/core';
1796
+
1797
+ type UpcasterFn = (data: unknown) => unknown;
135
1798
 
136
- // Low-level: register individual upcasters
137
1799
  const registry = createUpcasterRegistry();
138
- registry.register('order.placed', 1, 2, (data) => ({
1800
+
1801
+ // Register: eventName, fromVersion, toVersion, transform function
1802
+ registry.register('order.placed', 1, 2, (data: any) => ({
139
1803
  ...data,
140
1804
  currency: data.currency ?? 'USD',
141
1805
  }));
142
- const migrated = registry.upcast('order.placed', oldData, 1, 2);
1806
+ registry.register('order.placed', 2, 3, (data: any) => ({
1807
+ ...data,
1808
+ items: data.items ?? [],
1809
+ }));
1810
+
1811
+ // Upcast through the chain: v1 -> v2 -> v3
1812
+ const migrated = registry.upcast('order.placed', oldData, 1, 3);
1813
+
1814
+ // Get the latest registered version
1815
+ registry.getLatestVersion('order.placed'); // 3
1816
+ ```
1817
+
1818
+ The chain must be complete. If v2->v3 is missing, upcasting from v1->v3 throws.
143
1819
 
144
- // High-level: define events with auto-upcasting
145
- const OrderPlaced = defineEvent({
1820
+ ### High-Level: defineEvent and EventDefinitionRegistry
1821
+
1822
+ ```typescript
1823
+ import { defineEvent, createEventDefinitionRegistry } from '@ironflow/core';
1824
+ import type { EventDefinition, EventDefinitionOptions, EventDefinitionRegistry } from '@ironflow/core';
1825
+
1826
+ interface EventDefinitionOptions {
1827
+ name: string;
1828
+ version: number;
1829
+ upcast?: UpcasterFn; // transforms from version-1 to this version
1830
+ }
1831
+
1832
+ interface EventDefinition {
1833
+ name: string;
1834
+ version: number;
1835
+ upcast?: UpcasterFn;
1836
+ }
1837
+
1838
+ // Define event versions
1839
+ const OrderPlacedV2 = defineEvent({
146
1840
  name: 'order.placed',
147
1841
  version: 2,
148
- upcast: (data) => ({ ...data, currency: data.currency ?? 'USD' }),
1842
+ upcast: (data: any) => ({ ...data, currency: data.currency ?? 'USD' }),
1843
+ });
1844
+
1845
+ const OrderPlacedV3 = defineEvent({
1846
+ name: 'order.placed',
1847
+ version: 3,
1848
+ upcast: (data: any) => ({ ...data, items: data.items ?? [] }),
149
1849
  });
150
1850
 
1851
+ // Register all versions
151
1852
  const eventRegistry = createEventDefinitionRegistry();
152
- eventRegistry.register(OrderPlaced);
1853
+ eventRegistry.register(OrderPlacedV2);
1854
+ eventRegistry.register(OrderPlacedV3);
1855
+
1856
+ // Auto-upcast from any version to latest
1857
+ const latest = eventRegistry.upcastEvent('order.placed', oldData, 1);
1858
+
1859
+ // Query latest version
1860
+ eventRegistry.getLatestVersion('order.placed'); // 3
153
1861
  ```
154
1862
 
155
- ### Utilities
1863
+ ---
1864
+
1865
+ ## Logger
156
1866
 
157
1867
  ```typescript
158
- import {
159
- generateId,
160
- parseDuration,
161
- calculateBackoff,
162
- sleep,
163
- createDeferred,
164
- safeJsonParse,
165
- deepMerge,
166
- createLogger,
167
- createNoopLogger,
168
- } from '@ironflow/core';
1868
+ import { createLogger, createNoopLogger } from '@ironflow/core';
1869
+ import type { LogLevel, LoggerConfig, Logger } from '@ironflow/core';
1870
+
1871
+ type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
1872
+
1873
+ interface LoggerConfig {
1874
+ /** Minimum log level to output (default: "info", or IRONFLOW_LOG_LEVEL env var) */
1875
+ level?: LogLevel;
1876
+ /** Prefix for log messages (default: "[ironflow]") */
1877
+ prefix?: string;
1878
+ }
1879
+
1880
+ interface Logger {
1881
+ debug(message: string, data?: Record<string, unknown>): void;
1882
+ info(message: string, data?: Record<string, unknown>): void;
1883
+ warn(message: string, data?: Record<string, unknown>): void;
1884
+ error(message: string, data?: Record<string, unknown>): void;
1885
+ }
1886
+ ```
1887
+
1888
+ Usage:
1889
+
1890
+ ```typescript
1891
+ const logger = createLogger({ prefix: '[myapp]', level: 'debug' });
1892
+ logger.info('Processing order', { orderId: '123' });
1893
+ // Output: [myapp] Processing order {"orderId":"123"}
169
1894
 
170
- const runId = generateId('run'); // 'run_abc123...'
171
- const ms = parseDuration('5m'); // 300000
172
- const delay = calculateBackoff(3, 1000); // Exponential backoff
173
- const logger = createLogger({ prefix: '[myapp]' });
1895
+ // Silent logger for tests
1896
+ const noop = createNoopLogger();
174
1897
  ```
175
1898
 
176
- ## Documentation
1899
+ The default log level reads from `IRONFLOW_LOG_LEVEL` environment variable, falling back to `"info"`.
1900
+
1901
+ ---
1902
+
1903
+ ## SecretsClient
1904
+
1905
+ Read-only interface for accessing resolved secrets inside function handlers. Secrets are declared in `FunctionConfig.secrets` and resolved by the engine at execution time.
1906
+
1907
+ ```typescript
1908
+ interface SecretsClient {
1909
+ /** Get a secret value by name. Throws if not found. */
1910
+ get(name: string): string;
1911
+ /** Check if a secret exists. */
1912
+ has(name: string): boolean;
1913
+ }
1914
+ ```
1915
+
1916
+ Usage inside a function handler:
1917
+
1918
+ ```typescript
1919
+ const myFn = createFunction({
1920
+ id: 'charge-card',
1921
+ triggers: [{ event: 'order.placed' }],
1922
+ secrets: ['STRIPE_KEY'],
1923
+ }, async ({ secrets, step }) => {
1924
+ const stripeKey = secrets.get('STRIPE_KEY');
1925
+ // ...
1926
+ });
1927
+ ```
1928
+
1929
+ ---
1930
+
1931
+ ## Sub-Path Exports
1932
+
1933
+ The package provides additional entry points for selective imports:
1934
+
1935
+ | Path | What it exports |
1936
+ |---|---|
1937
+ | `@ironflow/core` | Everything (types, schemas, errors, constants, utils, protocol, patterns) |
1938
+ | `@ironflow/core/schemas` | Zod schemas and validation helpers only |
1939
+ | `@ironflow/core/protocol` | Protocol types and pattern helpers only |
1940
+ | `@ironflow/core/gen` | Generated protobuf/ConnectRPC code (requires optional deps) |
177
1941
 
178
- For the full API reference, see the [Core Package Documentation](https://ironflow.dev/docs/api-reference/js-sdk/core).
1942
+ ---
179
1943
 
180
1944
  ## License
181
1945