@shipfox/api-workflows-dto 2.0.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 (87) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +46 -0
  5. package/LICENSE +21 -0
  6. package/dist/events.d.ts +316 -0
  7. package/dist/events.d.ts.map +1 -0
  8. package/dist/events.js +144 -0
  9. package/dist/events.js.map +1 -0
  10. package/dist/index.d.ts +5 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +6 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/schemas/agent-runtime-config.d.ts +7 -0
  15. package/dist/schemas/agent-runtime-config.d.ts.map +1 -0
  16. package/dist/schemas/agent-runtime-config.js +7 -0
  17. package/dist/schemas/agent-runtime-config.js.map +1 -0
  18. package/dist/schemas/checkout-token.d.ts +56 -0
  19. package/dist/schemas/checkout-token.d.ts.map +1 -0
  20. package/dist/schemas/checkout-token.js +44 -0
  21. package/dist/schemas/checkout-token.js.map +1 -0
  22. package/dist/schemas/checkout.d.ts +10 -0
  23. package/dist/schemas/checkout.d.ts.map +1 -0
  24. package/dist/schemas/checkout.js +10 -0
  25. package/dist/schemas/checkout.js.map +1 -0
  26. package/dist/schemas/index.d.ts +11 -0
  27. package/dist/schemas/index.d.ts.map +1 -0
  28. package/dist/schemas/index.js +12 -0
  29. package/dist/schemas/index.js.map +1 -0
  30. package/dist/schemas/job-execution.d.ts +116 -0
  31. package/dist/schemas/job-execution.d.ts.map +1 -0
  32. package/dist/schemas/job-execution.js +42 -0
  33. package/dist/schemas/job-execution.js.map +1 -0
  34. package/dist/schemas/job-listening.d.ts +93 -0
  35. package/dist/schemas/job-listening.d.ts.map +1 -0
  36. package/dist/schemas/job-listening.js +60 -0
  37. package/dist/schemas/job-listening.js.map +1 -0
  38. package/dist/schemas/job.d.ts +101 -0
  39. package/dist/schemas/job.d.ts.map +1 -0
  40. package/dist/schemas/job.js +43 -0
  41. package/dist/schemas/job.js.map +1 -0
  42. package/dist/schemas/log-outcome.d.ts +7 -0
  43. package/dist/schemas/log-outcome.d.ts.map +1 -0
  44. package/dist/schemas/log-outcome.js +7 -0
  45. package/dist/schemas/log-outcome.js.map +1 -0
  46. package/dist/schemas/step.d.ts +186 -0
  47. package/dist/schemas/step.d.ts.map +1 -0
  48. package/dist/schemas/step.js +137 -0
  49. package/dist/schemas/step.js.map +1 -0
  50. package/dist/schemas/workflow-run-detail.d.ts +807 -0
  51. package/dist/schemas/workflow-run-detail.d.ts.map +1 -0
  52. package/dist/schemas/workflow-run-detail.js +51 -0
  53. package/dist/schemas/workflow-run-detail.js.map +1 -0
  54. package/dist/schemas/workflow-run.d.ts +213 -0
  55. package/dist/schemas/workflow-run.d.ts.map +1 -0
  56. package/dist/schemas/workflow-run.js +112 -0
  57. package/dist/schemas/workflow-run.js.map +1 -0
  58. package/dist/tsconfig.test.tsbuildinfo +1 -0
  59. package/package.json +55 -0
  60. package/src/events.test.ts +362 -0
  61. package/src/events.ts +180 -0
  62. package/src/index.ts +130 -0
  63. package/src/schemas/agent-runtime-config.test.ts +17 -0
  64. package/src/schemas/agent-runtime-config.ts +8 -0
  65. package/src/schemas/checkout-token.test.ts +162 -0
  66. package/src/schemas/checkout-token.ts +45 -0
  67. package/src/schemas/checkout.test.ts +49 -0
  68. package/src/schemas/checkout.ts +11 -0
  69. package/src/schemas/index.ts +104 -0
  70. package/src/schemas/job-execution.test.ts +27 -0
  71. package/src/schemas/job-execution.ts +92 -0
  72. package/src/schemas/job-listening.test.ts +64 -0
  73. package/src/schemas/job-listening.ts +59 -0
  74. package/src/schemas/job.test.ts +42 -0
  75. package/src/schemas/job.ts +53 -0
  76. package/src/schemas/log-outcome.ts +5 -0
  77. package/src/schemas/step-source-location.test.ts +45 -0
  78. package/src/schemas/step.test.ts +176 -0
  79. package/src/schemas/step.ts +163 -0
  80. package/src/schemas/workflow-run-detail.ts +67 -0
  81. package/src/schemas/workflow-run.test.ts +59 -0
  82. package/src/schemas/workflow-run.ts +144 -0
  83. package/tsconfig.build.json +9 -0
  84. package/tsconfig.build.tsbuildinfo +1 -0
  85. package/tsconfig.json +3 -0
  86. package/tsconfig.test.json +8 -0
  87. package/vitest.config.ts +3 -0
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@shipfox/api-workflows-dto",
3
+ "license": "MIT",
4
+ "version": "2.0.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
8
+ "directory": "libs/api/workflows-dto"
9
+ },
10
+ "private": false,
11
+ "type": "module",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "imports": {
15
+ "#test/*": "./test/*",
16
+ "#*": {
17
+ "workspace-source": "./src/*",
18
+ "development": "./src/*",
19
+ "default": "./dist/*"
20
+ }
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "development": {
25
+ "types": "./src/index.ts",
26
+ "default": "./src/index.ts"
27
+ },
28
+ "default": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "zod": "^4.4.3"
36
+ },
37
+ "devDependencies": {
38
+ "@shipfox/ts-config": "1.3.8",
39
+ "@shipfox/depcruise": "1.0.1",
40
+ "@shipfox/swc": "1.2.5",
41
+ "@shipfox/biome": "1.8.1",
42
+ "@shipfox/typescript": "1.1.6",
43
+ "@shipfox/vitest": "1.2.2"
44
+ },
45
+ "scripts": {
46
+ "build": "shipfox-swc",
47
+ "check": "shipfox-biome-check",
48
+ "check:fix": "shipfox-biome-check --write",
49
+ "depcruise": "shipfox-depcruise",
50
+ "test": "shipfox-vitest-run",
51
+ "test:watch": "shipfox-vitest-watch",
52
+ "type": "shipfox-tsc-check",
53
+ "type:emit": "shipfox-tsc-emit"
54
+ }
55
+ }
@@ -0,0 +1,362 @@
1
+ import {
2
+ WORKFLOWS_JOB_ACTIVATED,
3
+ WORKFLOWS_JOB_EVENT_DELIVERED,
4
+ WORKFLOWS_JOB_EXECUTION_TIMED_OUT,
5
+ WORKFLOWS_JOB_STEPS_SETTLED,
6
+ WORKFLOWS_JOB_TERMINATED,
7
+ WORKFLOWS_STEP_ATTEMPT_TERMINATED,
8
+ WORKFLOWS_STEP_RESTART_ENQUEUED,
9
+ WORKFLOWS_WORKFLOW_RUN_ATTEMPT_CREATED,
10
+ WORKFLOWS_WORKFLOW_RUN_CANCELLED,
11
+ WORKFLOWS_WORKFLOW_RUN_TERMINATED,
12
+ workflowsEventSchemas,
13
+ workflowsJobActivatedSchema,
14
+ workflowsJobEventDeliveredSchema,
15
+ workflowsJobExecutionTimedOutSchema,
16
+ workflowsJobStepsSettledSchema,
17
+ workflowsJobTerminatedSchema,
18
+ workflowsStepAttemptTerminatedSchema,
19
+ workflowsStepRestartEnqueuedSchema,
20
+ workflowsWorkflowRunAttemptCreatedSchema,
21
+ workflowsWorkflowRunCancelledSchema,
22
+ workflowsWorkflowRunTerminatedSchema,
23
+ } from './events.js';
24
+
25
+ const validRunCreated = {
26
+ workflowRunId: 'run-1',
27
+ workflowRunAttemptId: 'attempt-1',
28
+ attempt: 1,
29
+ workspaceId: 'ws-1',
30
+ projectId: 'proj-1',
31
+ definitionId: 'def-1',
32
+ };
33
+
34
+ const validJobTerminated = {
35
+ jobId: 'job-1',
36
+ workflowRunId: 'run-1',
37
+ workflowRunAttemptId: 'attempt-1',
38
+ status: 'succeeded',
39
+ statusReason: null,
40
+ };
41
+
42
+ const validRunTerminated = {
43
+ workflowRunId: 'run-1',
44
+ workflowRunAttemptId: 'attempt-1',
45
+ projectId: 'proj-1',
46
+ status: 'failed',
47
+ };
48
+
49
+ const validRunCancelled = {
50
+ workflowRunId: 'run-1',
51
+ workflowRunAttemptId: 'attempt-1',
52
+ projectId: 'proj-1',
53
+ };
54
+
55
+ const validJobExecutionTimedOut = {
56
+ jobId: 'job-1',
57
+ jobExecutionId: 'execution-1',
58
+ workflowRunAttemptId: 'attempt-1',
59
+ };
60
+
61
+ const validJobActivated = {
62
+ jobId: 'job-1',
63
+ workflowRunId: 'run-1',
64
+ workspaceId: 'ws-1',
65
+ mode: 'listening',
66
+ on: [{source: 'github', event: 'pull_request_review', inputs: {state: 'approved'}}],
67
+ until: [{source: 'github', event: 'pull_request_closed'}],
68
+ };
69
+
70
+ const validJobEventDelivered = {
71
+ jobId: 'job-1',
72
+ disposition: 'fire',
73
+ eventRef: 'delivery-1',
74
+ eventName: 'pull_request_review',
75
+ };
76
+
77
+ const validJobStepsSettled = {
78
+ jobId: 'job-1',
79
+ jobExecutionId: 'execution-1',
80
+ workflowRunId: 'run-1',
81
+ workflowRunAttemptId: 'attempt-1',
82
+ status: 'failed',
83
+ };
84
+
85
+ const validStepRestartEnqueued = {
86
+ jobId: 'job-1',
87
+ workflowRunId: 'run-1',
88
+ workflowRunAttemptId: 'attempt-1',
89
+ failedStepId: 'step-1',
90
+ failedStepAttempt: 2,
91
+ restartFromStepId: 'step-0',
92
+ feedback: 'gate failed',
93
+ };
94
+
95
+ const validStepAttemptTerminated = {
96
+ jobId: 'job-1',
97
+ workflowRunId: 'run-1',
98
+ workflowRunAttemptId: 'attempt-1',
99
+ workspaceId: 'ws-1',
100
+ projectId: 'proj-1',
101
+ stepId: 'step-1',
102
+ attempt: 1,
103
+ logOutcome: 'drained',
104
+ };
105
+
106
+ describe('workflowsJobTerminatedSchema', () => {
107
+ it('parses a valid job-terminated payload unchanged', () => {
108
+ const result = workflowsJobTerminatedSchema.parse(validJobTerminated);
109
+
110
+ expect(result).toEqual(validJobTerminated);
111
+ });
112
+
113
+ it('rejects a payload missing a required field', () => {
114
+ const {workflowRunId: _runId, ...withoutWorkflowRunId} = validJobTerminated;
115
+
116
+ const parse = () => workflowsJobTerminatedSchema.parse(withoutWorkflowRunId);
117
+
118
+ expect(parse).toThrow();
119
+ });
120
+
121
+ it('rejects a status outside the terminal set', () => {
122
+ const input = {...validJobTerminated, status: 'running'};
123
+
124
+ const parse = () => workflowsJobTerminatedSchema.parse(input);
125
+
126
+ expect(parse).toThrow();
127
+ });
128
+
129
+ it('accepts skipped as a job-only terminal status with a reason', () => {
130
+ const input = {
131
+ ...validJobTerminated,
132
+ status: 'skipped',
133
+ statusReason: 'dependency_not_completed',
134
+ };
135
+
136
+ const result = workflowsJobTerminatedSchema.parse(input);
137
+
138
+ expect(result).toEqual(input);
139
+ });
140
+
141
+ it('strips unknown keys (tolerant of forward-compatible producer additions)', () => {
142
+ const input = {...validJobTerminated, addedLater: 'ignored'};
143
+
144
+ const result = workflowsJobTerminatedSchema.parse(input);
145
+
146
+ expect(result).toEqual(validJobTerminated);
147
+ });
148
+ });
149
+
150
+ describe('workflowsWorkflowRunTerminatedSchema', () => {
151
+ it('parses a valid run-terminated payload unchanged', () => {
152
+ const result = workflowsWorkflowRunTerminatedSchema.parse(validRunTerminated);
153
+
154
+ expect(result).toEqual(validRunTerminated);
155
+ });
156
+
157
+ it('rejects a payload missing a required field', () => {
158
+ const {projectId: _projectId, ...withoutProjectId} = validRunTerminated;
159
+
160
+ const parse = () => workflowsWorkflowRunTerminatedSchema.parse(withoutProjectId);
161
+
162
+ expect(parse).toThrow();
163
+ });
164
+
165
+ it('rejects a status outside the terminal set', () => {
166
+ const input = {...validRunTerminated, status: 'running'};
167
+
168
+ const parse = () => workflowsWorkflowRunTerminatedSchema.parse(input);
169
+
170
+ expect(parse).toThrow();
171
+ });
172
+
173
+ it('rejects skipped because runs do not have a skipped terminal status', () => {
174
+ const input = {...validRunTerminated, status: 'skipped'};
175
+
176
+ const parse = () => workflowsWorkflowRunTerminatedSchema.parse(input);
177
+
178
+ expect(parse).toThrow();
179
+ });
180
+
181
+ it('strips unknown keys (tolerant of forward-compatible producer additions)', () => {
182
+ const input = {...validRunTerminated, addedLater: 'ignored'};
183
+
184
+ const result = workflowsWorkflowRunTerminatedSchema.parse(input);
185
+
186
+ expect(result).toEqual(validRunTerminated);
187
+ });
188
+ });
189
+
190
+ describe('workflowsJobActivatedSchema', () => {
191
+ it('requires at least one on matcher for listening jobs', () => {
192
+ const withoutMatchers = {...validJobActivated, on: []};
193
+
194
+ const parse = () => workflowsJobActivatedSchema.parse(withoutMatchers);
195
+
196
+ expect(parse).toThrow();
197
+ });
198
+
199
+ it('rejects null on matchers for listening jobs', () => {
200
+ const withoutMatchers = {...validJobActivated, on: null};
201
+
202
+ const parse = () => workflowsJobActivatedSchema.parse(withoutMatchers);
203
+
204
+ expect(parse).toThrow();
205
+ });
206
+
207
+ it('allows one-shot jobs without listener matchers', () => {
208
+ const payload = {
209
+ jobId: 'job-1',
210
+ workflowRunId: 'run-1',
211
+ workspaceId: 'ws-1',
212
+ mode: 'one_shot',
213
+ };
214
+
215
+ const result = workflowsJobActivatedSchema.parse(payload);
216
+
217
+ expect(result).toEqual(payload);
218
+ });
219
+
220
+ it('retains resolved listener filter snapshots on job-activated matchers', () => {
221
+ const payload = {
222
+ ...validJobActivated,
223
+ on: [
224
+ {
225
+ source: 'github',
226
+ event: 'pull_request_review',
227
+ filter: 'jobs.build.outputs.pr_number == event.pull_request.number',
228
+ filter_snapshot: {jobs: {build: {outputs: {pr_number: 42}}}},
229
+ },
230
+ ],
231
+ until: [
232
+ {
233
+ source: 'github',
234
+ event: 'pull_request',
235
+ filter: 'jobs.build.outputs.pr_number == event.pull_request.number',
236
+ filter_snapshot: {jobs: {build: {outputs: {pr_number: 42}}}},
237
+ },
238
+ ],
239
+ };
240
+
241
+ const result = workflowsJobActivatedSchema.parse(payload);
242
+
243
+ expect(result).toEqual(payload);
244
+ });
245
+
246
+ it('keeps authoring-shaped matchers compatible when no snapshot is present', () => {
247
+ const payload = {
248
+ ...validJobActivated,
249
+ on: [{source: 'github', event: 'pull_request_review', filter: 'event.action == "opened"'}],
250
+ until: [{source: 'github', event: 'pull_request'}],
251
+ };
252
+
253
+ const result = workflowsJobActivatedSchema.parse(payload);
254
+
255
+ expect(result).toEqual(payload);
256
+ });
257
+ });
258
+
259
+ describe('workflowsStepRestartEnqueuedSchema', () => {
260
+ it('rejects empty restart feedback', () => {
261
+ const input = {...validStepRestartEnqueued, feedback: ''};
262
+
263
+ const parse = () => workflowsStepRestartEnqueuedSchema.parse(input);
264
+
265
+ expect(parse).toThrow();
266
+ });
267
+ });
268
+
269
+ describe.each([
270
+ [
271
+ 'workflowsWorkflowRunAttemptCreatedSchema',
272
+ workflowsWorkflowRunAttemptCreatedSchema,
273
+ validRunCreated,
274
+ 'workflowRunAttemptId',
275
+ ],
276
+ [
277
+ 'workflowsWorkflowRunCancelledSchema',
278
+ workflowsWorkflowRunCancelledSchema,
279
+ validRunCancelled,
280
+ 'projectId',
281
+ ],
282
+ [
283
+ 'workflowsJobExecutionTimedOutSchema',
284
+ workflowsJobExecutionTimedOutSchema,
285
+ validJobExecutionTimedOut,
286
+ 'jobId',
287
+ ],
288
+ ['workflowsJobActivatedSchema', workflowsJobActivatedSchema, validJobActivated, 'mode'],
289
+ [
290
+ 'workflowsJobEventDeliveredSchema',
291
+ workflowsJobEventDeliveredSchema,
292
+ validJobEventDelivered,
293
+ 'eventRef',
294
+ ],
295
+ [
296
+ 'workflowsJobStepsSettledSchema',
297
+ workflowsJobStepsSettledSchema,
298
+ validJobStepsSettled,
299
+ 'status',
300
+ ],
301
+ [
302
+ 'workflowsStepRestartEnqueuedSchema',
303
+ workflowsStepRestartEnqueuedSchema,
304
+ validStepRestartEnqueued,
305
+ 'failedStepAttempt',
306
+ ],
307
+ [
308
+ 'workflowsStepAttemptTerminatedSchema',
309
+ workflowsStepAttemptTerminatedSchema,
310
+ validStepAttemptTerminated,
311
+ 'logOutcome',
312
+ ],
313
+ ] as const)('%s', (_name, schema, validPayload, requiredKey) => {
314
+ it('parses a valid payload unchanged', () => {
315
+ const result = schema.parse(validPayload);
316
+
317
+ expect(result).toEqual(validPayload);
318
+ });
319
+
320
+ it('rejects a payload missing a required field', () => {
321
+ const withoutRequiredKey = Object.fromEntries(
322
+ Object.entries(validPayload).filter(([key]) => key !== requiredKey),
323
+ );
324
+
325
+ const parse = () => schema.parse(withoutRequiredKey);
326
+
327
+ expect(parse).toThrow();
328
+ });
329
+ });
330
+
331
+ describe('workflowsEventSchemas', () => {
332
+ it('registers every workflows publisher event type', () => {
333
+ const registeredTypes = Object.keys(workflowsEventSchemas).sort();
334
+
335
+ expect(registeredTypes).toEqual(
336
+ [
337
+ WORKFLOWS_WORKFLOW_RUN_ATTEMPT_CREATED,
338
+ WORKFLOWS_WORKFLOW_RUN_TERMINATED,
339
+ WORKFLOWS_WORKFLOW_RUN_CANCELLED,
340
+ WORKFLOWS_JOB_EXECUTION_TIMED_OUT,
341
+ WORKFLOWS_JOB_ACTIVATED,
342
+ WORKFLOWS_JOB_EVENT_DELIVERED,
343
+ WORKFLOWS_JOB_TERMINATED,
344
+ WORKFLOWS_JOB_STEPS_SETTLED,
345
+ WORKFLOWS_STEP_RESTART_ENQUEUED,
346
+ WORKFLOWS_STEP_ATTEMPT_TERMINATED,
347
+ ].sort(),
348
+ );
349
+ });
350
+
351
+ it('does not register retired listener pseudo-entity events', () => {
352
+ const registeredTypes = Object.keys(workflowsEventSchemas);
353
+
354
+ expect(registeredTypes).toEqual(
355
+ expect.not.arrayContaining([
356
+ 'workflows.listener.started',
357
+ 'workflows.listener.resolved',
358
+ 'workflows.listener.cancelled',
359
+ ]),
360
+ );
361
+ });
362
+ });
package/src/events.ts ADDED
@@ -0,0 +1,180 @@
1
+ import {z} from 'zod';
2
+ import {jobStatusReasonSchema} from './schemas/job.js';
3
+ import {listeningTriggerSchema} from './schemas/job-listening.js';
4
+ import {logOutcomeSchema} from './schemas/log-outcome.js';
5
+
6
+ const nonEmptyStringSchema = z.string().nonempty();
7
+
8
+ export const WORKFLOWS_WORKFLOW_RUN_ATTEMPT_CREATED =
9
+ 'workflows.workflow_run_attempt.created' as const;
10
+ // Terminal fact for a workflow run, written in the same transaction as the status flip.
11
+ export const WORKFLOWS_WORKFLOW_RUN_TERMINATED = 'workflows.workflow_run.terminated' as const;
12
+ // Intent fact for cooperative run cancellation. Consumers use this to stop orchestration.
13
+ export const WORKFLOWS_WORKFLOW_RUN_CANCELLED = 'workflows.workflow_run.cancelled' as const;
14
+ export const WORKFLOWS_JOB_EXECUTION_TIMED_OUT = 'workflows.job_execution.timed_out' as const;
15
+ export const WORKFLOWS_JOB_ACTIVATED = 'workflows.job.activated' as const;
16
+ export const WORKFLOWS_JOB_EVENT_DELIVERED = 'workflows.job_event.delivered' as const;
17
+ // Terminal fact for a job: the single reliable "this job is over" signal, written in
18
+ // the same transaction as the status flip, on every terminal path.
19
+ export const WORKFLOWS_JOB_TERMINATED = 'workflows.job.terminated' as const;
20
+ // Internal signal, not a terminal fact: a job's steps have all settled, so the
21
+ // on-job-steps-settled subscriber can raise the Temporal JOB_FINISHED_SIGNAL. Fires
22
+ // before the job row is terminal; observe WORKFLOWS_JOB_TERMINATED for the outcome.
23
+ export const WORKFLOWS_JOB_STEPS_SETTLED = 'workflows.job.steps_settled' as const;
24
+ // Written in the same transaction as a durable gate restart: the failed attempt
25
+ // plus the rewind of the projection from `restart_from`. The pull-based runner
26
+ // re-dispatches the rewound step on its next pull, so consumers must treat this
27
+ // at-least-once outbox event as idempotent audit data.
28
+ export const WORKFLOWS_STEP_RESTART_ENQUEUED = 'workflows.step.restart_enqueued' as const;
29
+ export const WORKFLOWS_STEP_ATTEMPT_TERMINATED = 'workflows.step_attempt.terminated' as const;
30
+
31
+ export const workflowsWorkflowRunAttemptCreatedSchema = z.object({
32
+ workflowRunId: nonEmptyStringSchema,
33
+ workflowRunAttemptId: nonEmptyStringSchema,
34
+ attempt: z.number().int().positive(),
35
+ workspaceId: nonEmptyStringSchema,
36
+ projectId: nonEmptyStringSchema,
37
+ definitionId: nonEmptyStringSchema,
38
+ });
39
+ export type WorkflowsWorkflowRunAttemptCreatedEventDto = z.infer<
40
+ typeof workflowsWorkflowRunAttemptCreatedSchema
41
+ >;
42
+
43
+ // Keep outbox terminal statuses narrower than the public status schemas, which
44
+ // also carry pending/running and job-only skipped.
45
+ export const workflowRunTerminalStatusSchema = z.enum(['succeeded', 'failed', 'cancelled']);
46
+ export const jobTerminalStatusSchema = z.enum(['succeeded', 'failed', 'cancelled', 'skipped']);
47
+ export const terminalStatusSchema = workflowRunTerminalStatusSchema;
48
+
49
+ export const workflowsWorkflowRunTerminatedSchema = z.object({
50
+ workflowRunId: nonEmptyStringSchema,
51
+ workflowRunAttemptId: nonEmptyStringSchema,
52
+ projectId: nonEmptyStringSchema,
53
+ status: workflowRunTerminalStatusSchema,
54
+ });
55
+ export type WorkflowsWorkflowRunTerminatedEventDto = z.infer<
56
+ typeof workflowsWorkflowRunTerminatedSchema
57
+ >;
58
+
59
+ export const workflowsWorkflowRunCancelledSchema = z.object({
60
+ workflowRunId: nonEmptyStringSchema,
61
+ workflowRunAttemptId: nonEmptyStringSchema,
62
+ projectId: nonEmptyStringSchema,
63
+ });
64
+ export type WorkflowsWorkflowRunCancelledEventDto = z.infer<
65
+ typeof workflowsWorkflowRunCancelledSchema
66
+ >;
67
+
68
+ export const workflowsJobExecutionTimedOutSchema = z.object({
69
+ jobId: nonEmptyStringSchema,
70
+ jobExecutionId: nonEmptyStringSchema,
71
+ workflowRunAttemptId: nonEmptyStringSchema,
72
+ });
73
+ export type WorkflowsJobExecutionTimedOutEventDto = z.infer<
74
+ typeof workflowsJobExecutionTimedOutSchema
75
+ >;
76
+
77
+ const workflowsJobActivatedBaseSchema = z.object({
78
+ jobId: nonEmptyStringSchema,
79
+ workflowRunId: nonEmptyStringSchema,
80
+ workspaceId: nonEmptyStringSchema,
81
+ });
82
+
83
+ const resolvedListeningTriggerSchema = listeningTriggerSchema.extend({
84
+ filter_snapshot: z.record(z.string(), z.unknown()).optional(),
85
+ });
86
+
87
+ export const workflowsJobActivatedSchema = z.discriminatedUnion('mode', [
88
+ workflowsJobActivatedBaseSchema.extend({
89
+ mode: z.literal('one_shot'),
90
+ on: z.array(resolvedListeningTriggerSchema).nullable().optional(),
91
+ until: z.array(resolvedListeningTriggerSchema).nullable().optional(),
92
+ }),
93
+ workflowsJobActivatedBaseSchema.extend({
94
+ mode: z.literal('listening'),
95
+ on: z.array(resolvedListeningTriggerSchema).nonempty(),
96
+ until: z.array(resolvedListeningTriggerSchema).nullable(),
97
+ }),
98
+ ]);
99
+ export type WorkflowsJobActivatedEventDto = z.infer<typeof workflowsJobActivatedSchema>;
100
+
101
+ export const workflowsJobEventDeliveredSchema = z.object({
102
+ jobId: nonEmptyStringSchema,
103
+ disposition: z.enum(['fire', 'resolve']),
104
+ eventRef: nonEmptyStringSchema,
105
+ eventName: nonEmptyStringSchema,
106
+ });
107
+ export type WorkflowsJobEventDeliveredEventDto = z.infer<typeof workflowsJobEventDeliveredSchema>;
108
+
109
+ export const workflowsJobTerminatedSchema = z.object({
110
+ jobId: nonEmptyStringSchema,
111
+ workflowRunId: nonEmptyStringSchema,
112
+ workflowRunAttemptId: nonEmptyStringSchema,
113
+ status: jobTerminalStatusSchema,
114
+ statusReason: jobStatusReasonSchema.nullable(),
115
+ });
116
+ export type WorkflowsJobTerminatedEventDto = z.infer<typeof workflowsJobTerminatedSchema>;
117
+
118
+ const settledStatusSchema = z.enum(['succeeded', 'failed']);
119
+
120
+ export const workflowsJobStepsSettledSchema = z.object({
121
+ jobId: nonEmptyStringSchema,
122
+ jobExecutionId: nonEmptyStringSchema,
123
+ workflowRunId: nonEmptyStringSchema,
124
+ workflowRunAttemptId: nonEmptyStringSchema,
125
+ status: settledStatusSchema,
126
+ });
127
+ export type WorkflowsJobStepsSettledEventDto = z.infer<typeof workflowsJobStepsSettledSchema>;
128
+
129
+ export const workflowsStepRestartEnqueuedSchema = z.object({
130
+ jobId: nonEmptyStringSchema,
131
+ workflowRunId: nonEmptyStringSchema,
132
+ workflowRunAttemptId: nonEmptyStringSchema,
133
+ failedStepId: nonEmptyStringSchema,
134
+ failedStepAttempt: z.number(),
135
+ restartFromStepId: nonEmptyStringSchema,
136
+ feedback: nonEmptyStringSchema,
137
+ });
138
+ export type WorkflowsStepRestartEnqueuedEventDto = z.infer<
139
+ typeof workflowsStepRestartEnqueuedSchema
140
+ >;
141
+
142
+ export const workflowsStepAttemptTerminatedSchema = z.object({
143
+ jobId: nonEmptyStringSchema,
144
+ workflowRunId: nonEmptyStringSchema,
145
+ workflowRunAttemptId: nonEmptyStringSchema,
146
+ workspaceId: nonEmptyStringSchema,
147
+ projectId: nonEmptyStringSchema,
148
+ stepId: nonEmptyStringSchema,
149
+ attempt: z.number().int().positive(),
150
+ logOutcome: logOutcomeSchema,
151
+ });
152
+ export type WorkflowsStepAttemptTerminatedEventDto = z.infer<
153
+ typeof workflowsStepAttemptTerminatedSchema
154
+ >;
155
+
156
+ export interface WorkflowsEventMapDto {
157
+ [WORKFLOWS_WORKFLOW_RUN_ATTEMPT_CREATED]: WorkflowsWorkflowRunAttemptCreatedEventDto;
158
+ [WORKFLOWS_WORKFLOW_RUN_TERMINATED]: WorkflowsWorkflowRunTerminatedEventDto;
159
+ [WORKFLOWS_WORKFLOW_RUN_CANCELLED]: WorkflowsWorkflowRunCancelledEventDto;
160
+ [WORKFLOWS_JOB_EXECUTION_TIMED_OUT]: WorkflowsJobExecutionTimedOutEventDto;
161
+ [WORKFLOWS_JOB_ACTIVATED]: WorkflowsJobActivatedEventDto;
162
+ [WORKFLOWS_JOB_EVENT_DELIVERED]: WorkflowsJobEventDeliveredEventDto;
163
+ [WORKFLOWS_JOB_TERMINATED]: WorkflowsJobTerminatedEventDto;
164
+ [WORKFLOWS_JOB_STEPS_SETTLED]: WorkflowsJobStepsSettledEventDto;
165
+ [WORKFLOWS_STEP_RESTART_ENQUEUED]: WorkflowsStepRestartEnqueuedEventDto;
166
+ [WORKFLOWS_STEP_ATTEMPT_TERMINATED]: WorkflowsStepAttemptTerminatedEventDto;
167
+ }
168
+
169
+ export const workflowsEventSchemas = {
170
+ [WORKFLOWS_WORKFLOW_RUN_ATTEMPT_CREATED]: workflowsWorkflowRunAttemptCreatedSchema,
171
+ [WORKFLOWS_WORKFLOW_RUN_TERMINATED]: workflowsWorkflowRunTerminatedSchema,
172
+ [WORKFLOWS_WORKFLOW_RUN_CANCELLED]: workflowsWorkflowRunCancelledSchema,
173
+ [WORKFLOWS_JOB_EXECUTION_TIMED_OUT]: workflowsJobExecutionTimedOutSchema,
174
+ [WORKFLOWS_JOB_ACTIVATED]: workflowsJobActivatedSchema,
175
+ [WORKFLOWS_JOB_EVENT_DELIVERED]: workflowsJobEventDeliveredSchema,
176
+ [WORKFLOWS_JOB_TERMINATED]: workflowsJobTerminatedSchema,
177
+ [WORKFLOWS_JOB_STEPS_SETTLED]: workflowsJobStepsSettledSchema,
178
+ [WORKFLOWS_STEP_RESTART_ENQUEUED]: workflowsStepRestartEnqueuedSchema,
179
+ [WORKFLOWS_STEP_ATTEMPT_TERMINATED]: workflowsStepAttemptTerminatedSchema,
180
+ } satisfies Record<keyof WorkflowsEventMapDto, z.ZodType>;