ai-workflows 2.1.3 → 2.4.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 (188) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +14 -1
  3. package/README.md +2 -0
  4. package/dist/barrier.d.ts +6 -0
  5. package/dist/barrier.d.ts.map +1 -1
  6. package/dist/barrier.js +45 -7
  7. package/dist/barrier.js.map +1 -1
  8. package/dist/cascade-context.d.ts.map +1 -1
  9. package/dist/cascade-context.js +25 -25
  10. package/dist/cascade-context.js.map +1 -1
  11. package/dist/cascade-executor.d.ts.map +1 -1
  12. package/dist/cascade-executor.js +1 -1
  13. package/dist/cascade-executor.js.map +1 -1
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/context.js +23 -7
  16. package/dist/context.js.map +1 -1
  17. package/dist/cron-parser.d.ts +65 -0
  18. package/dist/cron-parser.d.ts.map +1 -0
  19. package/dist/cron-parser.js +294 -0
  20. package/dist/cron-parser.js.map +1 -0
  21. package/dist/cron-scheduler.d.ts +117 -0
  22. package/dist/cron-scheduler.d.ts.map +1 -0
  23. package/dist/cron-scheduler.js +176 -0
  24. package/dist/cron-scheduler.js.map +1 -0
  25. package/dist/database-context.d.ts +184 -0
  26. package/dist/database-context.d.ts.map +1 -0
  27. package/dist/database-context.js +428 -0
  28. package/dist/database-context.js.map +1 -0
  29. package/dist/digital-objects-adapter.d.ts +159 -0
  30. package/dist/digital-objects-adapter.d.ts.map +1 -0
  31. package/dist/digital-objects-adapter.js +229 -0
  32. package/dist/digital-objects-adapter.js.map +1 -0
  33. package/dist/durable-execution-cloudflare.d.ts +427 -0
  34. package/dist/durable-execution-cloudflare.d.ts.map +1 -0
  35. package/dist/durable-execution-cloudflare.js +510 -0
  36. package/dist/durable-execution-cloudflare.js.map +1 -0
  37. package/dist/durable-execution.d.ts +482 -0
  38. package/dist/durable-execution.d.ts.map +1 -0
  39. package/dist/durable-execution.js +594 -0
  40. package/dist/durable-execution.js.map +1 -0
  41. package/dist/durable-workflow.d.ts +176 -0
  42. package/dist/durable-workflow.d.ts.map +1 -0
  43. package/dist/durable-workflow.js +552 -0
  44. package/dist/durable-workflow.js.map +1 -0
  45. package/dist/graph/topological-sort.d.ts.map +1 -1
  46. package/dist/graph/topological-sort.js +5 -5
  47. package/dist/graph/topological-sort.js.map +1 -1
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +15 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/logger.d.ts +101 -0
  53. package/dist/logger.d.ts.map +1 -0
  54. package/dist/logger.js +115 -0
  55. package/dist/logger.js.map +1 -0
  56. package/dist/on.d.ts.map +1 -1
  57. package/dist/on.js +3 -3
  58. package/dist/on.js.map +1 -1
  59. package/dist/runtime.d.ts +169 -0
  60. package/dist/runtime.d.ts.map +1 -0
  61. package/dist/runtime.js +275 -0
  62. package/dist/runtime.js.map +1 -0
  63. package/dist/send.d.ts.map +1 -1
  64. package/dist/send.js +4 -3
  65. package/dist/send.js.map +1 -1
  66. package/dist/telemetry.d.ts +150 -0
  67. package/dist/telemetry.d.ts.map +1 -0
  68. package/dist/telemetry.js +388 -0
  69. package/dist/telemetry.js.map +1 -0
  70. package/dist/timer-registry.d.ts +25 -0
  71. package/dist/timer-registry.d.ts.map +1 -1
  72. package/dist/timer-registry.js +42 -8
  73. package/dist/timer-registry.js.map +1 -1
  74. package/dist/types.d.ts +17 -6
  75. package/dist/types.d.ts.map +1 -1
  76. package/dist/types.js +1 -1
  77. package/dist/types.js.map +1 -1
  78. package/dist/worker/durable-step.d.ts +481 -0
  79. package/dist/worker/durable-step.d.ts.map +1 -0
  80. package/dist/worker/durable-step.js +606 -0
  81. package/dist/worker/durable-step.js.map +1 -0
  82. package/dist/worker/index.d.ts +106 -0
  83. package/dist/worker/index.d.ts.map +1 -0
  84. package/dist/worker/index.js +124 -0
  85. package/dist/worker/index.js.map +1 -0
  86. package/dist/worker/state-adapter.d.ts +230 -0
  87. package/dist/worker/state-adapter.d.ts.map +1 -0
  88. package/dist/worker/state-adapter.js +409 -0
  89. package/dist/worker/state-adapter.js.map +1 -0
  90. package/dist/worker/topological-executor.d.ts +282 -0
  91. package/dist/worker/topological-executor.d.ts.map +1 -0
  92. package/dist/worker/topological-executor.js +396 -0
  93. package/dist/worker/topological-executor.js.map +1 -0
  94. package/dist/worker/workflow-builder.d.ts +286 -0
  95. package/dist/worker/workflow-builder.d.ts.map +1 -0
  96. package/dist/worker/workflow-builder.js +565 -0
  97. package/dist/worker/workflow-builder.js.map +1 -0
  98. package/dist/worker.d.ts +800 -0
  99. package/dist/worker.d.ts.map +1 -0
  100. package/dist/worker.js +2428 -0
  101. package/dist/worker.js.map +1 -0
  102. package/dist/workflow-builder.d.ts +287 -0
  103. package/dist/workflow-builder.d.ts.map +1 -0
  104. package/dist/workflow-builder.js +762 -0
  105. package/dist/workflow-builder.js.map +1 -0
  106. package/dist/workflow.d.ts +14 -30
  107. package/dist/workflow.d.ts.map +1 -1
  108. package/dist/workflow.js +132 -292
  109. package/dist/workflow.js.map +1 -1
  110. package/examples/01-ecommerce-order-pipeline.ts +358 -0
  111. package/examples/02-content-moderation-cascade.ts +454 -0
  112. package/examples/03-scheduled-reporting-dependencies.ts +479 -0
  113. package/examples/04-database-persistence.ts +518 -0
  114. package/examples/README.md +173 -0
  115. package/package.json +30 -13
  116. package/src/__tests__/digital-objects-adapter.test.ts +274 -0
  117. package/src/__tests__/durable-workflow.test.ts +297 -0
  118. package/src/barrier.ts +48 -7
  119. package/src/cascade-context.ts +36 -29
  120. package/src/cascade-executor.ts +3 -2
  121. package/src/context.ts +41 -12
  122. package/src/cron-parser.ts +347 -0
  123. package/src/cron-scheduler.ts +239 -0
  124. package/src/database-context.ts +658 -0
  125. package/src/digital-objects-adapter.ts +351 -0
  126. package/src/durable-execution-cloudflare.ts +855 -0
  127. package/src/durable-execution.ts +1042 -0
  128. package/src/durable-workflow.ts +717 -0
  129. package/src/graph/topological-sort.ts +6 -8
  130. package/src/index.ts +69 -0
  131. package/src/logger.ts +148 -0
  132. package/src/on.ts +8 -9
  133. package/src/runtime.ts +436 -0
  134. package/src/send.ts +4 -5
  135. package/src/telemetry.ts +577 -0
  136. package/src/timer-registry.ts +44 -10
  137. package/src/types.ts +32 -17
  138. package/src/worker/durable-step.ts +976 -0
  139. package/src/worker/index.ts +216 -0
  140. package/src/worker/state-adapter.ts +589 -0
  141. package/src/worker/topological-executor.ts +625 -0
  142. package/src/worker/workflow-builder.ts +871 -0
  143. package/src/worker.ts +2906 -0
  144. package/src/workflow-builder.ts +1068 -0
  145. package/src/workflow.ts +188 -351
  146. package/test/barrier-join.test.ts +32 -24
  147. package/test/cascade-executor.test.ts +9 -16
  148. package/test/cron-parser.test.ts +314 -0
  149. package/test/cron-scheduler.test.ts +291 -0
  150. package/test/database-context.test.ts +770 -0
  151. package/test/db-provider-adapter.test.ts +862 -0
  152. package/test/durable-execution-cloudflare.test.ts +606 -0
  153. package/test/durable-execution-in-process.test.ts +286 -0
  154. package/test/durable-execution.test.ts +247 -0
  155. package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
  156. package/test/integration.test.ts +442 -0
  157. package/test/rpc-surface.test.ts +946 -0
  158. package/test/runtime.test.ts +262 -0
  159. package/test/schedule-timer-cleanup.test.ts +30 -21
  160. package/test/send-race-conditions.test.ts +30 -40
  161. package/test/worker/durable-cascade.test.ts +1117 -0
  162. package/test/worker/durable-step.test.ts +723 -0
  163. package/test/worker/topological-executor.test.ts +1240 -0
  164. package/test/worker/workflow-builder.test.ts +1067 -0
  165. package/test/worker.test.ts +608 -0
  166. package/test/workflow-builder.test.ts +1670 -0
  167. package/test/workflow-cron.test.ts +256 -0
  168. package/test/workflow-state-adapter.test.ts +923 -0
  169. package/test/workflow.test.ts +25 -22
  170. package/tsconfig.json +3 -1
  171. package/vitest.config.ts +38 -1
  172. package/vitest.workers.config.ts +44 -0
  173. package/wrangler.jsonc +22 -0
  174. package/.turbo/turbo-test.log +0 -169
  175. package/LICENSE +0 -21
  176. package/src/context.js +0 -83
  177. package/src/every.js +0 -267
  178. package/src/index.js +0 -71
  179. package/src/on.js +0 -79
  180. package/src/send.js +0 -111
  181. package/src/types.js +0 -4
  182. package/src/workflow.js +0 -455
  183. package/test/context.test.js +0 -116
  184. package/test/every.test.js +0 -282
  185. package/test/on.test.js +0 -80
  186. package/test/send.test.js +0 -89
  187. package/test/workflow.test.js +0 -224
  188. package/vitest.config.js +0 -7
