Skip to content
File

Blob: src/worker/contracts/run-state.ts

typescript152 lines
1import { eg, type TypeFromCodec } from "@cloudflare/util-en-garde";
2 
3import {
4 BranchName,
5 CommitSha,
6 OpaqueId,
7 ProjectId,
8 RunId,
9 RunStatus,
10 TriggerType,
11 UnixTimestampMs,
12} from "@/contracts/common";
13import { LogStream, StepStatus } from "@/contracts/execution/primitives";
14import { PositiveInteger } from "./primitives";
15 
16const NonNegativeInteger = eg.brand("NonNegativeInteger", eg.number, (value) => Number.isInteger(value) && value >= 0);
17const NullableTimestamp = eg.union([UnixTimestampMs, eg.null]);
18 
19export const EnsureRunInput = eg.exactStrict(
20 eg.object({
21 runId: RunId,
22 projectId: ProjectId,
23 triggerType: TriggerType,
24 branch: BranchName,
25 commitSha: eg.union([CommitSha, eg.null]),
26 }),
27);
28export type EnsureRunInput = TypeFromCodec<typeof EnsureRunInput>;
29 
30export const RunMetaState = eg.exactStrict(
31 eg.object({
32 runId: RunId,
33 projectId: ProjectId,
34 status: RunStatus,
35 triggerType: TriggerType,
36 branch: BranchName,
37 commitSha: eg.union([CommitSha, eg.null]),
38 currentStep: eg.union([PositiveInteger, eg.null]),
39 startedAt: NullableTimestamp,
40 finishedAt: NullableTimestamp,
41 exitCode: eg.union([eg.number, eg.null]),
42 errorMessage: eg.union([eg.string, eg.null]),
43 }),
44);
45export type RunMetaState = TypeFromCodec<typeof RunMetaState>;
46 
47export const RunStepInput = eg.exactStrict(
48 eg.object({
49 position: PositiveInteger,
50 name: eg.string,
51 command: eg.string,
52 }),
53);
54export type RunStepInput = TypeFromCodec<typeof RunStepInput>;
55 
56export const ReplaceRunStepsInput = eg.exactStrict(
57 eg.object({
58 runId: RunId,
59 steps: eg.array(RunStepInput),
60 }),
61);
62export type ReplaceRunStepsInput = TypeFromCodec<typeof ReplaceRunStepsInput>;
63 
64export const UpdateRunStateInput = eg.exactStrict(
65 eg.object({
66 runId: RunId,
67 status: RunStatus,
68 currentStep: eg.union([PositiveInteger, eg.null]).optional,
69 startedAt: NullableTimestamp.optional,
70 finishedAt: NullableTimestamp.optional,
71 exitCode: eg.union([eg.number, eg.null]).optional,
72 errorMessage: eg.union([eg.string, eg.null]).optional,
73 }),
74);
75export type UpdateRunStateInput = TypeFromCodec<typeof UpdateRunStateInput>;
76 
77export const UpdateRunStepStateInput = eg.exactStrict(
78 eg.object({
79 runId: RunId,
80 position: PositiveInteger,
81 status: StepStatus,
82 startedAt: NullableTimestamp.optional,
83 finishedAt: NullableTimestamp.optional,
84 exitCode: eg.union([eg.number, eg.null]).optional,
85 }),
86);
87export type UpdateRunStepStateInput = TypeFromCodec<typeof UpdateRunStepStateInput>;
88 
89export const LogAppendEvent = eg.exactStrict(
90 eg.object({
91 stream: LogStream,
92 chunk: eg.string,
93 createdAt: UnixTimestampMs,
94 }),
95);
96export type LogAppendEvent = TypeFromCodec<typeof LogAppendEvent>;
97 
98export const AppendRunLogsInput = eg.exactStrict(
99 eg.object({
100 runId: RunId,
101 events: eg.array(LogAppendEvent),
102 }),
103);
104export type AppendRunLogsInput = TypeFromCodec<typeof AppendRunLogsInput>;
105 
106export const RunLogRecord = eg.exactStrict(
107 eg.object({
108 id: OpaqueId,
109 runId: RunId,
110 seq: PositiveInteger,
111 stream: LogStream,
112 chunk: eg.string,
113 createdAt: UnixTimestampMs,
114 }),
115);
116export type RunLogRecord = TypeFromCodec<typeof RunLogRecord>;
117 
118export const RunStepState = eg.exactStrict(
119 eg.object({
120 id: OpaqueId,
121 runId: RunId,
122 position: PositiveInteger,
123 name: eg.string,
124 command: eg.string,
125 status: StepStatus,
126 startedAt: NullableTimestamp,
127 finishedAt: NullableTimestamp,
128 exitCode: eg.union([eg.number, eg.null]),
129 }),
130);
131export type RunStepState = TypeFromCodec<typeof RunStepState>;
132 
133export const RunDetailState = eg.exactStrict(
134 eg.object({
135 meta: eg.union([RunMetaState, eg.null]),
136 steps: eg.array(RunStepState),
137 recentLogs: eg.array(RunLogRecord),
138 }),
139);
140export type RunDetailState = TypeFromCodec<typeof RunDetailState>;
141 
142export const RunQueueMessage = eg.exactStrict(
143 eg.object({
144 projectId: ProjectId,
145 runId: RunId,
146 }),
147);
148export type RunQueueMessage = TypeFromCodec<typeof RunQueueMessage>;
149 
150export const RunSequence = NonNegativeInteger;
151export type RunSequence = TypeFromCodec<typeof RunSequence>;