@framers/agentos-ext-github 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +43 -11
  2. package/dist/__tests__/app.test.js +155 -1
  3. package/dist/__tests__/app.test.js.map +1 -1
  4. package/dist/__tests__/documents.test.js +28 -1
  5. package/dist/__tests__/documents.test.js.map +1 -1
  6. package/dist/__tests__/events.test.d.ts +8 -0
  7. package/dist/__tests__/events.test.d.ts.map +1 -0
  8. package/dist/__tests__/events.test.js +304 -0
  9. package/dist/__tests__/events.test.js.map +1 -0
  10. package/dist/app/events.d.ts +142 -0
  11. package/dist/app/events.d.ts.map +1 -0
  12. package/dist/app/events.js +182 -0
  13. package/dist/app/events.js.map +1 -0
  14. package/dist/app/http.d.ts +82 -13
  15. package/dist/app/http.d.ts.map +1 -1
  16. package/dist/app/http.js +151 -23
  17. package/dist/app/http.js.map +1 -1
  18. package/dist/app/installations.d.ts +8 -6
  19. package/dist/app/installations.d.ts.map +1 -1
  20. package/dist/app/installations.js +21 -15
  21. package/dist/app/installations.js.map +1 -1
  22. package/dist/app/reconcile.d.ts +1 -1
  23. package/dist/app/reconcile.d.ts.map +1 -1
  24. package/dist/app/reconcile.js +8 -7
  25. package/dist/app/reconcile.js.map +1 -1
  26. package/dist/app/userFlow.d.ts +10 -3
  27. package/dist/app/userFlow.d.ts.map +1 -1
  28. package/dist/app/userFlow.js +43 -4
  29. package/dist/app/userFlow.js.map +1 -1
  30. package/dist/documents/GitHubDocumentsConnector.d.ts +7 -4
  31. package/dist/documents/GitHubDocumentsConnector.d.ts.map +1 -1
  32. package/dist/documents/GitHubDocumentsConnector.js +39 -18
  33. package/dist/documents/GitHubDocumentsConnector.js.map +1 -1
  34. package/dist/documents/index.d.ts +11 -6
  35. package/dist/documents/index.d.ts.map +1 -1
  36. package/dist/documents/index.js +11 -6
  37. package/dist/documents/index.js.map +1 -1
  38. package/manifest.json +4 -2
  39. package/package.json +5 -4
