flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/packages/contracts/src/events.ts

145 lines6,409 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 workflows.
5 *
6 * The envelope follows CloudEvents: `type` says what happened, `subject`
7 * says to what, `data` is the type-specific payload.
8 */
9
10import type { Verdict } from "./work";
11export type EventPayloads = {
12 "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean };
13 "repo.forked": { repoId: string; sourceRepoId: string; pullId: string };
14 /**
15 * A repository's description, topics or visibility changed.
16 * `visibilityChanged` says whether it went public or private, which
17 * `repo.visibility_changed` also announces on its own.
18 */
19 "repo.updated": { repoId: string; namespace: string; name: string; isPrivate: boolean; visibilityChanged: boolean };
20 "repo.visibility_changed": { repoId: string; isPrivate: boolean };
21 /** A repository's path changed. */
22 "repo.renamed": { repoId: string; namespace: string; name: string };
23 /** A repository is gone, and everything about it with it. */
24 "repo.deleted": { repoId: string };
25 /** An account was made, or changed what its profile shows. Ask identity for the profile. */
26 "user.updated": { username: string };
27 /** A workspace was made, or its name, description or icon changed. */
28 "workspace.updated": { workspaceId: string; slug: string };
29 /**
30 * One branch moved by a push. `ref` is the full ref, `after` the commit it
31 * points to now, and `defaultBranch` whether it is the default branch.
32 */
33 "git.push": { repoId: string; ref: string; after: string; defaultBranch: boolean };
34 "issue.opened": { issueId: string; repoId: string; number: number; title: string };
35 "issue.updated": { issueId: string; repoId: string; number: number };
36 /** The people an issue is assigned to changed; `assignees` is the new set. */
37 "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[] };
38 /** `resolvedBy` is the number of the pull request whose merge closed it. */
39 "issue.closed": {
40 issueId: string;
41 repoId: string;
42 number: number;
43 reason: "completed" | "not_planned";
44 resolvedBy?: number;
45 };
46 "issue.reopened": { issueId: string; repoId: string; number: number };
47 /** `issue` is the number of the issue the pull request is for. */
48 "pull.opened": { pullId: string; repoId: string; number: number; issue?: number; agent: string };
49 "pull.ready": { pullId: string; repoId: string; number: number; issue?: number };
50 /** A push moved the head of a pull request that is ready for review. */
51 "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
52 /** A merge was asked for while the pull request was behind; it has to catch up first. */
53 "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number };
54 "pull.closed": { pullId: string; repoId: string; number: number; issue?: number };
55 /**
56 * The pull request's head or its target moved and the files both changed
57 * overlap: a sandbox should find out whether it still merges cleanly.
58 * `commit` is its head.
59 */
60 "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
61 /** Whether the pull request merges cleanly was settled. */
62 "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number };
63 /** Another agent asked the agent on a pull request, which was not at work, a question or handed it work. */
64 "agent.asked": { pullId: string; repoId: string; number: number; issue?: number };
65 "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
66 /** A run of the acceptance checks finished. `commit` is what was checked. */
67 "checks.completed": {
68 pullId: string;
69 repoId: string;
70 number: number;
71 status: "passed" | "failed" | "errored";
72 commit: string;
73 };
74 /** A g1t agent finished reviewing a pull request; no verdict if it could not. */
75 "review.completed": {
76 pullId: string;
77 repoId: string;
78 number: number;
79 verdict?: "approve" | "request_changes";
80 };
81 /** A repository's merge queue gained, lost or settled an entry. */
82 "queue.changed": { repoId: string };
83 /** `number` is the issue or pull request commented on. */
84 "comment.created": {
85 commentId: string;
86 repoId: string;
87 number: number;
88 /** Set when the comment is on a pull request. */
89 pullId?: string;
90 /** Set when the comment is a review. */
91 verdict?: Verdict;
92 };
93 "session.appended": { pullId: string; repoId: string; number: number; count: number };
94 /**
95 * A workspace's slug changed from `from` to `to`. Services that store a
96 * slug move their rows to the workspace's *current* slug (see
97 * `currentWorkspaceSlug`), so a repeated or late delivery after a second
98 * rename still lands in the right place.
99 */
100 "workspace.renamed": { workspaceId: string; from: string; to: string };
101 /**
102 * A memory was added, changed, reviewed or forgotten. No text: ask the
103 * work service for it by id. `repoId` is the project's, or null for the
104 * workspace's memory. `status` is `deleted` once forgotten.
105 */
106 "memory.changed": { memoryId: string; workspace: string; status: "candidate" | "kept" | "dismissed" | "deleted" };
107};
108
109export type EventType = keyof EventPayloads;
110
111export type G1tEvent<T extends EventType = EventType> = {
112 [K in T]: {
113 id: string;
114 type: K;
115 /** The service that published it. */
116 source: string;
117 /** RFC 3339. */
118 time: string;
119 /** The repo the event concerns, used to scope timelines and deliveries. */
120 repoId: string | null;
121 /** The user or agent that caused it, if any. */
122 actor: string | null;
123 data: EventPayloads[K];
124 };
125}[T];
126
127/** What a publisher supplies; the bus fills in `id` and `time`. */
128export type NewEvent<T extends EventType = EventType> = {
129 [K in T]: Omit<G1tEvent<K>, "id" | "time">;
130}[T];
131
132export type EventQuery = {
133 repoId?: string;
134 types?: EventType[];
135 /** Return events older than this event id. */
136 before?: string;
137 limit?: number;
138};
139
140/** The event bus and its durable log. */
141export interface EventsApi {
142 publish(events: NewEvent[]): Promise<void>;
143 /** Newest first. */
144 list(query: EventQuery): Promise<G1tEvent[]>;
145}