@solidactions/sdk 0.1.1 → 0.2.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 (52) hide show
  1. package/README.md +25 -4
  2. package/dist/src/cli/cli.js +0 -0
  3. package/dist/src/testing/index.d.ts +13 -0
  4. package/dist/src/testing/index.d.ts.map +1 -0
  5. package/dist/src/testing/index.js +19 -0
  6. package/dist/src/testing/index.js.map +1 -0
  7. package/dist/src/testing/mock_server.d.ts +134 -0
  8. package/dist/src/testing/mock_server.d.ts.map +1 -0
  9. package/dist/src/testing/mock_server.js +613 -0
  10. package/dist/src/testing/mock_server.js.map +1 -0
  11. package/dist/tsconfig.tsbuildinfo +1 -1
  12. package/docs/sdk-reference.md +1207 -0
  13. package/package.json +6 -1
  14. package/.claude/settings.local.json +0 -7
  15. package/dist/dbos-config.schema.json +0 -132
  16. package/dist/src/cli/commands.d.ts +0 -3
  17. package/dist/src/cli/commands.d.ts.map +0 -1
  18. package/dist/src/cli/commands.js +0 -46
  19. package/dist/src/cli/commands.js.map +0 -1
  20. package/dist/src/datasource.d.ts +0 -109
  21. package/dist/src/datasource.d.ts.map +0 -1
  22. package/dist/src/datasource.js +0 -204
  23. package/dist/src/datasource.js.map +0 -1
  24. package/dist/src/dbos-executor.d.ts +0 -189
  25. package/dist/src/dbos-executor.d.ts.map +0 -1
  26. package/dist/src/dbos-executor.js +0 -817
  27. package/dist/src/dbos-executor.js.map +0 -1
  28. package/dist/src/dbos.d.ts +0 -519
  29. package/dist/src/dbos.d.ts.map +0 -1
  30. package/dist/src/dbos.js +0 -1282
  31. package/dist/src/dbos.js.map +0 -1
  32. package/dist/src/debouncer.d.ts +0 -33
  33. package/dist/src/debouncer.d.ts.map +0 -1
  34. package/dist/src/debouncer.js +0 -170
  35. package/dist/src/debouncer.js.map +0 -1
  36. package/dist/src/scheduler/crontab.d.ts +0 -14
  37. package/dist/src/scheduler/crontab.d.ts.map +0 -1
  38. package/dist/src/scheduler/crontab.js +0 -308
  39. package/dist/src/scheduler/crontab.js.map +0 -1
  40. package/dist/src/scheduler/scheduler.d.ts +0 -41
  41. package/dist/src/scheduler/scheduler.d.ts.map +0 -1
  42. package/dist/src/scheduler/scheduler.js +0 -165
  43. package/dist/src/scheduler/scheduler.js.map +0 -1
  44. package/dist/src/wfqueue.d.ts +0 -64
  45. package/dist/src/wfqueue.d.ts.map +0 -1
  46. package/dist/src/wfqueue.js +0 -147
  47. package/dist/src/wfqueue.js.map +0 -1
  48. package/docs/api-schema.md +0 -1441
  49. package/docs/migration-guide.md +0 -460
  50. package/docs/phase-14-changes.md +0 -156
  51. package/docs/solidsteps-ai-prompt.md +0 -534
  52. package/solidactions-ai-prompt.md +0 -1504
