pr_01m47d15m3e54sn21z27rpy5n9/packages/contracts/src/events.ts

84 lines3,323 bytesCodeBlame
1/**
2 * Every state change in g1t is published as an event. Services react to
3 * each other through events rather than direct calls, and the same stream
4 * feeds timelines, webhooks and automations.
5 *
6 * The envelope follows CloudEvents: `type` says what happened, `subject`
7 * says to what, `data` is the type-specific payload.
8 */
9export type EventPayloads = {
10 "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean };
11 "repo.forked": { repoId: string; sourceRepoId: string; pullId: string };
12 /**
13 * One branch moved by a push. `ref` is the full ref, `after` the commit it
14 * points to now, and `defaultBranch` whether it is the default branch.
15 */
16 "git.push": { repoId: string; ref: string; after: string; defaultBranch: boolean };
17 "issue.opened": { issueId: string; repoId: string; number: number; title: string };
18 "issue.updated": { issueId: string; repoId: string; number: number };
19 /** `resolvedBy` is the number of the pull request whose merge closed it. */
20 "issue.closed": {
21 issueId: string;
22 repoId: string;
23 number: number;
24 reason: "completed" | "not_planned";
25 resolvedBy?: number;
26 };
27 "issue.reopened": { issueId: string; repoId: string; number: number };
28 /** `issue` is the number of the issue the pull request is for. */
29 "pull.opened": { pullId: string; repoId: string; number: number; issue?: number; agent: string };
30 "pull.ready": { pullId: string; repoId: string; number: number; issue?: number };
31 /** A push moved the head of a pull request that is ready for review. */
32 "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
33 "pull.closed": { pullId: string; repoId: string; number: number; issue?: number };
34 "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
35 /** A run of the acceptance checks finished. `commit` is what was checked. */
36 "checks.completed": {
37 pullId: string;
38 repoId: string;
39 number: number;
40 status: "passed" | "failed" | "errored";
41 commit: string;
42 };
43 /** `number` is the issue or pull request commented on. */
44 "comment.created": { commentId: string; repoId: string; number: number };
45 "session.appended": { pullId: string; repoId: string; number: number; count: number };
46};
47
48export type EventType = keyof EventPayloads;
49
50export type G1tEvent<T extends EventType = EventType> = {
51 [K in T]: {
52 id: string;
53 type: K;
54 /** The service that published it. */
55 source: string;
56 /** RFC 3339. */
57 time: string;
58 /** The repo the event concerns, used to scope timelines and deliveries. */
59 repoId: string | null;
60 /** The user or agent that caused it, if any. */
61 actor: string | null;
62 data: EventPayloads[K];
63 };
64}[T];
65
66/** What a publisher supplies; the bus fills in `id` and `time`. */
67export type NewEvent<T extends EventType = EventType> = {
68 [K in T]: Omit<G1tEvent<K>, "id" | "time">;
69}[T];
70
71export type EventQuery = {
72 repoId?: string;
73 types?: EventType[];
74 /** Return events older than this event id. */
75 before?: string;
76 limit?: number;
77};
78
79/** The event bus and its durable log. */
80export interface EventsApi {
81 publish(events: NewEvent[]): Promise<void>;
82 /** Newest first. */
83 list(query: EventQuery): Promise<G1tEvent[]>;
84}