@mokronos/wfkit 0.1.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/authoring.d.ts +7 -0
  4. package/dist/authoring.d.ts.map +1 -0
  5. package/dist/authoring.js +8 -0
  6. package/dist/authoring.js.map +1 -0
  7. package/dist/cli/integrations.d.ts +3 -0
  8. package/dist/cli/integrations.d.ts.map +1 -0
  9. package/dist/cli/integrations.js +40 -0
  10. package/dist/cli/integrations.js.map +1 -0
  11. package/dist/cli/main.d.ts +3 -0
  12. package/dist/cli/main.d.ts.map +1 -0
  13. package/dist/cli/main.js +591 -0
  14. package/dist/cli/main.js.map +1 -0
  15. package/dist/core.d.ts +198 -0
  16. package/dist/core.d.ts.map +1 -0
  17. package/dist/core.js +1061 -0
  18. package/dist/core.js.map +1 -0
  19. package/dist/errors.d.ts +3 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +13 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/events.d.ts +154 -0
  24. package/dist/events.d.ts.map +1 -0
  25. package/dist/events.js +24 -0
  26. package/dist/events.js.map +1 -0
  27. package/dist/index.d.ts +15 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +11 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/replay.d.ts +3 -0
  32. package/dist/replay.d.ts.map +1 -0
  33. package/dist/replay.js +28 -0
  34. package/dist/replay.js.map +1 -0
  35. package/dist/runtime.d.ts +70 -0
  36. package/dist/runtime.d.ts.map +1 -0
  37. package/dist/runtime.js +183 -0
  38. package/dist/runtime.js.map +1 -0
  39. package/dist/schema.d.ts +18 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +19 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/schemas.d.ts +1198 -0
  44. package/dist/schemas.d.ts.map +1 -0
  45. package/dist/schemas.js +383 -0
  46. package/dist/schemas.js.map +1 -0
  47. package/dist/sdk/artifact.d.ts +41 -0
  48. package/dist/sdk/artifact.d.ts.map +1 -0
  49. package/dist/sdk/artifact.js +94 -0
  50. package/dist/sdk/artifact.js.map +1 -0
  51. package/dist/sdk/graph.d.ts +15 -0
  52. package/dist/sdk/graph.d.ts.map +1 -0
  53. package/dist/sdk/graph.js +388 -0
  54. package/dist/sdk/graph.js.map +1 -0
  55. package/dist/sdk/index.d.ts +14 -0
  56. package/dist/sdk/index.d.ts.map +1 -0
  57. package/dist/sdk/index.js +8 -0
  58. package/dist/sdk/index.js.map +1 -0
  59. package/dist/sdk/integrations.d.ts +18 -0
  60. package/dist/sdk/integrations.d.ts.map +1 -0
  61. package/dist/sdk/integrations.js +20 -0
  62. package/dist/sdk/integrations.js.map +1 -0
  63. package/dist/sdk/json.d.ts +4 -0
  64. package/dist/sdk/json.d.ts.map +1 -0
  65. package/dist/sdk/json.js +31 -0
  66. package/dist/sdk/json.js.map +1 -0
  67. package/dist/sdk/loader.d.ts +10 -0
  68. package/dist/sdk/loader.d.ts.map +1 -0
  69. package/dist/sdk/loader.js +75 -0
  70. package/dist/sdk/loader.js.map +1 -0
  71. package/dist/sdk/sdk.d.ts +102 -0
  72. package/dist/sdk/sdk.d.ts.map +1 -0
  73. package/dist/sdk/sdk.js +669 -0
  74. package/dist/sdk/sdk.js.map +1 -0
  75. package/dist/sdk/sqlite.d.ts +8 -0
  76. package/dist/sdk/sqlite.d.ts.map +1 -0
  77. package/dist/sdk/sqlite.js +288 -0
  78. package/dist/sdk/sqlite.js.map +1 -0
  79. package/dist/signal.d.ts +17 -0
  80. package/dist/signal.d.ts.map +1 -0
  81. package/dist/signal.js +78 -0
  82. package/dist/signal.js.map +1 -0
  83. package/dist/testing/index.d.ts +35 -0
  84. package/dist/testing/index.d.ts.map +1 -0
  85. package/dist/testing/index.js +244 -0
  86. package/dist/testing/index.js.map +1 -0
  87. package/package.json +67 -0
  88. package/src/authoring.ts +32 -0
  89. package/src/cli/integrations.ts +75 -0
  90. package/src/cli/main.ts +793 -0
  91. package/src/core.ts +1515 -0
  92. package/src/errors.ts +19 -0
  93. package/src/events.ts +37 -0
  94. package/src/index.ts +109 -0
  95. package/src/replay.ts +29 -0
  96. package/src/runtime.ts +314 -0
  97. package/src/schema.ts +34 -0
  98. package/src/schemas.ts +473 -0
  99. package/src/sdk/artifact.ts +176 -0
  100. package/src/sdk/graph.ts +486 -0
  101. package/src/sdk/index.ts +64 -0
  102. package/src/sdk/integrations.ts +49 -0
  103. package/src/sdk/json.ts +40 -0
  104. package/src/sdk/loader.ts +99 -0
  105. package/src/sdk/sdk.ts +911 -0
  106. package/src/sdk/sqlite.ts +405 -0
  107. package/src/signal.ts +116 -0
  108. package/src/testing/index.ts +341 -0
