@objectstack/service-automation 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,437 @@
1
+ # @objectstack/service-automation
2
+
3
+ Automation Service for ObjectStack — implements `IAutomationService` with plugin-based DAG (Directed Acyclic Graph) flow execution engine.
4
+
5
+ ## Features
6
+
7
+ - **Flow Execution Engine**: Execute multi-step automation flows with conditional logic
8
+ - **DAG-based Architecture**: Flows are represented as directed acyclic graphs for parallel execution
9
+ - **Trigger System**: Launch flows automatically on record changes, schedule, or manual invocation
10
+ - **Variable Management**: Pass data between flow steps with type-safe variables
11
+ - **Error Handling**: Built-in retry logic, error branches, and rollback support
12
+ - **Visual Flow Builder**: Compatible with Studio's visual flow designer
13
+ - **Type-Safe**: Full TypeScript support with flow definition validation
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @objectstack/service-automation
19
+ ```
20
+
21
+ ## Basic Usage
22
+
23
+ ```typescript
24
+ import { defineStack, defineFlow } from '@objectstack/spec';
25
+ import { ServiceAutomation } from '@objectstack/service-automation';
26
+
27
+ const stack = defineStack({
28
+ services: [ServiceAutomation.configure()],
29
+ });
30
+ ```
31
+
32
+ ## Flow Types
33
+
34
+ ObjectStack supports three types of flows:
35
+
36
+ ### 1. Autolaunched Flows
37
+ Triggered automatically by record changes:
38
+
39
+ ```typescript
40
+ const autoFlow = defineFlow({
41
+ name: 'welcome_email',
42
+ type: 'autolaunched',
43
+ trigger: {
44
+ object: 'user',
45
+ when: 'after_insert',
46
+ },
47
+ steps: [
48
+ {
49
+ type: 'action',
50
+ action: 'send_email',
51
+ inputs: {
52
+ to: '{!trigger.record.email}',
53
+ subject: 'Welcome to ObjectStack!',
54
+ body: 'Hello {!trigger.record.name}...',
55
+ },
56
+ },
57
+ ],
58
+ });
59
+ ```
60
+
61
+ ### 2. Screen Flows
62
+ Interactive flows with user input:
63
+
64
+ ```typescript
65
+ const screenFlow = defineFlow({
66
+ name: 'create_opportunity',
67
+ type: 'screen',
68
+ steps: [
69
+ {
70
+ type: 'screen',
71
+ fields: [
72
+ { name: 'account_id', label: 'Account', type: 'lookup', object: 'account' },
73
+ { name: 'amount', label: 'Amount', type: 'currency' },
74
+ { name: 'close_date', label: 'Close Date', type: 'date' },
75
+ ],
76
+ },
77
+ {
78
+ type: 'record_create',
79
+ object: 'opportunity',
80
+ fields: {
81
+ account_id: '{!screen.account_id}',
82
+ amount: '{!screen.amount}',
83
+ close_date: '{!screen.close_date}',
84
+ stage: 'prospecting',
85
+ },
86
+ },
87
+ ],
88
+ });
89
+ ```
90
+
91
+ ### 3. Scheduled Flows
92
+ Run on a schedule (cron syntax):
93
+
94
+ ```typescript
95
+ const scheduledFlow = defineFlow({
96
+ name: 'daily_report',
97
+ type: 'scheduled',
98
+ schedule: '0 9 * * *', // Every day at 9 AM
99
+ steps: [
100
+ {
101
+ type: 'query',
102
+ object: 'order',
103
+ filters: [
104
+ { field: 'created_at', operator: 'yesterday' },
105
+ ],
106
+ output: 'orders',
107
+ },
108
+ {
109
+ type: 'action',
110
+ action: 'send_email',
111
+ inputs: {
112
+ to: 'admin@company.com',
113
+ subject: 'Daily Orders Report',
114
+ body: 'Total orders: {!orders.length}',
115
+ },
116
+ },
117
+ ],
118
+ });
119
+ ```
120
+
121
+ ## Flow Steps
122
+
123
+ ### Record Operations
124
+
125
+ ```typescript
126
+ // Create record
127
+ {
128
+ type: 'record_create',
129
+ object: 'contact',
130
+ fields: {
131
+ name: '{!input.name}',
132
+ email: '{!input.email}',
133
+ },
134
+ output: 'new_contact',
135
+ }
136
+
137
+ // Update record
138
+ {
139
+ type: 'record_update',
140
+ object: 'account',
141
+ recordId: '{!trigger.recordId}',
142
+ fields: {
143
+ status: 'active',
144
+ },
145
+ }
146
+
147
+ // Delete record
148
+ {
149
+ type: 'record_delete',
150
+ object: 'task',
151
+ recordId: '{!input.taskId}',
152
+ }
153
+ ```
154
+
155
+ ### Query Step
156
+
157
+ ```typescript
158
+ {
159
+ type: 'query',
160
+ object: 'opportunity',
161
+ filters: [
162
+ { field: 'account_id', operator: 'eq', value: '{!trigger.record.account_id}' },
163
+ { field: 'stage', operator: 'eq', value: 'closed_won' },
164
+ ],
165
+ sort: [{ field: 'amount', direction: 'desc' }],
166
+ limit: 10,
167
+ output: 'opportunities',
168
+ }
169
+ ```
170
+
171
+ ### Decision (Conditional) Step
172
+
173
+ ```typescript
174
+ {
175
+ type: 'decision',
176
+ conditions: [
177
+ {
178
+ label: 'High Value',
179
+ expression: '{!trigger.record.amount} > 10000',
180
+ steps: [
181
+ { type: 'action', action: 'notify_sales_manager' },
182
+ ],
183
+ },
184
+ {
185
+ label: 'Medium Value',
186
+ expression: '{!trigger.record.amount} > 1000',
187
+ steps: [
188
+ { type: 'action', action: 'assign_to_sales_rep' },
189
+ ],
190
+ },
191
+ ],
192
+ defaultSteps: [
193
+ { type: 'action', action: 'auto_approve' },
194
+ ],
195
+ }
196
+ ```
197
+
198
+ ### Loop Step
199
+
200
+ ```typescript
201
+ {
202
+ type: 'loop',
203
+ collection: '{!query_results}',
204
+ variable: 'item',
205
+ steps: [
206
+ {
207
+ type: 'record_update',
208
+ object: 'task',
209
+ recordId: '{!item.id}',
210
+ fields: {
211
+ status: 'completed',
212
+ },
213
+ },
214
+ ],
215
+ }
216
+ ```
217
+
218
+ ### Custom Action Step
219
+
220
+ ```typescript
221
+ {
222
+ type: 'action',
223
+ action: 'calculate_tax',
224
+ inputs: {
225
+ amount: '{!opportunity.amount}',
226
+ region: '{!account.billing_region}',
227
+ },
228
+ output: 'tax_amount',
229
+ }
230
+ ```
231
+
232
+ ## Variable Expressions
233
+
234
+ Access variables in flow steps using `{!variable.path}` syntax:
235
+
236
+ ```typescript
237
+ // Trigger record fields
238
+ '{!trigger.record.name}'
239
+ '{!trigger.record.account.industry}'
240
+
241
+ // Screen input
242
+ '{!screen.fieldName}'
243
+
244
+ // Query results
245
+ '{!query_results[0].name}'
246
+ '{!query_results.length}'
247
+
248
+ // Step outputs
249
+ '{!step_name.output_field}'
250
+
251
+ // System variables
252
+ '{!now}'
253
+ '{!today}'
254
+ '{!currentUser.id}'
255
+ ```
256
+
257
+ ## Service API
258
+
259
+ ```typescript
260
+ // Get automation service
261
+ const automation = kernel.getService<IAutomationService>('automation');
262
+ ```
263
+
264
+ ### Execute Flow
265
+
266
+ ```typescript
267
+ // Execute a flow manually
268
+ const result = await automation.executeFlow({
269
+ flowName: 'create_opportunity',
270
+ inputs: {
271
+ account_id: '123',
272
+ amount: 50000,
273
+ },
274
+ });
275
+
276
+ // Check execution status
277
+ if (result.status === 'success') {
278
+ console.log('Flow completed:', result.outputs);
279
+ } else {
280
+ console.error('Flow failed:', result.error);
281
+ }
282
+ ```
283
+
284
+ ### Flow Management
285
+
286
+ ```typescript
287
+ // Get flow definition
288
+ const flow = await automation.getFlow('welcome_email');
289
+
290
+ // List all flows
291
+ const flows = await automation.listFlows();
292
+
293
+ // Get flow execution history
294
+ const history = await automation.getFlowHistory({
295
+ flowName: 'daily_report',
296
+ limit: 100,
297
+ });
298
+ ```
299
+
300
+ ### Trigger Management
301
+
302
+ ```typescript
303
+ // Register a custom trigger
304
+ automation.registerTrigger({
305
+ name: 'on_payment_received',
306
+ description: 'Triggered when a payment is received',
307
+ async handler(context) {
308
+ // Trigger logic
309
+ return {
310
+ record: context.payment,
311
+ timestamp: new Date(),
312
+ };
313
+ },
314
+ });
315
+ ```
316
+
317
+ ## REST API Endpoints
318
+
319
+ ```
320
+ POST /api/v1/automation/flows/:name/execute # Execute flow
321
+ GET /api/v1/automation/flows # List flows
322
+ GET /api/v1/automation/flows/:name # Get flow definition
323
+ GET /api/v1/automation/flows/:name/history # Get execution history
324
+ POST /api/v1/automation/triggers/:name # Trigger a flow
325
+ ```
326
+
327
+ ## Advanced Features
328
+
329
+ ### Parallel Execution
330
+
331
+ ```typescript
332
+ const flow = defineFlow({
333
+ name: 'parallel_processing',
334
+ steps: [
335
+ {
336
+ type: 'parallel',
337
+ branches: [
338
+ {
339
+ name: 'branch1',
340
+ steps: [{ type: 'action', action: 'process_a' }],
341
+ },
342
+ {
343
+ name: 'branch2',
344
+ steps: [{ type: 'action', action: 'process_b' }],
345
+ },
346
+ ],
347
+ },
348
+ ],
349
+ });
350
+ ```
351
+
352
+ ### Error Handling
353
+
354
+ ```typescript
355
+ {
356
+ type: 'try_catch',
357
+ trySteps: [
358
+ { type: 'action', action: 'risky_operation' },
359
+ ],
360
+ catchSteps: [
361
+ {
362
+ type: 'action',
363
+ action: 'send_error_notification',
364
+ inputs: {
365
+ error: '{!error.message}',
366
+ },
367
+ },
368
+ ],
369
+ }
370
+ ```
371
+
372
+ ### Subflows
373
+
374
+ ```typescript
375
+ {
376
+ type: 'subflow',
377
+ flowName: 'validate_address',
378
+ inputs: {
379
+ street: '{!input.street}',
380
+ city: '{!input.city}',
381
+ },
382
+ output: 'validated_address',
383
+ }
384
+ ```
385
+
386
+ ### Wait Step
387
+
388
+ ```typescript
389
+ {
390
+ type: 'wait',
391
+ duration: { hours: 24 },
392
+ nextSteps: [
393
+ { type: 'action', action: 'send_reminder' },
394
+ ],
395
+ }
396
+ ```
397
+
398
+ ## Best Practices
399
+
400
+ 1. **Keep Flows Simple**: Break complex logic into multiple flows
401
+ 2. **Use Descriptive Names**: Name flows and steps clearly
402
+ 3. **Handle Errors**: Always include error handling for critical operations
403
+ 4. **Test Thoroughly**: Test flows with various input scenarios
404
+ 5. **Monitor Performance**: Track flow execution times and optimize slow flows
405
+ 6. **Version Control**: Store flow definitions in version control
406
+ 7. **Document Intent**: Add descriptions to flows and steps
407
+
408
+ ## Performance Considerations
409
+
410
+ - **Parallel Execution**: DAG engine automatically parallelizes independent steps
411
+ - **Batch Processing**: Use loop steps efficiently for large collections
412
+ - **Query Optimization**: Filter queries early to reduce data volume
413
+ - **Async Execution**: Long-running flows execute asynchronously
414
+
415
+ ## Contract Implementation
416
+
417
+ Implements `IAutomationService` from `@objectstack/spec/contracts`:
418
+
419
+ ```typescript
420
+ interface IAutomationService {
421
+ executeFlow(options: FlowExecutionOptions): Promise<FlowResult>;
422
+ getFlow(name: string): Promise<Flow>;
423
+ listFlows(filter?: FlowFilter): Promise<Flow[]>;
424
+ getFlowHistory(options: FlowHistoryOptions): Promise<FlowExecution[]>;
425
+ registerTrigger(trigger: TriggerDefinition): void;
426
+ }
427
+ ```
428
+
429
+ ## License
430
+
431
+ Apache-2.0
432
+
433
+ ## See Also
434
+
435
+ - [@objectstack/spec/automation](../../spec/src/automation/)
436
+ - [Flow Builder Guide](/content/docs/guides/automation/)
437
+ - [Trigger Reference](/content/docs/references/automation/)