Skip to content
181 linesCodeBlameRaw
1import type { User, Viewer } from "./identity";
2import type { RepoPath } from "./repos";
3import type { Result } from "./result";
4
5/**
6 * Events, delivered to the addresses a repository or a workspace registers.
7 * Mirrors `crates/contracts/src/webhooks.rs`.
8 */
9
10/** Every event a webhook can be sent, in the order people are shown them. */
11export const EVENT_TYPES = [
12 "git.push",
13 "git.deleted",
14 "branch.renamed",
15 "repo.created",
16 "repo.forked",
17 "repo.updated",
18 "repo.visibility_changed",
19 "repo.renamed",
20 "repo.transferred",
21 "repo.default_branch_changed",
22 "repo.archived",
23 "repo.unarchived",
24 "repo.deleted",
25 "repo.restored",
26 "repo.purged",
27 "repo.collaborator_added",
28 "repo.collaborator_removed",
29 "repo.collaborator_role_changed",
30 "team.created",
31 "team.edited",
32 "team.deleted",
33 "team.member_added",
34 "team.member_role_changed",
35 "team.member_removed",
36 "team.repo_added",
37 "team.repo_role_changed",
38 "team.repo_removed",
39 "workspace.member_joined",
40 "ruleset.created",
41 "ruleset.updated",
42 "ruleset.deleted",
43 "issue.opened",
44 "issue.updated",
45 "issue.assigned",
46 "issue.labeled",
47 "issue.unlabeled",
48 "issue.milestoned",
49 "issue.demilestoned",
50 "issue.closed",
51 "issue.reopened",
52 "comment.created",
53 "comment.edited",
54 "comment.deleted",
55 "pull.opened",
56 "pull.ready",
57 "pull.updated",
58 "pull.merge_requested",
59 "pull.merged",
60 "pull.closed",
61 "pull.reopened",
62 "pull.converted_to_draft",
63 "pull.assigned",
64 "pull.review_requested",
65 "pull.review_request_removed",
66 "pull.labeled",
67 "pull.unlabeled",
68 "pull.milestoned",
69 "pull.demilestoned",
70 "pull.base_changed",
71 "pull.stalled",
72 "pull.resumed",
73 "release.created",
74 "release.published",
75 "release.released",
76 "release.prereleased",
77 "release.edited",
78 "release.unpublished",
79 "release.deleted",
80 "checks.completed",
81 "status.created",
82 "check_run.created",
83 "check_run.completed",
84 "check_run.rerequested",
85 "check_run.requested_action",
86 "check_suite.completed",
87 "check_suite.rerequested",
88 "workflow.completed",
89 "deployment.succeeded",
90 "deployment.failed",
91 "deployment.created",
92 "deployment_status.created",
93 "queue.changed",
94 "integration.failed",
95 "integration.passed",
96 "decision.recorded",
97 "session.appended",
98 "package.published",
99 "package.version_deleted",
100 "package.deleted",
101 "package.visibility_changed",
102 "secret_scanning_alert.created",
103 "secret_scanning_alert.fixed",
104 "secret_scanning_alert.dismissed",
105 "secret_scanning_alert.reopened",
106 "secret_scanning.bypass_requested",
107 "secret_scanning.bypass_reviewed",
108 "code_scanning_alert.created",
109 "code_scanning_alert.fixed",
110 "code_scanning_alert.dismissed",
111 "code_scanning_alert.reopened",
112 "vulnerability_alert.created",
113 "vulnerability_alert.fixed",
114 "vulnerability_alert.dismissed",
115 "secret_scanning_alert.summary",
116 "code_scanning_alert.summary",
117 "vulnerability_alert.reopened",
118 "vulnerability_alert.summary",
119 "security_advisory.published",
120 "security_advisory.withdrawn",
121 "security_advisory.reported",
122] as const;
123
124/**
125 * Event types webhooks were once offered that g1t no longer sends (from
126 * g1t's own agents, since removed). A webhook saved with one still reads;
127 * saving its list again leaves them out. Mirrors `RETIRED_EVENT_TYPES`.
128 */
129export const RETIRED_EVENT_TYPES: readonly string[] = ["agent.asked", "review.completed"];
130
131export type Hook = {
132 id: string;
133 scope: "repo" | "workspace";
134 workspace: string;
135 /** For a repository's webhook: `owner/name`. */
136 repo: string | null;
137 url: string;
138 /** Event types, or `["*"]` for all. */
139 events: string[];
140 active: boolean;
141 secretHint: string;
142 createdBy: string;
143 createdAt: string;
144 lastStatus: "delivered" | "pending" | "failed" | null;
145 lastDeliveredAt: string | null;
146};
147
148export type HookDelivery = {
149 id: string;
150 hookId: string;
151 eventId: string;
152 event: string;
153 status: "pending" | "delivered" | "failed";
154 attempts: number;
155 responseStatus: number | null;
156 responseBody: string | null;
157 error: string | null;
158 durationMs: number | null;
159 /** The JSON that was sent. */
160 payload: string;
161 createdAt: string;
162 deliveredAt: string | null;
163 nextAttemptAt: string | null;
164};
165
166/** A repository's webhooks, or with `repo` left out, the workspace's own. */
167export type HookOwner = { workspace: string; repo?: RepoPath };
168
169export interface WebhooksApi {
170 list(viewer: Viewer, owner: HookOwner): Promise<Result<Hook[]>>;
171 create(
172 actor: User,
173 owner: HookOwner,
174 input: { url: string; events?: string[]; secret?: string },
175 ): Promise<Result<{ hook: Hook; secret: string | null }>>;
176 update(actor: User, owner: HookOwner, id: string, input: { url?: string; events?: string[]; active?: boolean }): Promise<Result<Hook>>;
177 delete(actor: User, owner: HookOwner, id: string): Promise<Result<boolean>>;
178 ping(actor: User, owner: HookOwner, id: string): Promise<Result<HookDelivery>>;
179 deliveries(viewer: Viewer, owner: HookOwner, id: string): Promise<Result<HookDelivery[]>>;
180 redeliver(actor: User, owner: HookOwner, deliveryId: string): Promise<Result<HookDelivery>>;
181}