@@ -1,1441 +0,0 @@
1
- # DBOS HTTP API Schema
2
-
3
- This document defines the HTTP API that must be implemented by the backend (Laravel) to support the DBOS TypeScript SDK.
4
-
5
- ## Overview
6
-
7
- The SDK communicates with the backend exclusively via HTTP API calls. All workflow state, operations, messages, events, and streams are managed through these endpoints.
8
-
9
- **Base URL**: Configured via `DBOS_API_URL` environment variable or `api.url` in config file.
10
-
11
- ## Authentication
12
-
13
- All requests include a Bearer token in the Authorization header:
14
-
15
- ```
16
- Authorization: Bearer <api_key>
17
- ```
18
-
19
- The API key is configured via `DBOS_API_KEY` environment variable or `api.key` in config file.
20
-
21
- ## Common Headers
22
-
23
- **Request Headers:**
24
-
25
- ```
26
- Content-Type: application/json
27
- Accept: application/json
28
- Authorization: Bearer <api_key>
29
- ```
30
-
31
- **Response Headers:**
32
-
33
- ```
34
- Content-Type: application/json
35
- ```
36
-
37
- ## Error Responses
38
-
39
- All error responses follow this format:
40
-
41
- ```json
42
- {
43
- "message": "Human-readable error message",
44
- "type": "error_type", // Optional: specific error type
45
- "workflowID": "uuid", // Optional: for workflow-specific errors
46
- "retryAfter": 60 // Optional: seconds to wait (for 429)
47
- }
48
- ```
49
-
50
- ### HTTP Status Code Mapping
51
-
52
- | Status | SDK Exception | When to Return |
53
- | ------ | ------------------------------ | ----------------------------------------------------- |
54
- | 400 | `DBOSDataValidationError` | Invalid request body or parameters |
55
- | 401 | `DBOSUnauthorizedError` | Invalid or missing API key |
56
- | 403 | `DBOSForbiddenError` | Valid API key but insufficient permissions |
57
- | 404 | `DBOSNotFoundError` | Resource not found (general) |
58
- | 404 | `DBOSNonExistentWorkflowError` | Workflow not found (set `type: "workflow_not_found"`) |
59
- | 409 | `DBOSWorkflowConflictError` | Workflow UUID conflict |
60
- | 429 | `DBOSRateLimitedError` | Rate limit exceeded (include `retryAfter`) |
61
- | 5xx | `DBOSServerError` | Server errors (SDK will retry with backoff) |
62
-
63
- ---
64
-
65
- ## Endpoints
66
-
67
- ### Health Check
68
-
69
- #### GET /health
70
-
71
- Verify API connectivity.
72
-
73
- **Response 200:**
74
-
75
- ```json
76
- {
77
- "status": "ok"
78
- }
79
- ```
80
-
81
- ---
82
-
83
- ## Workflow Endpoints
84
-
85
- ### Create Workflow
86
-
87
- #### POST /workflows
88
-
89
- Initialize a new workflow status record.
90
-
91
- **Request Body:**
92
-
93
- ```json
94
- {
95
- "workflowUUID": "string", // Required: Unique workflow ID
96
- "status": "string", // Required: Initial status (typically "PENDING" or "ENQUEUED")
97
- "workflowName": "string", // Required: Function name
98
- "workflowClassName": "string", // Required: Class name (empty string if none)
99
- "workflowConfigName": "string", // Required: Config name (empty string if none)
100
- "queueName": "string | null", // Optional: Queue name if enqueued
101
- "authenticatedUser": "string", // Required: User ID (empty string if none)
102
- "assumedRole": "string", // Required: Role (empty string if none)
103
- "authenticatedRoles": ["string"], // Required: Array of roles
104
- "request": {}, // Required: Request context object
105
- "executorId": "string", // Required: Executor ID
106
- "applicationVersion": "string", // Optional: App version
107
- "applicationID": "string", // Required: Application ID
108
- "input": "string | null", // Required: Serialized JSON input
109
- "output": null, // Required: null on creation
110
- "error": null, // Required: null on creation
111
- "createdAt": 1234567890, // Required: Unix timestamp ms
112
- "timeoutMS": 30000, // Optional: Workflow timeout
113
- "deadlineEpochMS": 1234567890, // Optional: Absolute deadline
114
- "deduplicationID": "string", // Optional: For queue deduplication
115
- "priority": 0, // Required: Queue priority (0 = highest)
116
- "queuePartitionKey": "string", // Optional: Partition key
117
- "forkedFrom": "string", // Optional: Parent workflow ID
118
- "ownerXid": "string | null", // Required: Transaction ID
119
- "options": {
120
- "isRecoveryRequest": false, // Optional
121
- "isDequeuedRequest": false, // Optional
122
- "maxRetries": 100 // Optional
123
- }
124
- }
125
- ```
126
-
127
- **Response 200/201:**
128
-
129
- ```json
130
- {
131
- "status": "PENDING", // Current status after creation
132
- "shouldExecuteOnThisExecutor": true, // Whether this executor should run it
133
- "deadlineEpochMS": 1234567890 // Optional: Calculated deadline
134
- }
135
- ```
136
-
137
- **Atomicity**: This endpoint must be atomic. If a workflow with the same UUID exists:
138
-
139
- - Return `shouldExecuteOnThisExecutor: false` if another executor is handling it
140
- - Return 409 if there's a true conflict
141
-
142
- ---
143
-
144
- ### Get Workflow Status
145
-
146
- #### GET /workflows/{workflowID}
147
-
148
- Retrieve workflow status.
149
-
150
- **Path Parameters:**
151
-
152
- - `workflowID` (string, URL-encoded): Workflow UUID
153
-
154
- **Query Parameters:**
155
-
156
- - `callerID` (string, optional): Calling workflow's ID
157
- - `callerFN` (number, optional): Calling workflow's function ID
158
-
159
- **Response 200:**
160
-
161
- ```json
162
- {
163
- "workflowUUID": "string",
164
- "status": "PENDING | SUCCESS | ERROR | CANCELLED | ENQUEUED | MAX_RECOVERY_ATTEMPTS_EXCEEDED",
165
- "workflowName": "string",
166
- "workflowClassName": "string",
167
- "workflowConfigName": "string",
168
- "queueName": "string | null",
169
- "authenticatedUser": "string",
170
- "assumedRole": "string",
171
- "authenticatedRoles": ["string"],
172
- "request": {},
173
- "executorId": "string",
174
- "applicationVersion": "string",
175
- "applicationID": "string",
176
- "input": "string | null", // Serialized JSON
177
- "output": "string | null", // Serialized JSON
178
- "error": "string | null", // Serialized error
179
- "createdAt": 1234567890,
180
- "updatedAt": 1234567890,
181
- "recoveryAttempts": 0,
182
- "timeoutMS": 30000,
183
- "deadlineEpochMS": 1234567890,
184
- "deduplicationID": "string",
185
- "priority": 0,
186
- "queuePartitionKey": "string",
187
- "forkedFrom": "string"
188
- }
189
- ```
190
-
191
- **Response 404** (workflow not found):
192
-
193
- ```json
194
- {
195
- "message": "Workflow not found",
196
- "type": "workflow_not_found"
197
- }
198
- ```
199
-
200
- ---
201
-
202
- ### List Workflows
203
-
204
- #### GET /workflows
205
-
206
- List workflows with optional filters.
207
-
208
- **Query Parameters:**
209
-
210
- - `workflowName` (string): Filter by workflow name
211
- - `authenticatedUser` (string): Filter by user
212
- - `startTime` (string): RFC 3339 timestamp, workflows created after
213
- - `endTime` (string): RFC 3339 timestamp, workflows created before
214
- - `status` (string): Filter by status
215
- - `applicationVersion` (string): Filter by app version
216
- - `workflowID` (string): Filter by workflow ID (exact or prefix match)
217
- - `limit` (number): Max results (default: 100)
218
- - `offset` (number): Pagination offset
219
- - `sortAscending` (boolean): Sort order (default: false = descending)
220
-
221
- **Response 200:**
222
-
223
- ```json
224
- [
225
- {
226
- "workflowUUID": "string",
227
- "status": "string"
228
- // ... full WorkflowStatusInternal object
229
- }
230
- ]
231
- ```
232
-
233
- ---
234
-
235
- ### Record Workflow Output
236
-
237
- #### PUT /workflows/{workflowID}/output
238
-
239
- Record successful workflow completion.
240
-
241
- **Path Parameters:**
242
-
243
- - `workflowID` (string): Workflow UUID
244
-
245
- **Request Body:**
246
-
247
- ```json
248
- {
249
- "output": "string", // Serialized JSON output
250
- "status": "SUCCESS" // New status
251
- }
252
- ```
253
-
254
- **Response 200:**
255
-
256
- ```json
257
- {}
258
- ```
259
-
260
- ---
261
-
262
- ### Record Workflow Error
263
-
264
- #### PUT /workflows/{workflowID}/error
265
-
266
- Record workflow failure.
267
-
268
- **Path Parameters:**
269
-
270
- - `workflowID` (string): Workflow UUID
271
-
272
- **Request Body:**
273
-
274
- ```json
275
- {
276
- "error": "string", // Serialized error
277
- "status": "ERROR" // New status
278
- }
279
- ```
280
-
281
- **Response 200:**
282
-
283
- ```json
284
- {}
285
- ```
286
-
287
- ---
288
-
289
- ### Get Workflow Result (Polling)
290
-
291
- #### GET /workflows/{workflowID}/result
292
-
293
- Get workflow result for polling. SDK polls this endpoint until workflow completes.
294
-
295
- **Path Parameters:**
296
-
297
- - `workflowID` (string): Workflow UUID
298
-
299
- **Query Parameters:**
300
-
301
- - `callerID` (string, optional): Calling workflow's ID
302
- - `timerFuncID` (number, optional): Timer function ID
303
-
304
- **Response 200** (workflow complete):
305
-
306
- ```json
307
- {
308
- "output": "string | null", // Serialized output
309
- "error": "string | null", // Serialized error
310
- "cancelled": false
311
- }
312
- ```
313
-
314
- **Response 200** (workflow still pending):
315
-
316
- ```json
317
- null
318
- ```
319
-
320
- **Polling**: SDK polls every 1000ms. Consider implementing long-polling or returning immediately if result is ready.
321
-
322
- ---
323
-
324
- ### Get Pending Workflows
325
-
326
- #### GET /workflows/pending
327
-
328
- Get workflows that need recovery.
329
-
330
- **Query Parameters:**
331
-
332
- - `executorId` (string, required): Executor ID
333
- - `appVersion` (string, required): Application version
334
-
335
- **Response 200:**
336
-
337
- ```json
338
- [
339
- {
340
- "workflowUUID": "string",
341
- "queueName": "string | null"
342
- }
343
- ]
344
- ```
345
-
346
- ---
347
-
348
- ### Set Workflow Status
349
-
350
- #### PUT /workflows/{workflowID}/status
351
-
352
- Update workflow status.
353
-
354
- **Path Parameters:**
355
-
356
- - `workflowID` (string): Workflow UUID
357
-
358
- **Request Body:**
359
-
360
- ```json
361
- {
362
- "status": "PENDING | SUCCESS | ERROR | CANCELLED | ENQUEUED | MAX_RECOVERY_ATTEMPTS_EXCEEDED",
363
- "resetRecoveryAttempts": false
364
- }
365
- ```
366
-
367
- **Response 200:**
368
-
369
- ```json
370
- {}
371
- ```
372
-
373
- ---
374
-
375
- ### Cancel Workflow
376
-
377
- #### POST /workflows/{workflowID}/cancel
378
-
379
- Cancel a running workflow.
380
-
381
- **Path Parameters:**
382
-
383
- - `workflowID` (string): Workflow UUID
384
-
385
- **Request Body:**
386
-
387
- ```json
388
- {}
389
- ```
390
-
391
- **Response 200:**
392
-
393
- ```json
394
- {}
395
- ```
396
-
397
- **Side Effects**: Must update workflow status to "CANCELLED" and notify any waiting operations.
398
-
399
- ---
400
-
401
- ### Resume Workflow
402
-
403
- #### POST /workflows/{workflowID}/resume
404
-
405
- Resume a cancelled workflow.
406
-
407
- **Path Parameters:**
408
-
409
- - `workflowID` (string): Workflow UUID
410
-
411
- **Request Body:**
412
-
413
- ```json
414
- {}
415
- ```
416
-
417
- **Response 200:**
418
-
419
- ```json
420
- {}
421
- ```
422
-
423
- ---
424
-
425
- ### Fork Workflow
426
-
427
- #### POST /workflows/{workflowID}/fork
428
-
429
- Create a new workflow from an existing one, starting at a specific step.
430
-
431
- **Path Parameters:**
432
-
433
- - `workflowID` (string): Source workflow UUID
434
-
435
- **Request Body:**
436
-
437
- ```json
438
- {
439
- "startStep": 0, // Step number to start from
440
- "newWorkflowID": "string", // Optional: New workflow ID
441
- "applicationVersion": "string", // Optional: App version
442
- "timeoutMS": 30000 // Optional: New timeout
443
- }
444
- ```
445
-
446
- **Response 200:**
447
-
448
- ```json
449
- {
450
- "newWorkflowID": "string"
451
- }
452
- ```
453
-
454
- ---
455
-
456
- ### Check If Cancelled
457
-
458
- #### GET /workflows/{workflowID}/cancelled
459
-
460
- Check if workflow has been cancelled.
461
-
462
- **Path Parameters:**
463
-
464
- - `workflowID` (string): Workflow UUID
465
-
466
- **Response 200:**
467
-
468
- ```json
469
- {
470
- "cancelled": true | false
471
- }
472
- ```
473
-
474
- ---
475
-
476
- ## Operation Endpoints
477
-
478
- Operations are individual steps within a workflow.
479
-
480
- ### Get Operation Result
481
-
482
- #### GET /workflows/{workflowID}/operations/{functionID}
483
-
484
- Get a specific operation's result.
485
-
486
- **Path Parameters:**
487
-
488
- - `workflowID` (string): Workflow UUID
489
- - `functionID` (number): Function/step ID
490
-
491
- **Response 200** (operation exists):
492
-
493
- ```json
494
- {
495
- "output": "string | null", // Serialized output
496
- "error": "string | null", // Serialized error
497
- "cancelled": false,
498
- "childWorkflowID": "string | null",
499
- "functionName": "string"
500
- }
501
- ```
502
-
503
- **Response 200** (operation not recorded yet):
504
-
505
- ```json
506
- null
507
- ```
508
-
509
- ---
510
-
511
- ### Get All Operation Results
512
-
513
- #### GET /workflows/{workflowID}/operations
514
-
515
- Get all operations for a workflow.
516
-
517
- **Path Parameters:**
518
-
519
- - `workflowID` (string): Workflow UUID
520
-
521
- **Response 200:**
522
-
523
- ```json
524
- [
525
- {
526
- "workflow_uuid": "string",
527
- "function_id": 0,
528
- "output": "string",
529
- "error": "string",
530
- "child_workflow_id": "string",
531
- "function_name": "string",
532
- "started_at_epoch_ms": 1234567890,
533
- "completed_at_epoch_ms": 1234567890
534
- }
535
- ]
536
- ```
537
-
538
- ---
539
-
540
- ### Record Operation Result
541
-
542
- #### POST /workflows/{workflowID}/operations
543
-
544
- Record an operation's completion.
545
-
546
- **Path Parameters:**
547
-
548
- - `workflowID` (string): Workflow UUID
549
-
550
- **Request Body:**
551
-
552
- ```json
553
- {
554
- "functionID": 0, // Required: Step number
555
- "functionName": "string", // Required: Function name
556
- "checkConflict": true, // Required: Check for existing record
557
- "startTimeEpochMs": 1234567890, // Required: When operation started
558
- "endTimeEpochMs": 1234567890, // Required: When operation ended
559
- "output": "string | null", // Optional: Serialized output
560
- "error": "string | null", // Optional: Serialized error
561
- "childWorkflowID": "string | null" // Optional: If operation started a child workflow
562
- }
563
- ```
564
-
565
- **Response 200:**
566
-
567
- ```json
568
- {}
569
- ```
570
-
571
- **Atomicity**: If `checkConflict` is true and a record exists, return 409.
572
-
573
- ---
574
-
575
- ## Queue Endpoints
576
-
577
- ### Clear Queue Assignment
578
-
579
- #### DELETE /workflows/{workflowID}/queue-assignment
580
-
581
- Remove a workflow from its queue assignment.
582
-
583
- **Path Parameters:**
584
-
585
- - `workflowID` (string): Workflow UUID
586
-
587
- **Response 200:**
588
-
589
- ```json
590
- {
591
- "cleared": true
592
- }
593
- ```
594
-
595
- ---
596
-
597
- ### Get Deduplicated Workflow
598
-
599
- #### GET /queues/{queueName}/deduplicated/{deduplicationID}
600
-
601
- Find workflow by deduplication ID.
602
-
603
- **Path Parameters:**
604
-
605
- - `queueName` (string): Queue name
606
- - `deduplicationID` (string): Deduplication ID
607
-
608
- **Response 200:**
609
-
610
- ```json
611
- {
612
- "workflowID": "string | null" // null if no match
613
- }
614
- ```
615
-
616
- ---
617
-
618
- ### Get Queue Partitions
619
-
620
- #### GET /queues/{queueName}/partitions
621
-
622
- Get all partition keys for a queue.
623
-
624
- **Path Parameters:**
625
-
626
- - `queueName` (string): Queue name
627
-
628
- **Response 200:**
629
-
630
- ```json
631
- {
632
- "partitions": ["string"]
633
- }
634
- ```
635
-
636
- ---
637
-
638
- ### Find and Mark Startable Workflows
639
-
640
- #### POST /queues/{queueName}/start-workflows
641
-
642
- Find workflows ready to start and mark them as starting.
643
-
644
- **Path Parameters:**
645
-
646
- - `queueName` (string): Queue name
647
-
648
- **Request Body:**
649
-
650
- ```json
651
- {
652
- "executorID": "string", // Required
653
- "appVersion": "string", // Required
654
- "queuePartitionKey": "string | null", // Optional
655
- "concurrency": 10, // Required: Max concurrent workflows
656
- "rateLimit": {
657
- // Optional: Rate limiting config
658
- "limitPerPeriod": 100,
659
- "periodSec": 60
660
- }
661
- }
662
- ```
663
-
664
- **Response 200:**
665
-
666
- ```json
667
- {
668
- "workflowIDs": ["string"] // Workflows that should be started
669
- }
670
- ```
671
-
672
- **Atomicity**: This operation MUST be atomic (use transactions). It should:
673
-
674
- 1. Find eligible workflows (ENQUEUED status, respecting concurrency/rate limits)
675
- 2. Update their status to PENDING
676
- 3. Return their IDs
677
-
678
- ---
679
-
680
- ## Messaging Endpoints
681
-
682
- ### Send Message
683
-
684
- #### POST /workflows/{destinationID}/messages
685
-
686
- Send a message to a workflow.
687
-
688
- **Path Parameters:**
689
-
690
- - `destinationID` (string): Destination workflow UUID
691
-
692
- **Request Body:**
693
-
694
- ```json
695
- {
696
- "senderWorkflowID": "string", // Required: Sender's workflow ID
697
- "functionID": 0, // Required: Sender's function ID
698
- "message": "string | null", // Required: Message content (serialized)
699
- "topic": "string" // Optional: Message topic
700
- }
701
- ```
702
-
703
- **Response 200:**
704
-
705
- ```json
706
- {}
707
- ```
708
-
709
- **Side Effects**: Must wake up any `recv` polling for this destination+topic.
710
-
711
- ---
712
-
713
- ### Receive Message (Polling)
714
-
715
- #### GET /workflows/{workflowID}/messages
716
-
717
- Check for messages. SDK polls this endpoint.
718
-
719
- **Path Parameters:**
720
-
721
- - `workflowID` (string): Workflow UUID
722
-
723
- **Query Parameters:**
724
-
725
- - `topic` (string, optional): Filter by topic
726
- - `functionID` (number, required): Receiver's function ID
727
- - `timeoutFunctionID` (number, required): Timeout function ID
728
-
729
- **Response 200** (message available):
730
-
731
- ```json
732
- {
733
- "message": "string | null",
734
- "found": true
735
- }
736
- ```
737
-
738
- **Response 200** (no message yet):
739
-
740
- ```json
741
- {
742
- "message": null,
743
- "found": false
744
- }
745
- ```
746
-
747
- **Polling**: SDK polls every 1000ms with timeout. Consider long-polling.
748
-
749
- ---
750
-
751
- ### Durable Sleep
752
-
753
- #### POST /workflows/{workflowID}/sleep
754
-
755
- Record a durable sleep operation.
756
-
757
- **Path Parameters:**
758
-
759
- - `workflowID` (string): Workflow UUID
760
-
761
- **Request Body:**
762
-
763
- ```json
764
- {
765
- "functionID": 0, // Required: Function ID
766
- "duration": 5000, // Required: Sleep duration ms
767
- "wakeupTime": 1234567890 // Required: Wakeup timestamp ms
768
- }
769
- ```
770
-
771
- **Response 200:**
772
-
773
- ```json
774
- {}
775
- ```
776
-
777
- ---
778
-
779
- ## Event Endpoints
780
-
781
- ### Set Event
782
-
783
- #### PUT /workflows/{workflowID}/events/{key}
784
-
785
- Set an event value.
786
-
787
- **Path Parameters:**
788
-
789
- - `workflowID` (string): Workflow UUID
790
- - `key` (string): Event key
791
-
792
- **Request Body:**
793
-
794
- ```json
795
- {
796
- "functionID": 0, // Required
797
- "value": "string | null" // Required: Serialized value
798
- }
799
- ```
800
-
801
- **Response 200:**
802
-
803
- ```json
804
- {}
805
- ```
806
-
807
- **Side Effects**: Must wake up any `getEvent` polling for this workflow+key.
808
-
809
- ---
810
-
811
- ### Get Event (Polling)
812
-
813
- #### GET /workflows/{workflowID}/events/{key}
814
-
815
- Get an event value. SDK polls this endpoint.
816
-
817
- **Path Parameters:**
818
-
819
- - `workflowID` (string): Workflow UUID
820
- - `key` (string): Event key
821
-
822
- **Query Parameters:**
823
-
824
- - `callerWorkflowID` (string, optional): Caller's workflow ID
825
- - `callerFunctionID` (number, optional): Caller's function ID
826
- - `callerTimeoutFunctionID` (number, optional): Caller's timeout function ID
827
-
828
- **Response 200** (event set):
829
-
830
- ```json
831
- {
832
- "value": "string | null",
833
- "found": true
834
- }
835
- ```
836
-
837
- **Response 200** (event not set):
838
-
839
- ```json
840
- {
841
- "value": null,
842
- "found": false
843
- }
844
- ```
845
-
846
- **Polling**: SDK polls every 1000ms with timeout. Consider long-polling.
847
-
848
- ---
849
-
850
- ## Event Dispatch Endpoints
851
-
852
- ### Get Event Dispatch State
853
-
854
- #### GET /event-dispatch/{service}/{workflowFnName}/{key}
855
-
856
- Get external event dispatch state.
857
-
858
- **Path Parameters:**
859
-
860
- - `service` (string): Service name
861
- - `workflowFnName` (string): Workflow function name
862
- - `key` (string): State key
863
-
864
- **Response 200:**
865
-
866
- ```json
867
- {
868
- "service_name": "string",
869
- "workflow_fn_name": "string",
870
- "key": "string",
871
- "value": "string",
872
- "update_time": 1234567890,
873
- "update_seq": 123
874
- }
875
- ```
876
-
877
- **Response 404** (not found):
878
-
879
- ```json
880
- null
881
- ```
882
-
883
- ---
884
-
885
- ### Upsert Event Dispatch State
886
-
887
- #### PUT /event-dispatch
888
-
889
- Create or update event dispatch state.
890
-
891
- **Request Body:**
892
-
893
- ```json
894
- {
895
- "service_name": "string", // Required
896
- "workflow_fn_name": "string", // Required
897
- "key": "string", // Required
898
- "value": "string", // Optional
899
- "update_time": 1234567890, // Optional
900
- "update_seq": 123 // Optional
901
- }
902
- ```
903
-
904
- **Response 200:**
905
-
906
- ```json
907
- {
908
- "service_name": "string",
909
- "workflow_fn_name": "string",
910
- "key": "string",
911
- "value": "string",
912
- "update_time": 1234567890,
913
- "update_seq": 123
914
- }
915
- ```
916
-
917
- **Atomicity**: Upsert must be atomic with optimistic locking on `update_seq`.
918
-
919
- ---
920
-
921
- ## Stream Endpoints
922
-
923
- ### Write to Stream
924
-
925
- #### POST /workflows/{workflowID}/streams/{key}
926
-
927
- Write a value to a stream.
928
-
929
- **Path Parameters:**
930
-
931
- - `workflowID` (string): Workflow UUID
932
- - `key` (string): Stream key
933
-
934
- **Request Body:**
935
-
936
- ```json
937
- {
938
- "fromWorkflow": true, // Required: true if from workflow, false if from step
939
- "functionID": 0, // Required if fromWorkflow is true
940
- "value": {} // Required: Value to write (any JSON)
941
- }
942
- ```
943
-
944
- **Response 200:**
945
-
946
- ```json
947
- {}
948
- ```
949
-
950
- ---
951
-
952
- ### Close Stream
953
-
954
- #### POST /workflows/{workflowID}/streams/{key}/close
955
-
956
- Close a stream.
957
-
958
- **Path Parameters:**
959
-
960
- - `workflowID` (string): Workflow UUID
961
- - `key` (string): Stream key
962
-
963
- **Request Body:**
964
-
965
- ```json
966
- {
967
- "functionID": 0 // Required
968
- }
969
- ```
970
-
971
- **Response 200:**
972
-
973
- ```json
974
- {}
975
- ```
976
-
977
- ---
978
-
979
- ### Read from Stream
980
-
981
- #### GET /workflows/{workflowID}/streams/{key}/{offset}
982
-
983
- Read from a stream at a specific offset.
984
-
985
- **Path Parameters:**
986
-
987
- - `workflowID` (string): Workflow UUID
988
- - `key` (string): Stream key
989
- - `offset` (number): Read offset
990
-
991
- **Response 200:**
992
-
993
- ```json
994
- {
995
- "value": {}, // The value at this offset (any JSON)
996
- "closed": false // Whether stream is closed
997
- }
998
- ```
999
-
1000
- If stream is closed and offset is past the end, return `closed: true`.
1001
-
1002
- ---
1003
-
1004
- ## Admin Endpoints
1005
-
1006
- ### Garbage Collect
1007
-
1008
- #### POST /admin/garbage-collect
1009
-
1010
- Clean up old workflow data.
1011
-
1012
- **Request Body:**
1013
-
1014
- ```json
1015
- {
1016
- "cutoffEpochTimestampMs": 1234567890, // Optional: Delete before this time
1017
- "rowsThreshold": 10000 // Optional: Max rows to keep
1018
- }
1019
- ```
1020
-
1021
- **Response 200:**
1022
-
1023
- ```json
1024
- {}
1025
- ```
1026
-
1027
- ---
1028
-
1029
- ### Get Metrics
1030
-
1031
- #### GET /admin/metrics
1032
-
1033
- Get workflow metrics.
1034
-
1035
- **Query Parameters:**
1036
-
1037
- - `startTime` (string, required): RFC 3339 timestamp
1038
- - `endTime` (string, required): RFC 3339 timestamp
1039
-
1040
- **Response 200:**
1041
-
1042
- ```json
1043
- [
1044
- {
1045
- "metricType": "string",
1046
- "metricName": "string",
1047
- "value": 123
1048
- }
1049
- ]
1050
- ```
1051
-
1052
- ---
1053
-
1054
- ### Check Patch
1055
-
1056
- #### GET /workflows/{workflowID}/patch/{functionID}
1057
-
1058
- Check if a function has been patched.
1059
-
1060
- **Path Parameters:**
1061
-
1062
- - `workflowID` (string): Workflow UUID
1063
- - `functionID` (number): Function ID
1064
-
1065
- **Query Parameters:**
1066
-
1067
- - `patchName` (string, required): Name of the patch
1068
- - `deprecated` (boolean, required): Whether checking for deprecated patch
1069
-
1070
- **Response 200:**
1071
-
1072
- ```json
1073
- {
1074
- "isPatched": false,
1075
- "hasEntry": false
1076
- }
1077
- ```
1078
-
1079
- ---
1080
-
1081
- ## Implementation Notes
1082
-
1083
- ### Atomicity Requirements
1084
-
1085
- The following endpoints require atomic/transactional implementation:
1086
-
1087
- 1. **POST /workflows** - Conflict detection and status assignment must be atomic
1088
- 2. **POST /workflows/{id}/operations** - When `checkConflict` is true
1089
- 3. **POST /queues/{name}/start-workflows** - Finding and marking must be atomic
1090
- 4. **PUT /event-dispatch** - Optimistic locking on `update_seq`
1091
-
1092
- ### Polling Endpoints
1093
-
1094
- These endpoints are polled by the SDK:
1095
-
1096
- | Endpoint | Poll Interval | Notes |
1097
- | -------------------------------- | ------------- | --------------------------------- |
1098
- | GET /workflows/{id}/result | 1000ms | Until workflow completes |
1099
- | GET /workflows/{id}/messages | 1000ms | Until message received or timeout |
1100
- | GET /workflows/{id}/events/{key} | 1000ms | Until event set or timeout |
1101
-
1102
- Consider implementing long-polling (hold connection until data available or timeout) to reduce request overhead.
1103
-
1104
- ### Serialization
1105
-
1106
- All `input`, `output`, `error`, `value`, and `message` fields contain serialized JSON strings. The SDK uses `superjson` for serialization which supports:
1107
-
1108
- - Date objects
1109
- - BigInt
1110
- - Map/Set
1111
- - undefined
1112
- - Regular expressions
1113
- - Custom class instances (with registration)
1114
-
1115
- The backend should store these as opaque strings and return them unchanged.
1116
-
1117
- ### Status Values
1118
-
1119
- Valid workflow statuses:
1120
-
1121
- - `PENDING` - Workflow is running
1122
- - `SUCCESS` - Completed successfully
1123
- - `ERROR` - Completed with error
1124
- - `ENQUEUED` - Waiting in queue
1125
- - `CANCELLED` - Cancelled by user
1126
- - `MAX_RECOVERY_ATTEMPTS_EXCEEDED` - Failed after max retries
1127
-
1128
- ---
1129
-
1130
- ## Database Schema for Laravel
1131
-
1132
- Laravel must implement the database tables that store workflow state. This section documents the required schema.
1133
-
1134
- ### Table: workflow_status
1135
-
1136
- Primary table for workflow state.
1137
-
1138
- ```sql
1139
- CREATE TABLE workflow_status (
1140
- workflow_uuid VARCHAR(255) PRIMARY KEY,
1141
- status VARCHAR(50) NOT NULL,
1142
- name VARCHAR(255) NOT NULL, -- workflowName
1143
- class_name VARCHAR(255), -- workflowClassName
1144
- config_name VARCHAR(255), -- workflowConfigName
1145
- authenticated_user VARCHAR(255) NOT NULL DEFAULT '',
1146
- output TEXT, -- Serialized JSON
1147
- error TEXT, -- Serialized error
1148
- assumed_role VARCHAR(255) NOT NULL DEFAULT '',
1149
- authenticated_roles TEXT NOT NULL DEFAULT '[]', -- Serialized JSON array
1150
- request TEXT NOT NULL DEFAULT '{}', -- Serialized JSON object
1151
- executor_id VARCHAR(255) NOT NULL,
1152
- application_version VARCHAR(255),
1153
- queue_name VARCHAR(255),
1154
- created_at BIGINT NOT NULL, -- Unix timestamp ms
1155
- updated_at BIGINT NOT NULL, -- Unix timestamp ms
1156
- application_id VARCHAR(255) NOT NULL,
1157
- recovery_attempts INT NOT NULL DEFAULT 0,
1158
- workflow_timeout_ms BIGINT,
1159
- workflow_deadline_epoch_ms BIGINT,
1160
- inputs TEXT, -- Serialized JSON
1161
- started_at_epoch_ms BIGINT,
1162
- deduplication_id VARCHAR(255),
1163
- priority INT NOT NULL DEFAULT 0,
1164
- queue_partition_key VARCHAR(255),
1165
- forked_from VARCHAR(255),
1166
- owner_xid VARCHAR(255),
1167
-
1168
- -- Indexes for common queries
1169
- INDEX idx_status (status),
1170
- INDEX idx_executor (executor_id),
1171
- INDEX idx_created_at (created_at),
1172
- INDEX idx_queue_name (queue_name),
1173
- INDEX idx_deduplication (queue_name, deduplication_id),
1174
- INDEX idx_pending_recovery (status, executor_id, application_version)
1175
- );
1176
- ```
1177
-
1178
- ### Table: operation_outputs
1179
-
1180
- Stores results of individual workflow steps/operations.
1181
-
1182
- ```sql
1183
- CREATE TABLE operation_outputs (
1184
- workflow_uuid VARCHAR(255) NOT NULL,
1185
- function_id INT NOT NULL,
1186
- output TEXT, -- Serialized JSON
1187
- error TEXT, -- Serialized error
1188
- child_workflow_id VARCHAR(255),
1189
- function_name VARCHAR(255),
1190
- started_at_epoch_ms BIGINT,
1191
- completed_at_epoch_ms BIGINT,
1192
-
1193
- PRIMARY KEY (workflow_uuid, function_id),
1194
- FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE,
1195
- INDEX idx_child_workflow (child_workflow_id)
1196
- );
1197
- ```
1198
-
1199
- ### Table: notifications
1200
-
1201
- Stores messages sent between workflows.
1202
-
1203
- ```sql
1204
- CREATE TABLE notifications (
1205
- id BIGINT AUTO_INCREMENT PRIMARY KEY,
1206
- destination_uuid VARCHAR(255) NOT NULL,
1207
- topic VARCHAR(255),
1208
- message TEXT, -- Serialized JSON
1209
- created_at BIGINT NOT NULL,
1210
- consumed BOOLEAN NOT NULL DEFAULT FALSE,
1211
-
1212
- INDEX idx_destination_topic (destination_uuid, topic, consumed),
1213
- FOREIGN KEY (destination_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
1214
- );
1215
- ```
1216
-
1217
- ### Table: workflow_events
1218
-
1219
- Stores key-value events set by workflows.
1220
-
1221
- ```sql
1222
- CREATE TABLE workflow_events (
1223
- workflow_uuid VARCHAR(255) NOT NULL,
1224
- key VARCHAR(255) NOT NULL,
1225
- value TEXT, -- Serialized JSON
1226
-
1227
- PRIMARY KEY (workflow_uuid, key),
1228
- FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
1229
- );
1230
- ```
1231
-
1232
- ### Table: event_dispatch_kv
1233
-
1234
- Stores external event dispatch state for idempotency.
1235
-
1236
- ```sql
1237
- CREATE TABLE event_dispatch_kv (
1238
- service_name VARCHAR(255) NOT NULL,
1239
- workflow_fn_name VARCHAR(255) NOT NULL,
1240
- key VARCHAR(255) NOT NULL,
1241
- value TEXT, -- Serialized JSON
1242
- update_time BIGINT,
1243
- update_seq BIGINT,
1244
-
1245
- PRIMARY KEY (service_name, workflow_fn_name, key),
1246
- INDEX idx_update_seq (update_seq)
1247
- );
1248
- ```
1249
-
1250
- ### Table: workflow_streams
1251
-
1252
- Stores stream data for workflow streaming.
1253
-
1254
- ```sql
1255
- CREATE TABLE workflow_streams (
1256
- workflow_uuid VARCHAR(255) NOT NULL,
1257
- key VARCHAR(255) NOT NULL,
1258
- offset INT NOT NULL,
1259
- value TEXT NOT NULL, -- Serialized JSON
1260
- is_closed BOOLEAN NOT NULL DEFAULT FALSE,
1261
-
1262
- PRIMARY KEY (workflow_uuid, key, offset),
1263
- FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
1264
- );
1265
- ```
1266
-
1267
- ### Table: workflow_queue_state (Optional)
1268
-
1269
- For tracking queue concurrency and rate limiting. Can be managed in-memory if preferred.
1270
-
1271
- ```sql
1272
- CREATE TABLE workflow_queue_state (
1273
- queue_name VARCHAR(255) NOT NULL,
1274
- partition_key VARCHAR(255) NOT NULL DEFAULT '',
1275
- running_count INT NOT NULL DEFAULT 0,
1276
- last_started_at BIGINT,
1277
-
1278
- PRIMARY KEY (queue_name, partition_key)
1279
- );
1280
- ```
1281
-
1282
- ### Laravel Migration Example
1283
-
1284
- ```php
1285
- <?php
1286
-
1287
- use Illuminate\Database\Migrations\Migration;
1288
- use Illuminate\Database\Schema\Blueprint;
1289
- use Illuminate\Support\Facades\Schema;
1290
-
1291
- return new class extends Migration
1292
- {
1293
- public function up(): void
1294
- {
1295
- Schema::create('workflow_status', function (Blueprint $table) {
1296
- $table->string('workflow_uuid')->primary();
1297
- $table->string('status', 50);
1298
- $table->string('name');
1299
- $table->string('class_name')->nullable();
1300
- $table->string('config_name')->nullable();
1301
- $table->string('authenticated_user')->default('');
1302
- $table->text('output')->nullable();
1303
- $table->text('error')->nullable();
1304
- $table->string('assumed_role')->default('');
1305
- $table->text('authenticated_roles')->default('[]');
1306
- $table->text('request')->default('{}');
1307
- $table->string('executor_id');
1308
- $table->string('application_version')->nullable();
1309
- $table->string('queue_name')->nullable();
1310
- $table->bigInteger('created_at');
1311
- $table->bigInteger('updated_at');
1312
- $table->string('application_id');
1313
- $table->integer('recovery_attempts')->default(0);
1314
- $table->bigInteger('workflow_timeout_ms')->nullable();
1315
- $table->bigInteger('workflow_deadline_epoch_ms')->nullable();
1316
- $table->text('inputs')->nullable();
1317
- $table->bigInteger('started_at_epoch_ms')->nullable();
1318
- $table->string('deduplication_id')->nullable();
1319
- $table->integer('priority')->default(0);
1320
- $table->string('queue_partition_key')->nullable();
1321
- $table->string('forked_from')->nullable();
1322
- $table->string('owner_xid')->nullable();
1323
-
1324
- $table->index('status');
1325
- $table->index('executor_id');
1326
- $table->index('created_at');
1327
- $table->index('queue_name');
1328
- $table->index(['queue_name', 'deduplication_id']);
1329
- $table->index(['status', 'executor_id', 'application_version']);
1330
- });
1331
-
1332
- Schema::create('operation_outputs', function (Blueprint $table) {
1333
- $table->string('workflow_uuid');
1334
- $table->integer('function_id');
1335
- $table->text('output')->nullable();
1336
- $table->text('error')->nullable();
1337
- $table->string('child_workflow_id')->nullable();
1338
- $table->string('function_name')->nullable();
1339
- $table->bigInteger('started_at_epoch_ms')->nullable();
1340
- $table->bigInteger('completed_at_epoch_ms')->nullable();
1341
-
1342
- $table->primary(['workflow_uuid', 'function_id']);
1343
- $table->foreign('workflow_uuid')
1344
- ->references('workflow_uuid')
1345
- ->on('workflow_status')
1346
- ->onDelete('cascade');
1347
- $table->index('child_workflow_id');
1348
- });
1349
-
1350
- Schema::create('notifications', function (Blueprint $table) {
1351
- $table->id();
1352
- $table->string('destination_uuid');
1353
- $table->string('topic')->nullable();
1354
- $table->text('message')->nullable();
1355
- $table->bigInteger('created_at');
1356
- $table->boolean('consumed')->default(false);
1357
-
1358
- $table->index(['destination_uuid', 'topic', 'consumed']);
1359
- $table->foreign('destination_uuid')
1360
- ->references('workflow_uuid')
1361
- ->on('workflow_status')
1362
- ->onDelete('cascade');
1363
- });
1364
-
1365
- Schema::create('workflow_events', function (Blueprint $table) {
1366
- $table->string('workflow_uuid');
1367
- $table->string('key');
1368
- $table->text('value')->nullable();
1369
-
1370
- $table->primary(['workflow_uuid', 'key']);
1371
- $table->foreign('workflow_uuid')
1372
- ->references('workflow_uuid')
1373
- ->on('workflow_status')
1374
- ->onDelete('cascade');
1375
- });
1376
-
1377
- Schema::create('event_dispatch_kv', function (Blueprint $table) {
1378
- $table->string('service_name');
1379
- $table->string('workflow_fn_name');
1380
- $table->string('key');
1381
- $table->text('value')->nullable();
1382
- $table->bigInteger('update_time')->nullable();
1383
- $table->bigInteger('update_seq')->nullable();
1384
-
1385
- $table->primary(['service_name', 'workflow_fn_name', 'key']);
1386
- $table->index('update_seq');
1387
- });
1388
-
1389
- Schema::create('workflow_streams', function (Blueprint $table) {
1390
- $table->string('workflow_uuid');
1391
- $table->string('key');
1392
- $table->integer('offset');
1393
- $table->text('value');
1394
- $table->boolean('is_closed')->default(false);
1395
-
1396
- $table->primary(['workflow_uuid', 'key', 'offset']);
1397
- $table->foreign('workflow_uuid')
1398
- ->references('workflow_uuid')
1399
- ->on('workflow_status')
1400
- ->onDelete('cascade');
1401
- });
1402
- }
1403
-
1404
- public function down(): void
1405
- {
1406
- Schema::dropIfExists('workflow_streams');
1407
- Schema::dropIfExists('event_dispatch_kv');
1408
- Schema::dropIfExists('workflow_events');
1409
- Schema::dropIfExists('notifications');
1410
- Schema::dropIfExists('operation_outputs');
1411
- Schema::dropIfExists('workflow_status');
1412
- }
1413
- };
1414
- ```
1415
-
1416
- ### Key Implementation Notes for Laravel
1417
-
1418
- 1. **Atomic Operations**: Use database transactions for:
1419
-
1420
- - `POST /workflows` - Check-and-insert must be atomic
1421
- - `POST /queues/{name}/start-workflows` - Finding and updating must be atomic
1422
- - `PUT /event-dispatch` - Optimistic locking on `update_seq`
1423
-
1424
- 2. **Soft Real-time**: For polling endpoints (`/result`, `/messages`, `/events`), consider:
1425
-
1426
- - Long-polling with timeout
1427
- - Or Laravel broadcasting with Pusher/WebSockets
1428
-
1429
- 3. **Cleanup**: The `POST /admin/garbage-collect` endpoint should delete:
1430
-
1431
- - Completed workflows older than `cutoffEpochTimestampMs`
1432
- - Associated operation_outputs, notifications, events, streams
1433
-
1434
- 4. **Serialization**: All `output`, `error`, `value`, `message`, `inputs` fields are opaque JSON strings. Store as TEXT and return unchanged.
1435
-
1436
- ---
1437
-
1438
- ## Version
1439
-
1440
- API Schema Version: 1.0.0
1441
- Generated for DBOS SDK HTTP Transport