package/src/schemas.ts ADDED
@@ -0,0 +1,473 @@
1
+ import { Schema } from "effect"
2
+
3
+ export const ExecutionId = Schema.String.pipe(Schema.brand("ExecutionId"))
4
+ export type ExecutionId = typeof ExecutionId.Type
5
+
6
+ const OptionalString = Schema.optionalKey(Schema.String)
7
+ const OptionalUnknown = Schema.optionalKey(Schema.Unknown)
8
+
9
+ const JsonSchemaType = Schema.Union([Schema.String, Schema.Array(Schema.String)])
10
+
11
+ export interface JsonSchema {
12
+ readonly type?: string | ReadonlyArray<string>
13
+ readonly const?: Schema.Json
14
+ readonly enum?: ReadonlyArray<Schema.Json>
15
+ readonly anyOf?: ReadonlyArray<JsonSchema>
16
+ readonly oneOf?: ReadonlyArray<JsonSchema>
17
+ readonly items?: JsonSchema
18
+ readonly properties?: { readonly [key: string]: JsonSchema }
19
+ readonly required?: ReadonlyArray<string>
20
+ readonly [key: string]: Schema.Json | JsonSchema | ReadonlyArray<Schema.Json> | ReadonlyArray<JsonSchema> | { readonly [key: string]: JsonSchema } | undefined
21
+ }
22
+
23
+ export const JsonSchema: Schema.Codec<JsonSchema> = Schema.StructWithRest(
24
+ Schema.Struct({
25
+ type: Schema.optionalKey(JsonSchemaType),
26
+ const: Schema.optionalKey(Schema.Json),
27
+ enum: Schema.optionalKey(Schema.Array(Schema.Json)),
28
+ anyOf: Schema.optionalKey(Schema.Array(Schema.suspend((): Schema.Codec<JsonSchema> => JsonSchema))),
29
+ oneOf: Schema.optionalKey(Schema.Array(Schema.suspend((): Schema.Codec<JsonSchema> => JsonSchema))),
30
+ items: Schema.optionalKey(Schema.suspend((): Schema.Codec<JsonSchema> => JsonSchema)),
31
+ properties: Schema.optionalKey(Schema.Record(Schema.String, Schema.suspend((): Schema.Codec<JsonSchema> => JsonSchema))),
32
+ required: Schema.optionalKey(Schema.Array(Schema.String))
33
+ }),
34
+ [Schema.Record(Schema.String, Schema.Json)]
35
+ )
36
+
37
+ export const decodeJsonSchema = (value: unknown): JsonSchema =>
38
+ Schema.decodeUnknownSync(JsonSchema)(value)
39
+
40
+ /** Best-effort JSON Schema for an Effect schema; undefined when the schema
41
+ * has no JSON representation. */
42
+ export const jsonSchemaOf = (schema: unknown): JsonSchema | undefined => {
43
+ try {
44
+ const document = Schema.toJsonSchemaDocument(schema as never) as { readonly schema?: unknown }
45
+ return document.schema === undefined ? undefined : decodeJsonSchema(document.schema)
46
+ } catch {
47
+ return undefined
48
+ }
49
+ }
50
+
51
+ const WorkflowStartedEvent = Schema.Struct({
52
+ type: Schema.Literal("workflow.started"),
53
+ workflowName: Schema.String,
54
+ payload: OptionalUnknown
55
+ })
56
+
57
+ const WorkflowCompletedEvent = Schema.Struct({
58
+ type: Schema.Literal("workflow.completed"),
59
+ workflowName: Schema.String,
60
+ result: OptionalUnknown
61
+ })
62
+
63
+ const WorkflowFailedEvent = Schema.Struct({
64
+ type: Schema.Literal("workflow.failed"),
65
+ workflowName: Schema.String,
66
+ error: OptionalUnknown
67
+ })
68
+
69
+ const StepStartedEvent = Schema.Struct({
70
+ type: Schema.Literal("step.started"),
71
+ executionId: ExecutionId,
72
+ stepName: Schema.String,
73
+ invocation: Schema.Number,
74
+ activityName: Schema.String,
75
+ attempt: Schema.Number,
76
+ input: OptionalUnknown
77
+ })
78
+
79
+ const StepCompletedEvent = Schema.Struct({
80
+ type: Schema.Literal("step.completed"),
81
+ executionId: ExecutionId,
82
+ stepName: Schema.String,
83
+ invocation: Schema.Number,
84
+ activityName: Schema.String,
85
+ attempt: Schema.Number,
86
+ result: OptionalUnknown
87
+ })
88
+
89
+ const StepFailedEvent = Schema.Struct({
90
+ type: Schema.Literal("step.failed"),
91
+ executionId: ExecutionId,
92
+ stepName: Schema.String,
93
+ invocation: Schema.Number,
94
+ activityName: Schema.String,
95
+ error: OptionalUnknown
96
+ })
97
+
98
+ const CompensationStartedEvent = Schema.Struct({
99
+ type: Schema.Literal("compensation.started"),
100
+ executionId: ExecutionId,
101
+ stepName: Schema.String,
102
+ invocation: Schema.Number,
103
+ activityName: Schema.String,
104
+ result: OptionalUnknown,
105
+ input: OptionalUnknown,
106
+ reason: OptionalUnknown
107
+ })
108
+
109
+ const CompensationCompletedEvent = Schema.Struct({
110
+ type: Schema.Literal("compensation.completed"),
111
+ executionId: ExecutionId,
112
+ stepName: Schema.String,
113
+ invocation: Schema.Number,
114
+ activityName: Schema.String
115
+ })
116
+
117
+ const CompensationFailedEvent = Schema.Struct({
118
+ type: Schema.Literal("compensation.failed"),
119
+ executionId: ExecutionId,
120
+ stepName: Schema.String,
121
+ invocation: Schema.Number,
122
+ activityName: Schema.String,
123
+ error: OptionalUnknown
124
+ })
125
+
126
+ const SleepStartedEvent = Schema.Struct({
127
+ type: Schema.Literal("sleep.started"),
128
+ executionId: ExecutionId,
129
+ name: Schema.String,
130
+ invocation: Schema.Number,
131
+ activityName: Schema.String,
132
+ duration: OptionalUnknown
133
+ })
134
+
135
+ const SleepCompletedEvent = Schema.Struct({
136
+ type: Schema.Literal("sleep.completed"),
137
+ executionId: ExecutionId,
138
+ name: Schema.String,
139
+ invocation: Schema.Number,
140
+ activityName: Schema.String,
141
+ duration: OptionalUnknown
142
+ })
143
+
144
+ const SignalWaitingEvent = Schema.Struct({
145
+ type: Schema.Literal("signal.waiting"),
146
+ executionId: ExecutionId,
147
+ name: Schema.String,
148
+ invocation: Schema.Number,
149
+ activityName: Schema.String,
150
+ timeout: OptionalUnknown,
151
+ /** JSON Schema of the payload the wait expects; lets a human or agent see
152
+ * what to send before delivering the signal. */
153
+ payloadSchema: Schema.optionalKey(JsonSchema)
154
+ })
155
+
156
+ const SignalReceivedEvent = Schema.Struct({
157
+ type: Schema.Literal("signal.received"),
158
+ executionId: ExecutionId,
159
+ name: Schema.String,
160
+ invocation: Schema.Number,
161
+ activityName: Schema.String,
162
+ payload: OptionalUnknown
163
+ })
164
+
165
+ const SignalTimeoutEvent = Schema.Struct({
166
+ type: Schema.Literal("signal.timeout"),
167
+ executionId: ExecutionId,
168
+ name: Schema.String,
169
+ invocation: Schema.Number,
170
+ activityName: Schema.String,
171
+ timeout: OptionalUnknown
172
+ })
173
+
174
+ const CodeStartedEvent = Schema.Struct({
175
+ type: Schema.Literal("code.started"),
176
+ executionId: ExecutionId,
177
+ name: Schema.String,
178
+ invocation: Schema.Number,
179
+ activityName: Schema.String,
180
+ reason: OptionalString
181
+ })
182
+
183
+ const CodeCompletedEvent = Schema.Struct({
184
+ type: Schema.Literal("code.completed"),
185
+ executionId: ExecutionId,
186
+ name: Schema.String,
187
+ invocation: Schema.Number,
188
+ activityName: Schema.String,
189
+ reason: OptionalString,
190
+ result: OptionalUnknown
191
+ })
192
+
193
+ const CodeFailedEvent = Schema.Struct({
194
+ type: Schema.Literal("code.failed"),
195
+ executionId: ExecutionId,
196
+ name: Schema.String,
197
+ invocation: Schema.Number,
198
+ activityName: Schema.String,
199
+ reason: OptionalString,
200
+ error: OptionalUnknown
201
+ })
202
+
203
+ const AllStartedEvent = Schema.Struct({
204
+ type: Schema.Literal("all.started"),
205
+ executionId: ExecutionId,
206
+ name: Schema.String,
207
+ invocation: Schema.Number,
208
+ activityName: Schema.String,
209
+ branches: Schema.Number
210
+ })
211
+
212
+ const AllCompletedEvent = Schema.Struct({
213
+ type: Schema.Literal("all.completed"),
214
+ executionId: ExecutionId,
215
+ name: Schema.String,
216
+ invocation: Schema.Number,
217
+ activityName: Schema.String,
218
+ branches: Schema.Number
219
+ })
220
+
221
+ const AllFailedEvent = Schema.Struct({
222
+ type: Schema.Literal("all.failed"),
223
+ executionId: ExecutionId,
224
+ name: Schema.String,
225
+ invocation: Schema.Number,
226
+ activityName: Schema.String,
227
+ branches: Schema.Number,
228
+ error: OptionalUnknown
229
+ })
230
+
231
+ const CancellationReceivedEvent = Schema.Struct({
232
+ type: Schema.Literal("cancellation.received"),
233
+ executionId: ExecutionId,
234
+ compensate: Schema.Boolean,
235
+ actor: OptionalString
236
+ })
237
+
238
+ export const WorkflowEvent = Schema.Union([
239
+ WorkflowStartedEvent,
240
+ WorkflowCompletedEvent,
241
+ WorkflowFailedEvent,
242
+ StepStartedEvent,
243
+ StepCompletedEvent,
244
+ StepFailedEvent,
245
+ CompensationStartedEvent,
246
+ CompensationCompletedEvent,
247
+ CompensationFailedEvent,
248
+ SleepStartedEvent,
249
+ SleepCompletedEvent,
250
+ SignalWaitingEvent,
251
+ SignalReceivedEvent,
252
+ SignalTimeoutEvent,
253
+ CodeStartedEvent,
254
+ CodeCompletedEvent,
255
+ CodeFailedEvent,
256
+ AllStartedEvent,
257
+ AllCompletedEvent,
258
+ AllFailedEvent,
259
+ CancellationReceivedEvent
260
+ ])
261
+ export type WorkflowEvent = typeof WorkflowEvent.Type
262
+ export const isWorkflowEvent = Schema.is(WorkflowEvent)
263
+
264
+ export const HistoryExecutionStarted = Schema.Struct({
265
+ type: Schema.Literal("execution.started"),
266
+ executionId: ExecutionId,
267
+ workflowName: Schema.String,
268
+ version: Schema.Number,
269
+ payload: OptionalUnknown,
270
+ actor: OptionalString
271
+ })
272
+
273
+ export const HistorySignalDelivered = Schema.Struct({
274
+ type: Schema.Literal("signal.delivered"),
275
+ executionId: ExecutionId,
276
+ name: Schema.String,
277
+ payload: OptionalUnknown,
278
+ actor: OptionalString
279
+ })
280
+
281
+ export const HistoryExecutionCancelled = Schema.Struct({
282
+ type: Schema.Literal("execution.cancelled"),
283
+ executionId: ExecutionId,
284
+ compensate: Schema.Boolean,
285
+ actor: OptionalString
286
+ })
287
+
288
+ export const WorkflowHistoryEvent = Schema.Union([
289
+ WorkflowEvent,
290
+ HistoryExecutionStarted,
291
+ HistorySignalDelivered,
292
+ HistoryExecutionCancelled
293
+ ])
294
+ export type WorkflowHistoryEvent = typeof WorkflowHistoryEvent.Type
295
+
296
+ export const WorkflowRunStatus = Schema.Literals(["running", "completed", "failed"])
297
+ export type WorkflowRunStatus = typeof WorkflowRunStatus.Type
298
+
299
+ export const WorkflowArtifact = Schema.Struct({
300
+ id: Schema.String,
301
+ name: Schema.String,
302
+ version: Schema.String,
303
+ source: Schema.String,
304
+ exportName: OptionalString,
305
+ createdAt: OptionalString
306
+ })
307
+ export type WorkflowArtifact = typeof WorkflowArtifact.Type
308
+
309
+ export const WorkflowManifestEntry = Schema.Struct({
310
+ id: Schema.String,
311
+ name: Schema.String,
312
+ version: Schema.String,
313
+ source: OptionalString,
314
+ entrypoint: OptionalString,
315
+ exportName: OptionalString,
316
+ createdAt: OptionalString
317
+ })
318
+ export type WorkflowManifestEntry = typeof WorkflowManifestEntry.Type
319
+
320
+ export const WorkflowManifest = Schema.Struct({
321
+ workflows: Schema.Array(WorkflowManifestEntry)
322
+ })
323
+ export type WorkflowManifest = typeof WorkflowManifest.Type
324
+
325
+ export const WorkflowRunRecord = Schema.Struct({
326
+ id: ExecutionId,
327
+ workflowId: Schema.String,
328
+ workflowVersion: Schema.String,
329
+ status: WorkflowRunStatus,
330
+ input: Schema.Unknown,
331
+ result: OptionalUnknown,
332
+ error: OptionalUnknown,
333
+ startedAt: Schema.String,
334
+ finishedAt: OptionalString
335
+ })
336
+ export type WorkflowRunRecord = typeof WorkflowRunRecord.Type
337
+
338
+ export const WorkflowRunEventRecord = Schema.Struct({
339
+ id: Schema.Number,
340
+ runId: ExecutionId,
341
+ sequence: Schema.Number,
342
+ type: Schema.String,
343
+ event: WorkflowHistoryEvent,
344
+ createdAt: Schema.String
345
+ })
346
+ export type WorkflowRunEventRecord = typeof WorkflowRunEventRecord.Type
347
+
348
+ export const WorkflowGraphNodeKind = Schema.Literals([
349
+ "step",
350
+ "sleep",
351
+ "signal",
352
+ "now",
353
+ "random",
354
+ "code",
355
+ "all",
356
+ "start",
357
+ "end",
358
+ "error"
359
+ ])
360
+ export type WorkflowGraphNodeKind = typeof WorkflowGraphNodeKind.Type
361
+
362
+ export const WorkflowGraphSchemas = Schema.Struct({
363
+ input: Schema.optionalKey(JsonSchema),
364
+ output: Schema.optionalKey(JsonSchema),
365
+ errors: Schema.optionalKey(JsonSchema)
366
+ })
367
+ export type WorkflowGraphSchemas = typeof WorkflowGraphSchemas.Type
368
+
369
+ export const WorkflowGraphNodeSchemas = Schema.Struct({
370
+ input: Schema.optionalKey(JsonSchema),
371
+ output: Schema.optionalKey(JsonSchema),
372
+ errors: Schema.optionalKey(JsonSchema),
373
+ signal: Schema.optionalKey(JsonSchema)
374
+ })
375
+ export type WorkflowGraphNodeSchemas = typeof WorkflowGraphNodeSchemas.Type
376
+
377
+ export const WorkflowGraphNodeMetadata = Schema.Struct({
378
+ activityName: OptionalString,
379
+ input: OptionalUnknown,
380
+ duration: OptionalUnknown,
381
+ timeout: OptionalUnknown,
382
+ branches: Schema.optionalKey(Schema.Number),
383
+ reason: OptionalString,
384
+ retry: Schema.optionalKey(Schema.Struct({
385
+ attempts: Schema.Number,
386
+ backoff: Schema.Literals(["exponential", "none"])
387
+ })),
388
+ concurrency: Schema.optionalKey(Schema.Struct({
389
+ limit: Schema.Number,
390
+ keyed: Schema.Boolean
391
+ })),
392
+ compensates: Schema.optionalKey(Schema.Boolean)
393
+ })
394
+ export type WorkflowGraphNodeMetadata = typeof WorkflowGraphNodeMetadata.Type
395
+
396
+ export const WorkflowGraphNode = Schema.Struct({
397
+ id: Schema.String,
398
+ kind: WorkflowGraphNodeKind,
399
+ label: Schema.String,
400
+ invocation: Schema.optionalKey(Schema.Number),
401
+ repeated: Schema.Boolean,
402
+ description: OptionalString,
403
+ schemas: Schema.optionalKey(WorkflowGraphNodeSchemas),
404
+ metadata: WorkflowGraphNodeMetadata
405
+ })
406
+ export type WorkflowGraphNode = typeof WorkflowGraphNode.Type
407
+
408
+ export const WorkflowGraphEdge = Schema.Struct({
409
+ id: Schema.String,
410
+ source: Schema.String,
411
+ target: Schema.String,
412
+ label: OptionalString
413
+ })
414
+ export type WorkflowGraphEdge = typeof WorkflowGraphEdge.Type
415
+
416
+ export const WorkflowGraphCall = Schema.Struct({
417
+ kind: WorkflowGraphNodeKind,
418
+ name: Schema.String,
419
+ counter: Schema.Number,
420
+ branches: Schema.optionalKey(Schema.Number)
421
+ })
422
+
423
+ export const WorkflowGraph = Schema.Struct({
424
+ workflowName: Schema.String,
425
+ version: Schema.Number,
426
+ engineName: OptionalString,
427
+ sourceHash: OptionalString,
428
+ schemas: Schema.optionalKey(WorkflowGraphSchemas),
429
+ nodes: Schema.Array(WorkflowGraphNode),
430
+ edges: Schema.Array(WorkflowGraphEdge),
431
+ calls: Schema.Array(WorkflowGraphCall),
432
+ diagnostics: Schema.Array(Schema.String)
433
+ })
434
+ export type WorkflowGraph = typeof WorkflowGraph.Type
435
+
436
+ export const WorkflowArtifactGraph = Schema.Struct({
437
+ artifact: WorkflowArtifact,
438
+ exportName: OptionalString,
439
+ graph: Schema.optionalKey(WorkflowGraph),
440
+ diagnostics: Schema.Array(Schema.String)
441
+ })
442
+ export type WorkflowArtifactGraph = typeof WorkflowArtifactGraph.Type
443
+
444
+ export const WorkflowsResponse = Schema.Struct({
445
+ generatedAt: Schema.String,
446
+ workflows: Schema.Array(WorkflowArtifactGraph),
447
+ error: OptionalString
448
+ })
449
+ export type WorkflowsResponse = typeof WorkflowsResponse.Type
450
+
451
+ export const RunsResponse = Schema.Struct({
452
+ generatedAt: Schema.String,
453
+ runs: Schema.Array(WorkflowRunRecord),
454
+ error: OptionalString
455
+ })
456
+ export type RunsResponse = typeof RunsResponse.Type
457
+
458
+ export const RunEventsResponse = Schema.Struct({
459
+ generatedAt: Schema.String,
460
+ run: WorkflowRunRecord,
461
+ events: Schema.Array(WorkflowRunEventRecord),
462
+ error: OptionalString
463
+ })
464
+ export type RunEventsResponse = typeof RunEventsResponse.Type
465
+
466
+ export const decodeWorkflowsResponse = (value: unknown): WorkflowsResponse =>
467
+ Schema.decodeUnknownSync(WorkflowsResponse)(value)
468
+
469
+ export const decodeRunsResponse = (value: unknown): RunsResponse =>
470
+ Schema.decodeUnknownSync(RunsResponse)(value)
471
+
472
+ export const decodeRunEventsResponse = (value: unknown): RunEventsResponse =>
473
+ Schema.decodeUnknownSync(RunEventsResponse)(value)
@@ -0,0 +1,176 @@
1
+ import { readFileSync } from "node:fs"
2
+ import { readFile } from "node:fs/promises"
3
+ import path from "node:path"
4
+ import { Schema } from "effect"
5
+ import {
6
+ WorkflowArtifact as WorkflowArtifactSchema,
7
+ WorkflowManifest,
8
+ WorkflowManifestEntry,
9
+ type WorkflowArtifact,
10
+ type WorkflowRunEventRecord,
11
+ type WorkflowRunRecord,
12
+ type WorkflowRunStatus
13
+ } from "../schemas.ts"
14
+
15
+ export type { WorkflowArtifact, WorkflowRunEventRecord, WorkflowRunRecord, WorkflowRunStatus }
16
+
17
+ export interface WorkflowStore {
18
+ list(): Promise<ReadonlyArray<WorkflowArtifact>>
19
+ get(id: string): Promise<WorkflowArtifact | undefined>
20
+ }
21
+
22
+ export interface WorkflowRunStore {
23
+ getRun(id: string): Promise<WorkflowRunRecord | undefined>
24
+ startRun(options: {
25
+ readonly id: string
26
+ readonly workflow: WorkflowArtifact
27
+ readonly input: unknown
28
+ }): Promise<WorkflowRunRecord>
29
+ appendRunEvent(options: {
30
+ readonly runId: string
31
+ readonly type: string
32
+ readonly event: unknown
33
+ }): Promise<void>
34
+ completeRun(options: {
35
+ readonly runId: string
36
+ readonly result: unknown
37
+ }): Promise<void>
38
+ failRun(options: {
39
+ readonly runId: string
40
+ readonly error: unknown
41
+ }): Promise<void>
42
+ listRuns(): Promise<ReadonlyArray<WorkflowRunRecord>>
43
+ listRunEvents(runId: string): Promise<ReadonlyArray<WorkflowRunEventRecord>>
44
+ }
45
+
46
+ export interface WorkflowRepository extends WorkflowStore, WorkflowRunStore {
47
+ upsertWorkflow(workflow: WorkflowArtifact): Promise<void>
48
+ /** Remove every catalog row for a workflow id (all names/versions). */
49
+ deleteWorkflow(id: string): Promise<void>
50
+ }
51
+
52
+ export interface FileWorkflowStoreOptions {
53
+ readonly rootDir?: string
54
+ readonly manifestPath?: string
55
+ }
56
+
57
+ const defaultManifestPath = (rootDir: string) => path.join(rootDir, ".wf", "workflows.json")
58
+
59
+ interface NormalizedWorkflowManifest {
60
+ readonly workflows: ReadonlyArray<WorkflowArtifact>
61
+ }
62
+
63
+ const readManifest = async (rootDir: string, manifestPath: string): Promise<NormalizedWorkflowManifest> => {
64
+ let raw: string
65
+
66
+ try {
67
+ raw = await readFile(manifestPath, "utf8")
68
+ } catch (error) {
69
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
70
+ return { workflows: [] }
71
+ }
72
+ throw error
73
+ }
74
+
75
+ const parsed: unknown = JSON.parse(raw)
76
+ const manifest = Schema.decodeUnknownSync(WorkflowManifest)(parsed)
77
+
78
+ return {
79
+ workflows: manifest.workflows.map((workflow, index) =>
80
+ normalizeArtifact(rootDir, workflow, `workflow manifest entry ${index}`)
81
+ )
82
+ }
83
+ }
84
+
85
+ const requiredString = (
86
+ value: WorkflowManifestEntry,
87
+ key: "id" | "name" | "version",
88
+ label: string
89
+ ): string => {
90
+ const field = value[key]
91
+ if (typeof field !== "string" || field.length === 0) {
92
+ throw new Error(`${label}.${key} must be a non-empty string`)
93
+ }
94
+ return field
95
+ }
96
+
97
+ const nonEmptyOptionalString = (
98
+ field: string | undefined,
99
+ key: keyof WorkflowManifestEntry,
100
+ label: string
101
+ ): string | undefined => {
102
+ if (field === undefined) {
103
+ return undefined
104
+ }
105
+ if (typeof field !== "string" || field.length === 0) {
106
+ throw new Error(`${label}.${key} must be a non-empty string when present`)
107
+ }
108
+ return field
109
+ }
110
+
111
+ const normalizeArtifact = (rootDir: string, value: unknown, label: string): WorkflowArtifact => {
112
+ const artifact = Schema.decodeUnknownSync(WorkflowManifestEntry)(value)
113
+ const source = nonEmptyOptionalString(artifact.source, "source", label)
114
+ const entrypoint = nonEmptyOptionalString(artifact.entrypoint, "entrypoint", label)
115
+ const exportName = nonEmptyOptionalString(artifact.exportName, "exportName", label)
116
+ const createdAt = nonEmptyOptionalString(artifact.createdAt, "createdAt", label)
117
+
118
+ return Schema.decodeUnknownSync(WorkflowArtifactSchema)({
119
+ id: requiredString(artifact, "id", label),
120
+ name: requiredString(artifact, "name", label),
121
+ version: requiredString(artifact, "version", label),
122
+ source: source ?? readLegacySource(rootDir, entrypoint, label),
123
+ ...(exportName === undefined ? {} : { exportName }),
124
+ ...(createdAt === undefined ? {} : { createdAt })
125
+ })
126
+ }
127
+
128
+ const readLegacySource = (rootDir: string, entrypoint: string | undefined, label: string): string => {
129
+ if (entrypoint === undefined) {
130
+ throw new Error(`${label}.source must be a non-empty string`)
131
+ }
132
+
133
+ const sourcePath = path.isAbsolute(entrypoint)
134
+ ? entrypoint
135
+ : path.resolve(rootDir, entrypoint)
136
+ try {
137
+ return readFileSync(sourcePath, "utf8")
138
+ } catch (error) {
139
+ throw new Error(`${label}.entrypoint could not be read: ${(error as Error).message}`)
140
+ }
141
+ }
142
+
143
+ export const createFileWorkflowStore = (
144
+ options: FileWorkflowStoreOptions = {}
145
+ ): WorkflowStore => {
146
+ const rootDir = path.resolve(options.rootDir ?? process.cwd())
147
+ const manifestPath = path.resolve(options.manifestPath ?? defaultManifestPath(rootDir))
148
+
149
+ return {
150
+ async list() {
151
+ const manifest = await readManifest(rootDir, manifestPath)
152
+ return manifest.workflows
153
+ },
154
+
155
+ async get(id) {
156
+ const workflows = await this.list()
157
+ return workflows.find((workflow) => workflow.id === id)
158
+ }
159
+ }
160
+ }
161
+
162
+ export const createMemoryWorkflowStore = (
163
+ workflows: ReadonlyArray<WorkflowArtifact>
164
+ ): WorkflowStore => {
165
+ const artifacts = workflows.map((workflow) => ({ ...workflow }))
166
+
167
+ return {
168
+ async list() {
169
+ return artifacts
170
+ },
171
+
172
+ async get(id) {
173
+ return artifacts.find((workflow) => workflow.id === id)
174
+ }
175
+ }
176
+ }