@@ -0,0 +1,304 @@
1
+ /**
2
+ * @fileoverview A GitHub App's webhook deliveries read as typed events, over deliveries built the way GitHub sends
3
+ * them: the `X-GitHub-Event`, `X-GitHub-Delivery` and `X-Hub-Signature-256` headers and a JSON body whose payloads
4
+ * keep the fields of GitHub's push, installation, installation_repositories, installation_target and ping events
5
+ * (https://docs.github.com/en/webhooks/webhook-events-and-payloads), each signed with the webhook's secret.
6
+ */
7
+ import { createHmac } from 'node:crypto';
8
+ import { describe, expect, it } from 'vitest';
9
+ import { readWebhookDelivery, readWebhookRequest, WebhookDeliveryRefused } from '../documents/index.js';
10
+ const SECRET = 'test-webhook-secret';
11
+ const DELIVERY_ID = '72d3162e-cc78-11e3-81ab-4c9367dc0958';
12
+ const C1 = '1'.repeat(40);
13
+ const C2 = '2'.repeat(40);
14
+ const ZERO = '0'.repeat(40);
15
+ /** The fields GitHub sends for the person who caused an event; the reader takes none of them. */
16
+ const SENDER = { login: 'test-person', id: 501, type: 'User' };
17
+ /** A push to the handbook's default branch, as an app's delivery carries it. */
18
+ const PUSH = {
19
+ ref: 'refs/heads/main',
20
+ before: C1,
21
+ after: C2,
22
+ repository: {
23
+ id: 77,
24
+ node_id: 'R_test77',
25
+ name: 'handbook',
26
+ full_name: 'acme-team/handbook',
27
+ private: true,
28
+ default_branch: 'main',
29
+ master_branch: 'main',
30
+ },
31
+ pusher: { name: 'test-person', email: null },
32
+ sender: SENDER,
33
+ installation: { id: 5, node_id: 'I_test5' },
34
+ created: false,
35
+ deleted: false,
36
+ forced: false,
37
+ base_ref: null,
38
+ compare: `https://github.com/acme-team/handbook/compare/${C1.slice(0, 12)}...${C2.slice(0, 12)}`,
39
+ commits: [],
40
+ head_commit: null,
41
+ };
42
+ /** The installation of the app on the acme-team organization, on a selection of its repositories. */
43
+ const INSTALLATION = {
44
+ id: 5,
45
+ account: { login: 'acme-team', id: 901, type: 'Organization' },
46
+ repository_selection: 'selected',
47
+ app_id: 1,
48
+ target_type: 'Organization',
49
+ };
50
+ /** A repository as an installation event lists it. */
51
+ function listed(id, fullName) {
52
+ return { id, node_id: `R_test${id}`, name: fullName.split('/')[1], full_name: fullName, private: true };
53
+ }
54
+ /** A delivery as GitHub sends it: the event's name, the delivery's id and the body's signature under `secret`. */
55
+ function delivery(event, payload, { id = DELIVERY_ID, secret = SECRET, body } = {}) {
56
+ const bytes = body ?? new TextEncoder().encode(JSON.stringify(payload));
57
+ const headers = new Headers({
58
+ 'content-type': 'application/json',
59
+ 'user-agent': 'GitHub-Hookshot/044aadd',
60
+ 'x-hub-signature-256': `sha256=${createHmac('sha256', secret).update(bytes).digest('hex')}`,
61
+ });
62
+ if (event !== null)
63
+ headers.set('x-github-event', event);
64
+ if (id !== null)
65
+ headers.set('x-github-delivery', id);
66
+ return { headers, body: bytes };
67
+ }
68
+ /** What `readWebhookDelivery` refused the delivery for, or the delivery it read. */
69
+ function refusalOf(read) {
70
+ try {
71
+ return read();
72
+ }
73
+ catch (error) {
74
+ if (error instanceof WebhookDeliveryRefused)
75
+ return error.reason;
76
+ throw error;
77
+ }
78
+ }
79
+ describe("a GitHub App's webhook deliveries", () => {
80
+ it('reads a push: the installation, the repository and its default branch, the ref and the commits around it', () => {
81
+ const read = readWebhookDelivery(delivery('push', PUSH), SECRET);
82
+ expect(read).toEqual({
83
+ id: DELIVERY_ID,
84
+ name: 'push',
85
+ event: {
86
+ kind: 'push',
87
+ installationId: 5,
88
+ repository: { id: 77, fullName: 'acme-team/handbook', defaultBranch: 'main' },
89
+ ref: 'refs/heads/main',
90
+ before: C1,
91
+ after: C2,
92
+ created: false,
93
+ deleted: false,
94
+ forced: false,
95
+ toDefaultBranch: true,
96
+ },
97
+ });
98
+ });
99
+ it('marks a push that moved the default branch, and no other: a force push counts, a branch, a tag and a deletion do not', () => {
100
+ const cases = [
101
+ [{ forced: true }, true],
102
+ [{ ref: 'refs/heads/feature' }, false],
103
+ [{ ref: 'refs/tags/v1.0.0' }, false],
104
+ [{ ref: 'refs/heads/mainline' }, false],
105
+ [{ deleted: true, after: ZERO }, false],
106
+ [{ created: true, before: ZERO, ref: 'refs/heads/draft' }, false],
107
+ ];
108
+ for (const [change, toDefaultBranch] of cases) {
109
+ const read = readWebhookDelivery(delivery('push', { ...PUSH, ...change }), SECRET);
110
+ expect(read.event.kind).toBe('push');
111
+ expect(read.event.kind === 'push' && read.event.toDefaultBranch).toBe(toDefaultBranch);
112
+ }
113
+ });
114
+ it("reads each of an installation's actions, with the account and the repositories a new installation lists", () => {
115
+ const created = readWebhookDelivery(delivery('installation', {
116
+ action: 'created',
117
+ installation: INSTALLATION,
118
+ repositories: [listed(77, 'acme-team/handbook'), listed(78, 'acme-team/large')],
119
+ requester: null,
120
+ sender: SENDER,
121
+ }), SECRET);
122
+ expect(created.event).toEqual({
123
+ kind: 'installation',
124
+ action: 'created',
125
+ installationId: 5,
126
+ account: { login: 'acme-team', id: 901 },
127
+ repositories: [
128
+ { id: 77, fullName: 'acme-team/handbook' },
129
+ { id: 78, fullName: 'acme-team/large' },
130
+ ],
131
+ });
132
+ for (const action of ['deleted', 'suspend', 'unsuspend', 'new_permissions_accepted']) {
133
+ const read = readWebhookDelivery(delivery('installation', { action, installation: INSTALLATION, sender: SENDER }), SECRET);
134
+ expect(read.event).toEqual({ kind: 'installation', action, installationId: 5, account: { login: 'acme-team', id: 901 }, repositories: [] });
135
+ }
136
+ const enterprise = readWebhookDelivery(delivery('installation', { action: 'suspend', installation: { ...INSTALLATION, account: { slug: 'acme-enterprise', id: 902 } }, sender: SENDER }), SECRET);
137
+ expect(enterprise.event).toMatchObject({ kind: 'installation', account: { login: 'acme-enterprise', id: 902 } });
138
+ const unknown = readWebhookDelivery(delivery('installation', { action: 'transferred', installation: INSTALLATION, sender: SENDER }), SECRET);
139
+ expect(unknown).toEqual({ id: DELIVERY_ID, name: 'installation', event: { kind: 'other' } });
140
+ });
141
+ it("reads the repositories added to and removed from an installation, and the selection they leave", () => {
142
+ const added = readWebhookDelivery(delivery('installation_repositories', {
143
+ action: 'added',
144
+ installation: INSTALLATION,
145
+ repository_selection: 'selected',
146
+ repositories_added: [listed(79, 'acme-team/notes')],
147
+ repositories_removed: [],
148
+ requester: null,
149
+ sender: SENDER,
150
+ }), SECRET);
151
+ expect(added.event).toEqual({
152
+ kind: 'installation_repositories',
153
+ action: 'added',
154
+ installationId: 5,
155
+ selection: 'selected',
156
+ added: [{ id: 79, fullName: 'acme-team/notes' }],
157
+ removed: [],
158
+ });
159
+ const removed = readWebhookDelivery(delivery('installation_repositories', {
160
+ action: 'removed',
161
+ installation: INSTALLATION,
162
+ repository_selection: 'selected',
163
+ repositories_added: [],
164
+ repositories_removed: [listed(77, 'acme-team/handbook')],
165
+ requester: null,
166
+ sender: SENDER,
167
+ }), SECRET);
168
+ expect(removed.event).toEqual({
169
+ kind: 'installation_repositories',
170
+ action: 'removed',
171
+ installationId: 5,
172
+ selection: 'selected',
173
+ added: [],
174
+ removed: [{ id: 77, fullName: 'acme-team/handbook' }],
175
+ });
176
+ // From all repositories to a selection, GitHub names none of the repositories that left.
177
+ const narrowed = readWebhookDelivery(delivery('installation_repositories', {
178
+ action: 'removed',
179
+ installation: { ...INSTALLATION, repository_selection: 'selected' },
180
+ repository_selection: 'selected',
181
+ repositories_added: [],
182
+ repositories_removed: [],
183
+ requester: null,
184
+ sender: SENDER,
185
+ }), SECRET);
186
+ expect(narrowed.event).toMatchObject({ kind: 'installation_repositories', action: 'removed', selection: 'selected', removed: [] });
187
+ });
188
+ it('reads an account renamed under an installation, by its new login or an enterprise slug', () => {
189
+ const renamed = readWebhookDelivery(delivery('installation_target', {
190
+ action: 'renamed',
191
+ account: { login: 'acme-renamed', id: 901, node_id: 'O_test901', avatar_url: 'https://avatars.example/901', html_url: 'https://github.com/acme-renamed' },
192
+ changes: { login: { from: 'acme-team' } },
193
+ target_type: 'Organization',
194
+ installation: { id: 5, node_id: 'I_test5' },
195
+ sender: SENDER,
196
+ }), SECRET);
197
+ expect(renamed.event).toEqual({ kind: 'installation_target', action: 'renamed', installationId: 5, account: { login: 'acme-renamed', id: 901 } });
198
+ const slug = readWebhookDelivery(delivery('installation_target', {
199
+ action: 'renamed',
200
+ account: { slug: 'acme-enterprise-renamed', id: 902, node_id: 'E_test902', avatar_url: 'https://avatars.example/902', html_url: 'https://github.com/enterprises/x' },
201
+ changes: { slug: { from: 'acme-enterprise' } },
202
+ target_type: 'Enterprise',
203
+ installation: { id: 6, node_id: 'I_test6' },
204
+ }), SECRET);
205
+ expect(slug.event).toEqual({ kind: 'installation_target', action: 'renamed', installationId: 6, account: { login: 'acme-enterprise-renamed', id: 902 } });
206
+ });
207
+ it('answers a ping, an event it does not read, and a payload without the fields it reads, naming no field of them', () => {
208
+ expect(readWebhookDelivery(delivery('ping', { zen: 'Keep it logically awesome.', hook_id: 123, hook: { type: 'App' } }), SECRET)).toEqual({
209
+ id: DELIVERY_ID,
210
+ name: 'ping',
211
+ event: { kind: 'ping' },
212
+ });
213
+ expect(readWebhookDelivery(delivery('issues', { action: 'opened', issue: { title: 'private words' }, sender: SENDER }), SECRET)).toEqual({
214
+ id: DELIVERY_ID,
215
+ name: 'issues',
216
+ event: { kind: 'other' },
217
+ });
218
+ const { installation: _dropped, ...withoutInstallation } = PUSH;
219
+ expect(readWebhookDelivery(delivery('push', withoutInstallation), SECRET).event).toEqual({ kind: 'other' });
220
+ expect(readWebhookDelivery(delivery('push', { ...PUSH, after: 'not-a-commit' }), SECRET).event).toEqual({ kind: 'other' });
221
+ expect(readWebhookDelivery(delivery('installation_repositories', { action: 'added', installation: INSTALLATION, sender: SENDER }), SECRET).event).toEqual({
222
+ kind: 'other',
223
+ });
224
+ const odd = readWebhookDelivery(delivery('Push Event!', PUSH), SECRET);
225
+ expect(odd).toEqual({ id: DELIVERY_ID, name: '', event: { kind: 'other' } });
226
+ expect(readWebhookDelivery(delivery(null, PUSH), SECRET)).toEqual({ id: DELIVERY_ID, name: '', event: { kind: 'other' } });
227
+ });
228
+ it('refuses a delivery whose signature does not hold before it reads the body', () => {
229
+ const signedElsewhere = delivery('push', PUSH, { secret: 'another-secret' });
230
+ expect(refusalOf(() => readWebhookDelivery(signedElsewhere, SECRET))).toBe('signature');
231
+ const unsigned = delivery('push', PUSH);
232
+ unsigned.headers.delete('x-hub-signature-256');
233
+ expect(refusalOf(() => readWebhookDelivery(unsigned, SECRET))).toBe('signature');
234
+ // A body that is not JSON under a wrong signature is refused for its signature, never parsed.
235
+ const garbled = delivery('push', null, { secret: 'another-secret', body: new TextEncoder().encode('{"private": ') });
236
+ expect(refusalOf(() => readWebhookDelivery(garbled, SECRET))).toBe('signature');
237
+ });
238
+ it('refuses a delivery without a usable id, a body past the cap, and a signed body that is not a JSON object, quoting none of it', () => {
239
+ expect(refusalOf(() => readWebhookDelivery(delivery('push', PUSH, { id: null }), SECRET))).toBe('delivery');
240
+ expect(refusalOf(() => readWebhookDelivery(delivery('push', PUSH, { id: 'not a delivery id' }), SECRET))).toBe('delivery');
241
+ const large = delivery('push', PUSH, { secret: 'another-secret' });
242
+ expect(refusalOf(() => readWebhookDelivery(large, SECRET, { maxBytes: large.body.byteLength - 1 }))).toBe('too_large');
243
+ expect(refusalOf(() => readWebhookDelivery(delivery('push', PUSH), SECRET, { maxBytes: 64 }))).toBe('too_large');
244
+ for (const body of ['[1,2]', 'null', '"push"', '{"private words": ']) {
245
+ const signed = delivery('push', null, { body: new TextEncoder().encode(body) });
246
+ let failure;
247
+ try {
248
+ readWebhookDelivery(signed, SECRET);
249
+ }
250
+ catch (error) {
251
+ failure = error;
252
+ }
253
+ expect(failure).toBeInstanceOf(WebhookDeliveryRefused);
254
+ expect(failure.reason).toBe('body');
255
+ expect(failure.message).not.toContain('private');
256
+ }
257
+ const notUtf8 = delivery('push', null, { body: new Uint8Array([0x7b, 0x22, 0xff, 0xfe, 0x22, 0x3a, 0x31, 0x7d]) });
258
+ expect(refusalOf(() => readWebhookDelivery(notUtf8, SECRET))).toBe('body');
259
+ });
260
+ it('throws a TypeError for an empty secret, whatever the delivery', () => {
261
+ expect(() => readWebhookDelivery(delivery('push', PUSH, { secret: '' }), '')).toThrow(TypeError);
262
+ });
263
+ it("reads a request's body under the cap, and stops a stream that passes it", async () => {
264
+ const { headers, body } = delivery('push', PUSH);
265
+ const sent = new ReadableStream({
266
+ start(controller) {
267
+ controller.enqueue(body.slice(0, 100));
268
+ controller.enqueue(body.slice(100));
269
+ controller.close();
270
+ },
271
+ });
272
+ const whole = await readWebhookRequest({ headers, body: sent }, SECRET);
273
+ expect(whole.event).toMatchObject({ kind: 'push', installationId: 5, toDefaultBranch: true });
274
+ expect(whole.id).toBe(DELIVERY_ID);
275
+ let pulled = 0;
276
+ let cancelled = false;
277
+ const endless = new ReadableStream({
278
+ pull(controller) {
279
+ pulled += 65_536;
280
+ controller.enqueue(new Uint8Array(65_536).fill(0x20));
281
+ },
282
+ cancel() {
283
+ cancelled = true;
284
+ },
285
+ }, { highWaterMark: 0 });
286
+ const failure = await readWebhookRequest({ headers, body: endless }, SECRET, { maxBytes: 200_000 }).catch((error) => error);
287
+ expect(failure).toBeInstanceOf(WebhookDeliveryRefused);
288
+ expect(failure.reason).toBe('too_large');
289
+ expect(cancelled).toBe(true);
290
+ expect(pulled).toBeLessThanOrEqual(200_000 + 65_536);
291
+ const declared = new Headers(headers);
292
+ declared.set('content-length', String(10_000_000));
293
+ let read = false;
294
+ const stated = new ReadableStream({
295
+ pull() {
296
+ read = true;
297
+ },
298
+ }, { highWaterMark: 0 });
299
+ const refused = await readWebhookRequest({ headers: declared, body: stated }, SECRET, { maxBytes: 200_000 }).catch((error) => error);
300
+ expect(refused.reason).toBe('too_large');
301
+ expect(read).toBe(false);
302
+ });
303
+ });
304
+ //# sourceMappingURL=events.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.test.js","sourceRoot":"","sources":["../../src/__tests__/events.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @fileoverview A GitHub App's webhook deliveries read as typed events. A delivery's size is checked first, then its
3
+ * `X-Hub-Signature-256` on the raw body, then its `X-GitHub-Delivery` id, and only then is its body parsed; each event
4
+ * an app reading its installations' repositories acts on (a push, an installation's actions, the repositories it
5
+ * reaches, its account renamed, a ping) is answered with the fields that reading needs, and every other delivery as
6
+ * `other`. No text of a payload reaches an error, and nothing of a payload but those fields leaves the reader.
7
+ * Payloads as https://docs.github.com/en/webhooks/webhook-events-and-payloads documents them.
8
+ * @module agentos-ext-github/app/events
9
+ */
10
+ import { type GitHubAccount } from './installations.js';
11
+ /** The largest delivery read by default: 25 MiB (26,214,400 bytes). GitHub delivers no payload past 25 MB. */
12
+ export declare const DEFAULT_MAX_DELIVERY_BYTES = 26214400;
13
+ /**
14
+ * Why a delivery was refused: `too_large` past the cap (answer 413), `signature` for a signature that does not hold
15
+ * or is missing (answer 401), `delivery` for a missing or malformed `X-GitHub-Delivery` (answer 400), `body` for a
16
+ * signed body that is not a JSON object in UTF-8 (answer 400).
17
+ */
18
+ export type WebhookRefusalReason = 'too_large' | 'signature' | 'delivery' | 'body';
19
+ /** A delivery the reader refused. The message names the reason alone, never the body or a header's value. */
20
+ export declare class WebhookDeliveryRefused extends Error {
21
+ readonly reason: WebhookRefusalReason;
22
+ /** @param reason Why the delivery was refused. */
23
+ constructor(reason: WebhookRefusalReason);
24
+ }
25
+ /** A repository an event names. */
26
+ export interface GitHubEventRepository {
27
+ id: number;
28
+ /** `owner/name`. */
29
+ fullName: string;
30
+ }
31
+ /** A push to a repository the installation reaches. */
32
+ export interface GitHubPushEvent {
33
+ kind: 'push';
34
+ installationId: number;
35
+ repository: GitHubEventRepository & {
36
+ defaultBranch: string;
37
+ };
38
+ /** The full ref pushed, such as `refs/heads/main` or `refs/tags/v1.0.0`. */
39
+ ref: string;
40
+ /** The ref's commit before the push; zeros when the push created the ref. */
41
+ before: string;
42
+ /** The ref's commit after the push; zeros when the push deleted the ref. */
43
+ after: string;
44
+ created: boolean;
45
+ deleted: boolean;
46
+ forced: boolean;
47
+ /** True when the push moved the repository's default branch: `ref` is `refs/heads/<default branch>` and it was not deleted. */
48
+ toDefaultBranch: boolean;
49
+ }
50
+ /** An installation's action: installed, uninstalled, suspended, unsuspended, or new permissions accepted. */
51
+ export interface GitHubInstallationEvent {
52
+ kind: 'installation';
53
+ action: 'created' | 'deleted' | 'suspend' | 'unsuspend' | 'new_permissions_accepted';
54
+ installationId: number;
55
+ /** The account the app is installed on, or null when GitHub sends none. */
56
+ account: GitHubAccount | null;
57
+ /** The repositories the installation can access, where GitHub lists them (an installation on selected repositories); else empty. */
58
+ repositories: GitHubEventRepository[];
59
+ }
60
+ /**
61
+ * Repositories added to or removed from an installation. When the installation goes from all of an account's
62
+ * repositories to a selection, GitHub sends `removed` with no repository listed, so `removed` can be empty while
63
+ * repositories left: read the installation's repositories again.
64
+ */
65
+ export interface GitHubInstallationRepositoriesEvent {
66
+ kind: 'installation_repositories';
67
+ action: 'added' | 'removed';
68
+ installationId: number;
69
+ /** Whether the installation now reaches all of the account's repositories or a selection. */
70
+ selection: 'all' | 'selected';
71
+ added: GitHubEventRepository[];
72
+ removed: GitHubEventRepository[];
73
+ }
74
+ /** The account an installation is on was renamed. */
75
+ export interface GitHubInstallationTargetEvent {
76
+ kind: 'installation_target';
77
+ action: 'renamed';
78
+ installationId: number;
79
+ /** The account under its new login, or an enterprise's new slug. */
80
+ account: GitHubAccount;
81
+ }
82
+ /** GitHub's check that the webhook is set up. */
83
+ export interface GitHubPingEvent {
84
+ kind: 'ping';
85
+ }
86
+ /** A delivery the reader does not read: another event, another action, or a payload without the fields above. */
87
+ export interface GitHubOtherEvent {
88
+ kind: 'other';
89
+ }
90
+ /** A delivery's event. */
91
+ export type GitHubEvent = GitHubPushEvent | GitHubInstallationEvent | GitHubInstallationRepositoriesEvent | GitHubInstallationTargetEvent | GitHubPingEvent | GitHubOtherEvent;
92
+ /** A delivery read. */
93
+ export interface GitHubDelivery {
94
+ /** The `X-GitHub-Delivery` GUID: the same for a redelivery, so a receiver applies each id once. */
95
+ id: string;
96
+ /** The `X-GitHub-Event` name when it is an event name (lower case letters, digits and underscores), else `''`. */
97
+ name: string;
98
+ event: GitHubEvent;
99
+ }
100
+ /** What a delivery is read from: its headers and its raw body exactly as received. */
101
+ export interface WebhookDeliveryInput {
102
+ headers: {
103
+ get(name: string): string | null;
104
+ };
105
+ body: Uint8Array;
106
+ }
107
+ /** What a request is read from: a `Request`, or anything with its headers and its body's stream. */
108
+ export interface WebhookRequestInput {
109
+ headers: {
110
+ get(name: string): string | null;
111
+ };
112
+ body: ReadableStream<Uint8Array> | null;
113
+ }
114
+ /** The reader's bound. */
115
+ export interface ReadWebhookOptions {
116
+ /** The largest body read, in bytes ({@link DEFAULT_MAX_DELIVERY_BYTES} when absent). */
117
+ maxBytes?: number;
118
+ }
119
+ /**
120
+ * Reads a delivery already received whole: refuses it past `maxBytes` (`too_large`), when its signature under
121
+ * `secret` does not hold (`signature`), when it has no usable `X-GitHub-Delivery` (`delivery`), or when its signed
122
+ * body is not a JSON object in UTF-8 (`body`), each with {@link WebhookDeliveryRefused}; answers its id, its event's
123
+ * name and its typed event otherwise. A receiver answers GitHub at once and applies each delivery id once: GitHub
124
+ * expects a 2xx within 10 seconds, and a redelivery carries the id of the delivery it repeats.
125
+ *
126
+ * @param input The delivery's headers and its raw body exactly as received.
127
+ * @param secret The webhook's secret, never empty.
128
+ * @param options The largest body read.
129
+ * @throws TypeError when the secret is empty or missing: anyone can sign a delivery under an empty key.
130
+ */
131
+ export declare function readWebhookDelivery(input: WebhookDeliveryInput, secret: string, options?: ReadWebhookOptions): GitHubDelivery;
132
+ /**
133
+ * Reads a delivery from a request: its body read as it streams and refused at `maxBytes` (`too_large`), before any
134
+ * check that needs it whole, the stream then cancelled unread; a `Content-Length` past the cap is refused before a byte
135
+ * is read. Then as {@link readWebhookDelivery}.
136
+ *
137
+ * @param request The request, or its headers and body stream.
138
+ * @param secret The webhook's secret, never empty.
139
+ * @param options The largest body read.
140
+ */
141
+ export declare function readWebhookRequest(request: WebhookRequestInput, secret: string, options?: ReadWebhookOptions): Promise<GitHubDelivery>;
142
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/app/events.ts"],"names":[],"mappings":"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"}