@@ -0,0 +1,518 @@
1
+ /**
2
+ * Example: Integration with ai-database for Persistence
3
+ *
4
+ * This example demonstrates how to integrate ai-workflows with a database
5
+ * for durable event storage, state persistence, and audit logging.
6
+ *
7
+ * Note: This example uses a mock database implementation. In production,
8
+ * you would use ai-database or another persistence layer.
9
+ *
10
+ * Key concepts demonstrated:
11
+ * - DatabaseContext integration with workflows
12
+ * - Durable event storage with $.do
13
+ * - State checkpointing
14
+ * - Audit trail with 5W+H events
15
+ * - Recovery from failures
16
+ *
17
+ * @example
18
+ * ```bash
19
+ * npx tsx examples/04-database-persistence.ts
20
+ * ```
21
+ */
22
+
23
+ import {
24
+ Workflow,
25
+ createCascadeContext,
26
+ recordStep,
27
+ type WorkflowContext,
28
+ type DatabaseContext,
29
+ } from '../dist/index.js'
30
+
31
+ // ============================================================================
32
+ // Type Definitions
33
+ // ============================================================================
34
+
35
+ interface StoredEvent {
36
+ id: string
37
+ event: string
38
+ data: unknown
39
+ timestamp: number
40
+ }
41
+
42
+ interface StoredAction {
43
+ id: string
44
+ actor: string
45
+ object: string
46
+ action: string
47
+ status?: 'pending' | 'active' | 'completed' | 'failed'
48
+ metadata?: Record<string, unknown>
49
+ createdAt: number
50
+ completedAt?: number
51
+ result?: unknown
52
+ }
53
+
54
+ interface StoredArtifact {
55
+ key: string
56
+ type: string
57
+ sourceHash: string
58
+ content: unknown
59
+ metadata?: Record<string, unknown>
60
+ storedAt: number
61
+ }
62
+
63
+ interface WorkflowCheckpoint {
64
+ workflowId: string
65
+ state: Record<string, unknown>
66
+ history: Array<{ timestamp: number; type: string; name: string; data?: unknown }>
67
+ createdAt: number
68
+ }
69
+
70
+ // ============================================================================
71
+ // Mock Database Implementation
72
+ // ============================================================================
73
+
74
+ class MockDatabase {
75
+ private events: StoredEvent[] = []
76
+ private actions: Map<string, StoredAction> = new Map()
77
+ private artifacts: Map<string, StoredArtifact> = new Map()
78
+ private checkpoints: Map<string, WorkflowCheckpoint> = new Map()
79
+
80
+ // Event storage
81
+ async recordEvent(event: string, data: unknown): Promise<string> {
82
+ const id = `evt_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
83
+ const stored: StoredEvent = {
84
+ id,
85
+ event,
86
+ data,
87
+ timestamp: Date.now(),
88
+ }
89
+ this.events.push(stored)
90
+ console.log(` [DB] Recorded event: ${event} (${id})`)
91
+ return id
92
+ }
93
+
94
+ async getEvents(filter?: { event?: string; since?: number }): Promise<StoredEvent[]> {
95
+ let result = [...this.events]
96
+ if (filter?.event) {
97
+ result = result.filter((e) => e.event === filter.event)
98
+ }
99
+ if (filter?.since) {
100
+ result = result.filter((e) => e.timestamp >= filter.since)
101
+ }
102
+ return result
103
+ }
104
+
105
+ // Action storage
106
+ async createAction(action: Omit<StoredAction, 'id' | 'createdAt'>): Promise<string> {
107
+ const id = `act_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
108
+ const stored: StoredAction = {
109
+ ...action,
110
+ id,
111
+ status: action.status || 'pending',
112
+ createdAt: Date.now(),
113
+ }
114
+ this.actions.set(id, stored)
115
+ console.log(` [DB] Created action: ${action.action} on ${action.object} (${id})`)
116
+ return id
117
+ }
118
+
119
+ async updateAction(
120
+ id: string,
121
+ update: Partial<Pick<StoredAction, 'status' | 'result'>>
122
+ ): Promise<void> {
123
+ const action = this.actions.get(id)
124
+ if (action) {
125
+ Object.assign(action, update)
126
+ if (update.status === 'completed' || update.status === 'failed') {
127
+ action.completedAt = Date.now()
128
+ }
129
+ console.log(` [DB] Updated action ${id}: status=${action.status}`)
130
+ }
131
+ }
132
+
133
+ async getAction(id: string): Promise<StoredAction | null> {
134
+ return this.actions.get(id) || null
135
+ }
136
+
137
+ async getPendingActions(): Promise<StoredAction[]> {
138
+ return Array.from(this.actions.values()).filter(
139
+ (a) => a.status === 'pending' || a.status === 'active'
140
+ )
141
+ }
142
+
143
+ // Artifact storage
144
+ async storeArtifact(artifact: Omit<StoredArtifact, 'storedAt'>): Promise<void> {
145
+ const stored: StoredArtifact = {
146
+ ...artifact,
147
+ storedAt: Date.now(),
148
+ }
149
+ this.artifacts.set(artifact.key, stored)
150
+ console.log(` [DB] Stored artifact: ${artifact.key} (${artifact.type})`)
151
+ }
152
+
153
+ async getArtifact(key: string): Promise<StoredArtifact | null> {
154
+ return this.artifacts.get(key) || null
155
+ }
156
+
157
+ // Checkpoint storage
158
+ async saveCheckpoint(checkpoint: WorkflowCheckpoint): Promise<void> {
159
+ this.checkpoints.set(checkpoint.workflowId, checkpoint)
160
+ console.log(` [DB] Saved checkpoint for workflow ${checkpoint.workflowId}`)
161
+ }
162
+
163
+ async getCheckpoint(workflowId: string): Promise<WorkflowCheckpoint | null> {
164
+ return this.checkpoints.get(workflowId) || null
165
+ }
166
+
167
+ // Stats
168
+ getStats() {
169
+ return {
170
+ events: this.events.length,
171
+ actions: this.actions.size,
172
+ artifacts: this.artifacts.size,
173
+ checkpoints: this.checkpoints.size,
174
+ }
175
+ }
176
+
177
+ // Dump for inspection
178
+ dump() {
179
+ return {
180
+ events: this.events,
181
+ actions: Array.from(this.actions.values()),
182
+ artifacts: Array.from(this.artifacts.values()),
183
+ checkpoints: Array.from(this.checkpoints.values()),
184
+ }
185
+ }
186
+ }
187
+
188
+ // ============================================================================
189
+ // Database Context Adapter
190
+ // ============================================================================
191
+
192
+ function createDatabaseContext(db: MockDatabase): DatabaseContext {
193
+ return {
194
+ async recordEvent(event: string, data: unknown): Promise<void> {
195
+ await db.recordEvent(event, data)
196
+ },
197
+
198
+ async createAction(action: {
199
+ actor: string
200
+ object: string
201
+ action: string
202
+ status?: 'pending' | 'active' | 'completed' | 'failed'
203
+ metadata?: Record<string, unknown>
204
+ }): Promise<void> {
205
+ await db.createAction(action)
206
+ },
207
+
208
+ async completeAction(id: string, result: unknown): Promise<void> {
209
+ await db.updateAction(id, { status: 'completed', result })
210
+ },
211
+
212
+ async storeArtifact(artifact: {
213
+ key: string
214
+ type: string
215
+ sourceHash: string
216
+ content: unknown
217
+ metadata?: Record<string, unknown>
218
+ }): Promise<void> {
219
+ await db.storeArtifact(artifact)
220
+ },
221
+
222
+ async getArtifact(key: string): Promise<unknown | null> {
223
+ const artifact = await db.getArtifact(key)
224
+ return artifact?.content ?? null
225
+ },
226
+ }
227
+ }
228
+
229
+ // ============================================================================
230
+ // Durable Workflow Example
231
+ // ============================================================================
232
+
233
+ interface PaymentRequest {
234
+ orderId: string
235
+ amount: number
236
+ customerId: string
237
+ }
238
+
239
+ interface PaymentResult {
240
+ transactionId: string
241
+ status: 'success' | 'failed'
242
+ processedAt: number
243
+ }
244
+
245
+ async function createDurablePaymentWorkflow(db: MockDatabase) {
246
+ const dbContext = createDatabaseContext(db)
247
+
248
+ const workflow = Workflow(
249
+ ($) => {
250
+ // Payment processing with durable state
251
+ $.on.Payment.process(async (request: PaymentRequest, $: WorkflowContext) => {
252
+ $.log(`Processing payment for order ${request.orderId}`)
253
+
254
+ // Create cascade context for tracing
255
+ const cascade = createCascadeContext({ name: 'payment-processing' })
256
+
257
+ // Step 1: Validate payment
258
+ const validateStep = recordStep(cascade, 'validate', {
259
+ actor: 'payment-service',
260
+ action: 'validate-payment',
261
+ })
262
+
263
+ try {
264
+ // Simulate validation
265
+ await new Promise((resolve) => setTimeout(resolve, 50))
266
+ if (request.amount <= 0) {
267
+ throw new Error('Invalid amount')
268
+ }
269
+ validateStep.complete()
270
+ $.log(' Payment validated')
271
+ } catch (error) {
272
+ validateStep.fail(error instanceof Error ? error : new Error(String(error)))
273
+ throw error
274
+ }
275
+
276
+ // Step 2: Process payment (durable)
277
+ const processStep = recordStep(cascade, 'process', {
278
+ actor: 'payment-gateway',
279
+ action: 'charge-card',
280
+ })
281
+
282
+ try {
283
+ // This would be $.do in real usage for durable execution
284
+ await new Promise((resolve) => setTimeout(resolve, 100))
285
+ const transactionId = `txn_${Date.now()}`
286
+
287
+ // Store transaction artifact
288
+ if ($.db) {
289
+ await $.db.storeArtifact({
290
+ key: `payment:${request.orderId}`,
291
+ type: 'transaction',
292
+ sourceHash: request.orderId,
293
+ content: {
294
+ transactionId,
295
+ amount: request.amount,
296
+ customerId: request.customerId,
297
+ },
298
+ })
299
+ }
300
+
301
+ processStep.complete()
302
+ $.log(` Payment processed: ${transactionId}`)
303
+
304
+ // Emit success event
305
+ $.send('Payment.completed', {
306
+ orderId: request.orderId,
307
+ transactionId,
308
+ amount: request.amount,
309
+ })
310
+
311
+ return {
312
+ transactionId,
313
+ status: 'success' as const,
314
+ processedAt: Date.now(),
315
+ }
316
+ } catch (error) {
317
+ processStep.fail(error instanceof Error ? error : new Error(String(error)))
318
+
319
+ $.send('Payment.failed', {
320
+ orderId: request.orderId,
321
+ error: error instanceof Error ? error.message : String(error),
322
+ })
323
+
324
+ throw error
325
+ }
326
+ })
327
+
328
+ $.on.Payment.completed(
329
+ async (data: { orderId: string; transactionId: string }, $: WorkflowContext) => {
330
+ $.log(`Payment ${data.transactionId} completed for order ${data.orderId}`)
331
+
332
+ // Create action to fulfill order
333
+ if ($.db) {
334
+ await $.db.createAction({
335
+ actor: 'fulfillment-service',
336
+ object: `order:${data.orderId}`,
337
+ action: 'fulfill',
338
+ metadata: { transactionId: data.transactionId },
339
+ })
340
+ }
341
+ }
342
+ )
343
+
344
+ $.on.Payment.failed(async (data: { orderId: string; error: string }, $: WorkflowContext) => {
345
+ $.log(`Payment failed for order ${data.orderId}: ${data.error}`)
346
+
347
+ // Create action to notify customer
348
+ if ($.db) {
349
+ await $.db.createAction({
350
+ actor: 'notification-service',
351
+ object: `customer:order:${data.orderId}`,
352
+ action: 'notify-payment-failed',
353
+ metadata: { error: data.error },
354
+ })
355
+ }
356
+ })
357
+ },
358
+ { db: dbContext }
359
+ )
360
+
361
+ return workflow
362
+ }
363
+
364
+ // ============================================================================
365
+ // State Recovery Example
366
+ // ============================================================================
367
+
368
+ async function demonstrateStateRecovery(db: MockDatabase) {
369
+ console.log('\n--- State Recovery Demo ---\n')
370
+
371
+ // Simulate saving a checkpoint
372
+ const checkpoint: WorkflowCheckpoint = {
373
+ workflowId: 'workflow-123',
374
+ state: {
375
+ orderId: 'order-456',
376
+ step: 'payment-processing',
377
+ attempts: 2,
378
+ },
379
+ history: [
380
+ { timestamp: Date.now() - 10000, type: 'event', name: 'Order.placed' },
381
+ { timestamp: Date.now() - 5000, type: 'action', name: 'validate' },
382
+ {
383
+ timestamp: Date.now() - 1000,
384
+ type: 'action',
385
+ name: 'process-payment',
386
+ data: { attempt: 1 },
387
+ },
388
+ ],
389
+ createdAt: Date.now(),
390
+ }
391
+
392
+ await db.saveCheckpoint(checkpoint)
393
+
394
+ // Simulate recovery
395
+ console.log('Recovering workflow state...')
396
+ const recovered = await db.getCheckpoint('workflow-123')
397
+
398
+ if (recovered) {
399
+ console.log(` Recovered workflow: ${recovered.workflowId}`)
400
+ console.log(` State: ${JSON.stringify(recovered.state)}`)
401
+ console.log(` History entries: ${recovered.history.length}`)
402
+ console.log(` Last action: ${recovered.history[recovered.history.length - 1]?.name}`)
403
+ }
404
+ }
405
+
406
+ // ============================================================================
407
+ // Audit Trail Example
408
+ // ============================================================================
409
+
410
+ async function demonstrateAuditTrail(db: MockDatabase) {
411
+ console.log('\n--- Audit Trail Demo ---\n')
412
+
413
+ // Record various events
414
+ await db.recordEvent('User.login', {
415
+ userId: 'user-123',
416
+ ip: '192.168.1.1',
417
+ userAgent: 'Mozilla/5.0...',
418
+ })
419
+
420
+ await db.recordEvent('Order.placed', {
421
+ orderId: 'order-789',
422
+ customerId: 'user-123',
423
+ total: 99.99,
424
+ })
425
+
426
+ await db.recordEvent('Payment.processed', {
427
+ orderId: 'order-789',
428
+ transactionId: 'txn-abc',
429
+ amount: 99.99,
430
+ })
431
+
432
+ await db.recordEvent('Order.shipped', {
433
+ orderId: 'order-789',
434
+ trackingNumber: 'TRK123456',
435
+ carrier: 'FastShip',
436
+ })
437
+
438
+ // Query events
439
+ console.log('All recorded events:')
440
+ const events = await db.getEvents()
441
+ for (const event of events) {
442
+ console.log(` ${new Date(event.timestamp).toISOString()} | ${event.event}`)
443
+ }
444
+
445
+ // Query specific event type
446
+ console.log('\nOrder-related events:')
447
+ const orderEvents = await db.getEvents({ event: 'Order.placed' })
448
+ for (const event of orderEvents) {
449
+ console.log(` ${event.id}: ${JSON.stringify(event.data)}`)
450
+ }
451
+ }
452
+
453
+ // ============================================================================
454
+ // Demo Execution
455
+ // ============================================================================
456
+
457
+ async function runDemo() {
458
+ console.log('='.repeat(60))
459
+ console.log('Database Persistence Integration Demo')
460
+ console.log('='.repeat(60))
461
+ console.log()
462
+
463
+ // Create mock database
464
+ const db = new MockDatabase()
465
+
466
+ // Create and start workflow
467
+ const workflow = await createDurablePaymentWorkflow(db)
468
+ await workflow.start()
469
+
470
+ // Process some payments
471
+ console.log('--- Processing Payments ---\n')
472
+
473
+ await workflow.send('Payment.process', {
474
+ orderId: 'order-001',
475
+ amount: 99.99,
476
+ customerId: 'cust-001',
477
+ })
478
+ await new Promise((resolve) => setTimeout(resolve, 200))
479
+
480
+ await workflow.send('Payment.process', {
481
+ orderId: 'order-002',
482
+ amount: 149.99,
483
+ customerId: 'cust-002',
484
+ })
485
+ await new Promise((resolve) => setTimeout(resolve, 200))
486
+
487
+ // Demonstrate state recovery
488
+ await demonstrateStateRecovery(db)
489
+
490
+ // Demonstrate audit trail
491
+ await demonstrateAuditTrail(db)
492
+
493
+ // Show database stats
494
+ console.log('\n--- Database Stats ---\n')
495
+ const stats = db.getStats()
496
+ console.log(` Events: ${stats.events}`)
497
+ console.log(` Actions: ${stats.actions}`)
498
+ console.log(` Artifacts: ${stats.artifacts}`)
499
+ console.log(` Checkpoints: ${stats.checkpoints}`)
500
+
501
+ // Show pending actions
502
+ console.log('\n--- Pending Actions ---\n')
503
+ const pending = await db.getPendingActions()
504
+ for (const action of pending) {
505
+ console.log(` ${action.id}: ${action.action} on ${action.object} (${action.status})`)
506
+ }
507
+
508
+ // Full dump for inspection
509
+ console.log('\n--- Full Database Dump ---\n')
510
+ const dump = db.dump()
511
+ console.log(JSON.stringify(dump, null, 2))
512
+
513
+ // Clean up
514
+ await workflow.stop()
515
+ }
516
+
517
+ // Run if executed directly
518
+ runDemo().catch(console.error)
@@ -0,0 +1,173 @@
1
+ # ai-workflows Examples
2
+
3
+ This directory contains runnable examples demonstrating the key features of ai-workflows.
4
+
5
+ ## Prerequisites
6
+
7
+ ```bash
8
+ # From the package root (or monorepo root)
9
+ npm install
10
+ npm run build # Must build first since examples import from dist/
11
+ ```
12
+
13
+ ## Running Examples
14
+
15
+ Each example can be run directly with `tsx`:
16
+
17
+ ```bash
18
+ # From the ai-workflows package directory
19
+ npx tsx examples/01-ecommerce-order-pipeline.ts
20
+ npx tsx examples/02-content-moderation-cascade.ts
21
+ npx tsx examples/03-scheduled-reporting-dependencies.ts
22
+ npx tsx examples/04-database-persistence.ts
23
+ ```
24
+
25
+ **Note:** Examples import from `../dist/index.js` to use the built package. Ensure you run `npm run build` first.
26
+
27
+ ## Examples Overview
28
+
29
+ ### 01 - E-commerce Order Processing Pipeline
30
+
31
+ Demonstrates a complete order processing workflow using event-driven architecture.
32
+
33
+ **Key Concepts:**
34
+ - Event handlers with `$.on.Noun.event()`
35
+ - Event chaining (one event triggers another)
36
+ - State management with `$.state`
37
+ - Error handling and compensation patterns
38
+ - Customer notification flow
39
+
40
+ **Flow:**
41
+ ```
42
+ Order.placed -> Payment.requested -> Payment.completed -> Order.confirmed
43
+ -> Shipping.requested -> Order.shipped
44
+ ```
45
+
46
+ ### 02 - AI Content Moderation with Human Escalation
47
+
48
+ Demonstrates the CascadeExecutor pattern for tiered processing with escalation.
49
+
50
+ **Key Concepts:**
51
+ - `CascadeExecutor` for code -> AI -> agent -> human escalation
52
+ - Per-tier timeouts and retry configuration
53
+ - Skip conditions for tier bypassing
54
+ - 5W+H audit trail for compliance
55
+ - Workflow integration with cascade results
56
+
57
+ **Tiers:**
58
+ 1. **Code**: Fast keyword/pattern matching (100ms timeout)
59
+ 2. **Generative**: LLM-based analysis (5s timeout)
60
+ 3. **Agentic**: Multi-step reasoning with tools (30s timeout)
61
+ 4. **Human**: Expert review queue (1 hour timeout)
62
+
63
+ ### 03 - Scheduled Reporting with Dependency Chains
64
+
65
+ Demonstrates complex workflows with dependencies and parallel execution.
66
+
67
+ **Key Concepts:**
68
+ - `DependencyGraph` for step ordering
69
+ - `topologicalSort()` for execution planning
70
+ - `getExecutionLevels()` for parallel grouping
71
+ - `waitForAll()` and `Barrier` for synchronization
72
+ - `withConcurrencyLimit()` for controlled parallelism
73
+
74
+ **Pipeline:**
75
+ ```
76
+ Level 0: [fetch-sales, fetch-crm, fetch-inventory, fetch-analytics] (parallel)
77
+ Level 1: [aggregate-data] (sequential)
78
+ Level 2: [generate-daily-report, generate-summary] (parallel)
79
+ Level 3: [distribute-email, distribute-slack, archive-s3] (parallel)
80
+ ```
81
+
82
+ ### 04 - Database Persistence Integration
83
+
84
+ Demonstrates durable event storage and state persistence.
85
+
86
+ **Key Concepts:**
87
+ - `DatabaseContext` integration with workflows
88
+ - Durable event storage with `$.db.recordEvent()`
89
+ - Action tracking with `$.db.createAction()`
90
+ - Artifact storage with `$.db.storeArtifact()`
91
+ - State checkpointing and recovery
92
+ - Audit trail with 5W+H events
93
+
94
+ **Note:** Uses a mock database implementation. In production, integrate with `ai-database` or your persistence layer.
95
+
96
+ ## Code Patterns
97
+
98
+ ### Basic Workflow Setup
99
+
100
+ ```typescript
101
+ import { Workflow } from 'ai-workflows'
102
+
103
+ const workflow = Workflow($ => {
104
+ $.on.Entity.event(async (data, $) => {
105
+ $.log('Processing event')
106
+ $.send('Another.event', { result: 'done' })
107
+ })
108
+ })
109
+
110
+ await workflow.start()
111
+ await workflow.send('Entity.event', { input: 'data' })
112
+ await workflow.stop()
113
+ ```
114
+
115
+ ### Cascade Executor
116
+
117
+ ```typescript
118
+ import { CascadeExecutor } from 'ai-workflows'
119
+
120
+ const cascade = new CascadeExecutor({
121
+ tiers: {
122
+ code: { name: 'rules', execute: async (input) => { /* fast rules */ } },
123
+ generative: { name: 'ai', execute: async (input) => { /* AI analysis */ } },
124
+ human: { name: 'review', execute: async (input) => { /* human queue */ } },
125
+ },
126
+ useDefaultTimeouts: true,
127
+ })
128
+
129
+ const result = await cascade.execute(input)
130
+ console.log(`Resolved by ${result.tier} tier`)
131
+ ```
132
+
133
+ ### Dependency Graph
134
+
135
+ ```typescript
136
+ import { DependencyGraph, getExecutionLevels } from 'ai-workflows'
137
+
138
+ const graph = new DependencyGraph()
139
+ graph.addNode('step-a')
140
+ graph.addNode('step-b')
141
+ graph.addNode('step-c', { dependsOn: ['step-a', 'step-b'] })
142
+
143
+ const levels = getExecutionLevels(graph.getNodes())
144
+ // Level 0: [step-a, step-b]
145
+ // Level 1: [step-c]
146
+ ```
147
+
148
+ ### Barrier Synchronization
149
+
150
+ ```typescript
151
+ import { Barrier, waitForAll } from 'ai-workflows'
152
+
153
+ // Simple parallel wait
154
+ const results = await waitForAll([
155
+ fetchA(),
156
+ fetchB(),
157
+ fetchC(),
158
+ ], { timeout: 5000 })
159
+
160
+ // Manual barrier with progress
161
+ const barrier = new Barrier(3, {
162
+ onProgress: (p) => console.log(`${p.percentage}% complete`)
163
+ })
164
+ // ... barrier.arrive(result) from parallel workers
165
+ const all = await barrier.wait()
166
+ ```
167
+
168
+ ## Related Documentation
169
+
170
+ - [ai-workflows README](../README.md) - Full API documentation
171
+ - [CascadeExecutor](../src/cascade-executor.ts) - Tiered execution pattern
172
+ - [DependencyGraph](../src/dependency-graph.ts) - Step dependency management
173
+ - [Barrier](../src/barrier.ts) - Parallel coordination primitives