Skip to content
File

Blob: src/contracts/run.ts

typescript117 lines
1import { eg, type TypeFromCodec } from "@cloudflare/util-en-garde";
2 
3import {
4 BranchName,
5 CommitSha,
6 IsoDateTime,
7 OpaqueId,
8 ProjectId,
9 RunId,
10 RunStatus,
11 TriggerType,
12 UserId,
13} from "@/contracts/common";
14import { StepStatus } from "@/contracts/execution";
15import { LogEvent } from "@/contracts/log";
16 
17const RunPageLimit = eg.brand(
18 "RunPageLimit",
19 eg.number,
20 (value) => Number.isInteger(value) && value > 0 && value <= 100,
21);
22const OpaqueCursor = eg.string;
23 
24export const TriggerRunRequest = eg.exactStrict(
25 eg.object({
26 branch: BranchName.optional,
27 }),
28);
29export type TriggerRunRequest = TypeFromCodec<typeof TriggerRunRequest>;
30 
31export const TriggerRunAcceptedResponse = eg.exactStrict(
32 eg.object({
33 runId: RunId,
34 }),
35);
36export type TriggerRunAcceptedResponse = TypeFromCodec<typeof TriggerRunAcceptedResponse>;
37 
38export const GetProjectRunsQuery = eg.exactStrict(
39 eg.object({
40 limit: RunPageLimit.optional,
41 cursor: OpaqueCursor.optional,
42 }),
43);
44export type GetProjectRunsQuery = TypeFromCodec<typeof GetProjectRunsQuery>;
45 
46export const RunSummary = eg.exactStrict(
47 eg.object({
48 id: RunId,
49 projectId: ProjectId,
50 triggeredByUserId: eg.union([UserId, eg.null]),
51 triggerType: TriggerType,
52 branch: BranchName,
53 commitSha: eg.union([CommitSha, eg.null]),
54 status: RunStatus,
55 queuedAt: IsoDateTime,
56 startedAt: eg.union([IsoDateTime, eg.null]),
57 finishedAt: eg.union([IsoDateTime, eg.null]),
58 exitCode: eg.union([eg.number, eg.null]),
59 }),
60);
61export type RunSummary = TypeFromCodec<typeof RunSummary>;
62 
63export const GetProjectRunsResponse = eg.exactStrict(
64 eg.object({
65 runs: eg.array(RunSummary),
66 nextCursor: eg.union([OpaqueCursor, eg.null]),
67 }),
68);
69export type GetProjectRunsResponse = TypeFromCodec<typeof GetProjectRunsResponse>;
70 
71export const RunStep = eg.exactStrict(
72 eg.object({
73 id: OpaqueId,
74 runId: RunId,
75 position: eg.number,
76 name: eg.string,
77 command: eg.string,
78 status: StepStatus,
79 startedAt: eg.union([IsoDateTime, eg.null]),
80 finishedAt: eg.union([IsoDateTime, eg.null]),
81 exitCode: eg.union([eg.number, eg.null]),
82 }),
83);
84export type RunStep = TypeFromCodec<typeof RunStep>;
85 
86export const RunExecutionState = eg.exactStrict(
87 eg.object({
88 status: RunStatus,
89 currentStep: eg.union([eg.number, eg.null]),
90 startedAt: eg.union([IsoDateTime, eg.null]),
91 finishedAt: eg.union([IsoDateTime, eg.null]),
92 exitCode: eg.union([eg.number, eg.null]),
93 errorMessage: eg.union([eg.string, eg.null]),
94 }),
95);
96export type RunExecutionState = TypeFromCodec<typeof RunExecutionState>;
97 
98export const RunDetail = eg.exactStrict(
99 eg.object({
100 run: RunSummary,
101 currentStep: eg.union([eg.number, eg.null]),
102 errorMessage: eg.union([eg.string, eg.null]),
103 steps: eg.array(RunStep),
104 recentLogs: eg.array(LogEvent),
105 detailAvailable: eg.boolean,
106 }),
107);
108export type RunDetail = TypeFromCodec<typeof RunDetail>;
109 
110export const LogStreamTicketResponse = eg.exactStrict(
111 eg.object({
112 ticket: eg.string,
113 expiresAt: IsoDateTime,
114 }),
115);
116export type LogStreamTicketResponse = TypeFromCodec<typeof LogStreamTicketResponse>;