@effected/github 0.17.0 → 0.19.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.
@@ -0,0 +1,183 @@
1
+ import { GitHubError } from "./GitHubError.js";
2
+ import { GitHubClient } from "./GitHubClient.js";
3
+ import { numericId } from "./internal/ids.js";
4
+ import { Context, Effect, Layer, Schema, Stream } from "effect";
5
+
6
+ //#region src/AuthenticatedApp.ts
7
+ /**
8
+ * The GitHub App itself, as `GET /app` reports it.
9
+ *
10
+ * @public
11
+ */
12
+ var AppInfo = class extends Schema.Class("AppInfo")({
13
+ /** The app's numeric id. */
14
+ id: Schema.Int,
15
+ /**
16
+ * The URL slug, e.g. `"my-app"`; the app's bot user is `<slug>[bot]`.
17
+ *
18
+ * @remarks
19
+ * Optional because GitHub's schema for an app declares it optional; the
20
+ * authenticated app's own read is where you would expect it.
21
+ */
22
+ slug: Schema.optionalKey(Schema.String),
23
+ /** The display name. */
24
+ name: Schema.String,
25
+ /** The app's GraphQL node id (wire `node_id`). */
26
+ nodeId: Schema.String,
27
+ /** The app's OAuth client id (wire `client_id`), when GitHub reports one. */
28
+ clientId: Schema.optionalKey(Schema.String),
29
+ /** The app's page on GitHub (wire `html_url`). */
30
+ htmlUrl: Schema.String
31
+ }) {};
32
+ /**
33
+ * One delivery of the app's webhook, as `GET /app/hook/deliveries` lists it.
34
+ *
35
+ * @remarks
36
+ * **Ids are numbers, and refuse to lose precision.** GitHub types a delivery
37
+ * id (and an installation or repository id) as int64, and octokit as
38
+ * `number | bigint`. A response body arrives through `JSON.parse`, which
39
+ * never produces a bigint: an id beyond 2^53 would already have been rounded.
40
+ * Every id here is decoded as a **safe** integer, so such an id fails the read
41
+ * with a typed `decode` error instead of handing back a rounded id that names
42
+ * a different delivery. Today's ids are many orders of magnitude below that
43
+ * line.
44
+ *
45
+ * Encodable: every field is a JSON primitive, so a delivery can be stored as
46
+ * it is.
47
+ *
48
+ * @public
49
+ */
50
+ var DeliveryAttempt = class extends Schema.Class("DeliveryAttempt")({
51
+ /** The delivery's id; pass it to {@link AuthenticatedAppShape.redeliver}. */
52
+ id: Schema.Int,
53
+ /**
54
+ * The event's GUID (the `X-GitHub-Delivery` header). Shared by a delivery
55
+ * and all its redeliveries, so it identifies the event; `id` identifies
56
+ * the attempt.
57
+ */
58
+ guid: Schema.String,
59
+ /** When it was delivered, as GitHub's ISO 8601 string (wire `delivered_at`). */
60
+ deliveredAt: Schema.String,
61
+ /** Whether this attempt was a redelivery. */
62
+ redelivery: Schema.Boolean,
63
+ /** How long the delivery took, in seconds. */
64
+ duration: Schema.Number,
65
+ /** GitHub's description of the outcome, e.g. `"OK"`. */
66
+ status: Schema.String,
67
+ /** The HTTP status your endpoint answered (wire `status_code`); `0` when it never answered. */
68
+ statusCode: Schema.Int,
69
+ /** The event, e.g. `"workflow_run"`. */
70
+ event: Schema.String,
71
+ /** The event's action, e.g. `"completed"`; `null` for an event without one. */
72
+ action: Schema.NullOr(Schema.String),
73
+ /** The installation the event concerns (wire `installation_id`); `null` for none. */
74
+ installationId: Schema.NullOr(Schema.Int),
75
+ /** The repository the event concerns (wire `repository_id`); `null` for none. */
76
+ repositoryId: Schema.NullOr(Schema.Int),
77
+ /** When the delivery was throttled (wire `throttled_at`), when GitHub reports it. */
78
+ throttledAt: Schema.optionalKey(Schema.NullOr(Schema.String))
79
+ }) {};
80
+ /**
81
+ * The app-level REST surface: the app's own record, its webhook delivery log
82
+ * and redelivery, and uninstalling.
83
+ *
84
+ * @remarks
85
+ * Provide {@link AuthenticatedApp.layer} over an App-JWT client from
86
+ * {@link GitHubApp.appClientLayer}. This module imports no JWT signer: the
87
+ * credential is the client's business, so a test drives it with any client.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { AuthenticatedApp, GitHubApp } from "@effected/github";
92
+ * import { DateTime, Effect, Layer, Redacted, Stream } from "effect";
93
+ *
94
+ * // Redeliver every failed delivery from the last hour.
95
+ * const sweep = Effect.gen(function* () {
96
+ * const app = yield* AuthenticatedApp;
97
+ * const since = DateTime.subtract(yield* DateTime.now, { hours: 1 });
98
+ * yield* app.deliveries({ status: "failure" }).pipe(
99
+ * Stream.takeWhile((delivery) => DateTime.isGreaterThan(DateTime.makeUnsafe(delivery.deliveredAt), since)),
100
+ * Stream.runForEach((delivery) => app.redeliver(delivery.id)),
101
+ * );
102
+ * });
103
+ *
104
+ * const layer = AuthenticatedApp.layer.pipe(
105
+ * Layer.provide(
106
+ * GitHubApp.appClientLayer({
107
+ * appId: "12345",
108
+ * privateKey: Redacted.make("-----BEGIN RSA PRIVATE KEY-----\n..."),
109
+ * }),
110
+ * ),
111
+ * );
112
+ *
113
+ * Effect.runPromise(Effect.provide(sweep, layer));
114
+ * ```
115
+ *
116
+ * @public
117
+ */
118
+ var AuthenticatedApp = class AuthenticatedApp extends Context.Service()("@effected/github/AuthenticatedApp") {
119
+ /** The live service, built over an App-JWT `GitHubClient`. */
120
+ static layer = Layer.effect(this, Effect.map(GitHubClient, (client) => make(client)));
121
+ /** An in-memory double; unstubbed members die naming themselves. */
122
+ static makeTest = (overrides = {}) => ({
123
+ get: overrides.get ?? (() => unstubbed("get")),
124
+ deliveries: overrides.deliveries ?? (() => unstubbed("deliveries")),
125
+ delivery: overrides.delivery ?? (() => unstubbed("delivery")),
126
+ redeliver: overrides.redeliver ?? (() => unstubbed("redeliver")),
127
+ uninstall: overrides.uninstall ?? (() => unstubbed("uninstall"))
128
+ });
129
+ /** {@link AuthenticatedApp.makeTest} behind a `Layer`. */
130
+ static layerTest = (overrides = {}) => Layer.succeed(AuthenticatedApp, AuthenticatedApp.makeTest(overrides));
131
+ };
132
+ const unstubbed = (member) => {
133
+ throw new Error(`AuthenticatedApp.makeTest: ${member}() was called but not stubbed — pass an override.`);
134
+ };
135
+ const decodeDelivery = Schema.decodeUnknownEffect(DeliveryAttempt);
136
+ const decodeApp = Schema.decodeUnknownEffect(AppInfo);
137
+ /** A nullable int64 id, narrowed like every other id. */
138
+ const nullableId = (id) => id === null ? null : numericId(id);
139
+ const deliveryOf = (operation, raw) => decodeDelivery(typeof raw !== "object" || raw === null ? raw : {
140
+ id: numericId(raw.id),
141
+ guid: raw.guid,
142
+ deliveredAt: raw.delivered_at,
143
+ redelivery: raw.redelivery,
144
+ duration: raw.duration,
145
+ status: raw.status,
146
+ statusCode: raw.status_code,
147
+ event: raw.event,
148
+ action: raw.action,
149
+ installationId: nullableId(raw.installation_id),
150
+ repositoryId: nullableId(raw.repository_id),
151
+ ...raw.throttled_at !== void 0 ? { throttledAt: raw.throttled_at } : {}
152
+ }).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(GitHubError.decode(operation, "GitHub returned an unexpected webhook delivery", error))));
153
+ const make = (client) => ({
154
+ get: Effect.fn("AuthenticatedApp.get")(function* () {
155
+ const app = yield* client.request("GET /app", {});
156
+ if (app === null) return yield* GitHubError.decode("AuthenticatedApp.get", "GET /app returned no app");
157
+ return yield* decodeApp({
158
+ id: numericId(app.id),
159
+ ...app.slug !== void 0 ? { slug: app.slug } : {},
160
+ name: app.name,
161
+ nodeId: app.node_id,
162
+ ...app.client_id !== void 0 ? { clientId: app.client_id } : {},
163
+ htmlUrl: app.html_url
164
+ }).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(GitHubError.decode("AuthenticatedApp.get", "GitHub returned an unexpected app", error))));
165
+ }),
166
+ deliveries: (options) => client.paginateStream("GET /app/hook/deliveries", options?.status !== void 0 ? { status: options.status } : {}, options?.page).pipe(Stream.mapEffect((raw) => deliveryOf("AuthenticatedApp.deliveries", raw))),
167
+ delivery: Effect.fn("AuthenticatedApp.delivery")(function* (deliveryId) {
168
+ yield* Effect.annotateCurrentSpan({ deliveryId });
169
+ const raw = yield* client.request("GET /app/hook/deliveries/{delivery_id}", { delivery_id: deliveryId });
170
+ return yield* deliveryOf("AuthenticatedApp.delivery", raw);
171
+ }),
172
+ redeliver: Effect.fn("AuthenticatedApp.redeliver")(function* (deliveryId) {
173
+ yield* Effect.annotateCurrentSpan({ deliveryId });
174
+ yield* client.request("POST /app/hook/deliveries/{delivery_id}/attempts", { delivery_id: deliveryId });
175
+ }),
176
+ uninstall: Effect.fn("AuthenticatedApp.uninstall")(function* (installationId) {
177
+ yield* Effect.annotateCurrentSpan({ installationId });
178
+ yield* client.request("DELETE /app/installations/{installation_id}", { installation_id: installationId });
179
+ })
180
+ });
181
+
182
+ //#endregion
183
+ export { AppInfo, AuthenticatedApp, DeliveryAttempt };
package/CheckRun.js CHANGED
@@ -15,6 +15,48 @@ const CheckConclusion = Schema.Literals([
15
15
  "action_required",
16
16
  "skipped"
17
17
  ]);
18
+ /**
19
+ * The phase of its lifecycle a check run is in, as GitHub reports it.
20
+ *
21
+ * @remarks
22
+ * `"waiting"`, `"requested"` and `"pending"` are reserved for GitHub Actions
23
+ * runs; an integrator can only write `"queued"`, `"in_progress"` and, through
24
+ * {@link CheckRunShape.complete}, `"completed"`.
25
+ *
26
+ * @public
27
+ */
28
+ const CheckRunStatus = Schema.Literals([
29
+ "queued",
30
+ "in_progress",
31
+ "completed",
32
+ "waiting",
33
+ "requested",
34
+ "pending"
35
+ ]);
36
+ /**
37
+ * How a check run finished, as GitHub reports it: every
38
+ * {@link CheckConclusion} plus `"stale"`.
39
+ *
40
+ * @remarks
41
+ * GitHub's check-run response schema omits `"stale"`, but its update
42
+ * endpoint documents it: *"You cannot change a check run conclusion to
43
+ * `stale`, only GitHub can set this."* GitHub sets it on a run left
44
+ * incomplete too long, so a read that refused it would fail on any commit
45
+ * carrying one. It is read-only, which is why {@link CheckConclusion}, the
46
+ * write set, does not include it.
47
+ *
48
+ * @public
49
+ */
50
+ const ReportedCheckConclusion = Schema.Literals([
51
+ "success",
52
+ "failure",
53
+ "neutral",
54
+ "cancelled",
55
+ "timed_out",
56
+ "action_required",
57
+ "skipped",
58
+ "stale"
59
+ ]);
18
60
  /** How serious an annotation is. @public */
19
61
  const AnnotationLevel = Schema.Literals([
20
62
  "notice",
@@ -113,22 +155,76 @@ const capBytes = (value) => {
113
155
  return `${cut}${CheckRunOutput.NOTICE}`;
114
156
  };
115
157
  /**
158
+ * The rendered output a check run reports: its title and summary, and how
159
+ * many annotations it carries.
160
+ *
161
+ * @remarks
162
+ * The read-side counterpart of {@link CheckRunOutput}. It leaves out the
163
+ * long-form `text` deliberately: it can run to 65535 bytes, and a caller
164
+ * listing a commit's runs rarely wants it. Read the run's full output through
165
+ * the typed request surface when you do.
166
+ *
167
+ * @public
168
+ */
169
+ var ReportedCheckRunOutput = class extends Schema.Class("ReportedCheckRunOutput")({
170
+ /** The output's title; `null` when the run has none. */
171
+ title: Schema.NullOr(Schema.String),
172
+ /** The output's markdown summary; `null` when the run has none. */
173
+ summary: Schema.NullOr(Schema.String),
174
+ /** How many annotations the run carries (wire `annotations_count`). */
175
+ annotationsCount: Schema.Int
176
+ }) {};
177
+ /**
116
178
  * A check run as GitHub reports it.
117
179
  *
180
+ * @remarks
181
+ * Every field beyond the original five (the four required ones and
182
+ * `externalId`) is optional, so a test double built with
183
+ * `CheckRunRef.make({ id, name, url, status })` stays valid; a run decoded
184
+ * from a GitHub response carries all of them, because GitHub always sends
185
+ * them. A nullable field is `null` when GitHub reported `null`.
186
+ *
187
+ * **Three URLs, named apart.** `url` is the **web** URL (wire `html_url`, or
188
+ * `""` when GitHub reported none), kept under that name so existing callers
189
+ * read what they always read. `htmlUrl` is the same wire field with its
190
+ * `null` preserved, `apiUrl` is the REST URL (wire `url`), and `detailsUrl`
191
+ * is the integrator's own link (wire `details_url`).
192
+ *
118
193
  * @public
119
194
  */
120
195
  var CheckRunRef = class extends Schema.Class("CheckRunRef")({
121
196
  id: Schema.Int,
122
197
  name: Schema.String,
123
- /** The web URL. */
198
+ /** The web URL (wire `html_url`), or `""` when GitHub reported none. See also `htmlUrl`. */
124
199
  url: Schema.String,
125
- status: Schema.String,
200
+ /** The run's lifecycle phase. */
201
+ status: CheckRunStatus,
126
202
  /**
127
203
  * The integrator's own id for the run (wire `external_id`), when it has
128
204
  * one. GitHub reports a run created without one as `null` or `""`; both
129
205
  * leave this absent.
130
206
  */
131
- externalId: Schema.optionalKey(Schema.String)
207
+ externalId: Schema.optionalKey(Schema.String),
208
+ /** The commit the run checks (wire `head_sha`). */
209
+ headSha: Schema.optionalKey(Schema.String),
210
+ /** The run's GraphQL node id (wire `node_id`). */
211
+ nodeId: Schema.optionalKey(Schema.String),
212
+ /** How the run finished; `null` until it completes. */
213
+ conclusion: Schema.optionalKey(Schema.NullOr(ReportedCheckConclusion)),
214
+ /** When the run started, as GitHub's ISO 8601 string; `null` for a run that has not. */
215
+ startedAt: Schema.optionalKey(Schema.NullOr(Schema.String)),
216
+ /** When the run completed, as GitHub's ISO 8601 string; `null` for a run that has not. */
217
+ completedAt: Schema.optionalKey(Schema.NullOr(Schema.String)),
218
+ /** The integrator's link for the run (wire `details_url`). */
219
+ detailsUrl: Schema.optionalKey(Schema.NullOr(Schema.String)),
220
+ /** The web URL (wire `html_url`), `null` preserved. */
221
+ htmlUrl: Schema.optionalKey(Schema.NullOr(Schema.String)),
222
+ /** The run's REST API URL (wire `url`). */
223
+ apiUrl: Schema.optionalKey(Schema.String),
224
+ /** The check suite the run belongs to (wire `check_suite.id`); `null` when GitHub reported none. */
225
+ checkSuiteId: Schema.optionalKey(Schema.NullOr(Schema.Int)),
226
+ /** The run's title, summary and annotation count. */
227
+ output: Schema.optionalKey(ReportedCheckRunOutput)
132
228
  }) {};
133
229
  /**
134
230
  * Create, update and conclude GitHub check runs, including the
@@ -148,8 +244,11 @@ var CheckRun = class CheckRun extends Context.Service()("@effected/github/CheckR
148
244
  create: overrides.create ?? (() => unstubbed("create")),
149
245
  get: overrides.get ?? (() => unstubbed("get")),
150
246
  update: overrides.update ?? (() => unstubbed("update")),
247
+ updateRef: overrides.updateRef ?? (() => unstubbed("updateRef")),
248
+ list: overrides.list ?? (() => unstubbed("list")),
151
249
  findByExternalId: overrides.findByExternalId ?? (() => unstubbed("findByExternalId")),
152
250
  complete: overrides.complete ?? (() => unstubbed("complete")),
251
+ completeRef: overrides.completeRef ?? (() => unstubbed("completeRef")),
153
252
  withCheckRun: overrides.withCheckRun ?? (() => unstubbed("withCheckRun"))
154
253
  });
155
254
  /** {@link CheckRun.makeTest} behind a `Layer`. */
@@ -226,6 +325,19 @@ const concludeFor = (name, id, exit, recorded, complete) => {
226
325
  return Exit.isSuccess(exit) ? write : Effect.ignore(write);
227
326
  };
228
327
  const decodeRef = Schema.decodeUnknownEffect(CheckRunRef);
328
+ /** Whether a wire value is an object whose fields can be read. */
329
+ const isRecord = (value) => typeof value === "object" && value !== null;
330
+ /**
331
+ * A nested wire object's fields, renamed for the schema, or the value itself
332
+ * when it is not an object.
333
+ *
334
+ * @remarks
335
+ * Handing the raw value through is what keeps a malformed response typed: a
336
+ * `null` `output` (which GitHub's schema forbids) reaches the decoder and fails
337
+ * as `decode` instead of throwing a `TypeError` while its fields are read,
338
+ * which would be a defect escaping every `GitHubError` handler.
339
+ */
340
+ const nested = (value, project) => isRecord(value) ? project(value) : value;
229
341
  /**
230
342
  * Project a check-run response onto {@link CheckRunRef}, **decoding** it.
231
343
  *
@@ -233,14 +345,30 @@ const decodeRef = Schema.decodeUnknownEffect(CheckRunRef);
233
345
  * Decoded rather than built with `make`, which throws: a response missing a
234
346
  * field (a hand-written double, or GitHub changing shape) is input, and input
235
347
  * failures are a typed `decode` `GitHubError` naming the operation rather than
236
- * a defect.
348
+ * a defect. That includes a status or conclusion outside the literal sets:
349
+ * GitHub adding one fails the read loudly instead of passing an unknown
350
+ * string to a caller's exhaustive switch.
237
351
  */
238
- const refOf = (operation, raw) => decodeRef({
352
+ const refOf = (operation, raw) => decodeRef(!isRecord(raw) ? raw : {
239
353
  id: numericId(raw.id),
240
354
  name: raw.name,
241
355
  url: raw.html_url ?? "",
242
356
  status: raw.status,
243
- ...raw.external_id ? { externalId: raw.external_id } : {}
357
+ ...raw.external_id ? { externalId: raw.external_id } : {},
358
+ ...raw.head_sha !== void 0 ? { headSha: raw.head_sha } : {},
359
+ ...raw.node_id !== void 0 ? { nodeId: raw.node_id } : {},
360
+ ...raw.conclusion !== void 0 ? { conclusion: raw.conclusion } : {},
361
+ ...raw.started_at !== void 0 ? { startedAt: raw.started_at } : {},
362
+ ...raw.completed_at !== void 0 ? { completedAt: raw.completed_at } : {},
363
+ ...raw.details_url !== void 0 ? { detailsUrl: raw.details_url } : {},
364
+ ...raw.html_url !== void 0 ? { htmlUrl: raw.html_url } : {},
365
+ ...raw.url !== void 0 ? { apiUrl: raw.url } : {},
366
+ ...raw.check_suite !== void 0 ? { checkSuiteId: nested(raw.check_suite, (suite) => typeof suite.id === "number" || typeof suite.id === "bigint" ? numericId(suite.id) : suite.id) } : {},
367
+ ...raw.output !== void 0 ? { output: nested(raw.output, (output) => ({
368
+ title: output.title,
369
+ summary: output.summary,
370
+ annotationsCount: output.annotations_count
371
+ })) } : {}
244
372
  }).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(GitHubError.decode(operation, "GitHub returned an unexpected check run", error))));
245
373
  /** The current time as GitHub's ISO 8601 timestamp, from `Clock` so `TestClock` drives it. */
246
374
  const isoNow = Effect.map(DateTime.now, DateTime.formatIso);
@@ -267,7 +395,17 @@ const make = (client) => {
267
395
  });
268
396
  return yield* refOf("CheckRun.create", created);
269
397
  });
270
- const complete = Effect.fn("CheckRun.complete")(function* (id, conclusion, output, options) {
398
+ /**
399
+ * The completing PATCH, answering GitHub's raw response.
400
+ *
401
+ * @remarks
402
+ * Shared by `complete`, which discards the response, and `completeRef`,
403
+ * which decodes it. Only the second can fail on an unexpected response:
404
+ * `complete` runs inside the bracket's finalizer, and a run GitHub has
405
+ * already concluded must not fail the program over a field it did not ask
406
+ * to read.
407
+ */
408
+ const completePatch = (id, conclusion, output, options) => Effect.gen(function* () {
271
409
  const { owner, repo } = yield* Repo;
272
410
  yield* Effect.annotateCurrentSpan({
273
411
  owner,
@@ -275,7 +413,7 @@ const make = (client) => {
275
413
  id,
276
414
  conclusion
277
415
  });
278
- yield* client.request("PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}", {
416
+ return yield* client.request("PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}", {
279
417
  owner,
280
418
  repo,
281
419
  check_run_id: id,
@@ -286,6 +424,30 @@ const make = (client) => {
286
424
  ...options?.detailsUrl !== void 0 ? { details_url: options.detailsUrl } : {}
287
425
  });
288
426
  });
427
+ const complete = Effect.fn("CheckRun.complete")(function* (id, conclusion, output, options) {
428
+ yield* completePatch(id, conclusion, output, options);
429
+ });
430
+ const completeRef = Effect.fn("CheckRun.completeRef")(function* (id, conclusion, output, options) {
431
+ return yield* refOf("CheckRun.completeRef", yield* completePatch(id, conclusion, output, options));
432
+ });
433
+ /** The updating PATCH, answering GitHub's raw response; see `completePatch` for why it is shared. */
434
+ const updatePatch = (id, output, options) => Effect.gen(function* () {
435
+ const { owner, repo } = yield* Repo;
436
+ yield* Effect.annotateCurrentSpan({
437
+ owner,
438
+ repo,
439
+ id
440
+ });
441
+ return yield* client.request("PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}", {
442
+ owner,
443
+ repo,
444
+ check_run_id: id,
445
+ ...output !== void 0 ? { output: wireOutput(output) } : {},
446
+ ...options?.status !== void 0 ? { status: options.status } : {},
447
+ ...options?.status === "in_progress" ? { started_at: yield* isoNow } : {},
448
+ ...options?.detailsUrl !== void 0 ? { details_url: options.detailsUrl } : {}
449
+ });
450
+ });
289
451
  return {
290
452
  create,
291
453
  complete,
@@ -304,21 +466,29 @@ const make = (client) => {
304
466
  return yield* refOf("CheckRun.get", raw);
305
467
  }),
306
468
  update: Effect.fn("CheckRun.update")(function* (id, output, options) {
469
+ yield* updatePatch(id, output, options);
470
+ }),
471
+ updateRef: Effect.fn("CheckRun.updateRef")(function* (id, output, options) {
472
+ return yield* refOf("CheckRun.updateRef", yield* updatePatch(id, output, options));
473
+ }),
474
+ completeRef,
475
+ list: Effect.fn("CheckRun.list")(function* (ref, options) {
307
476
  const { owner, repo } = yield* Repo;
308
477
  yield* Effect.annotateCurrentSpan({
309
478
  owner,
310
479
  repo,
311
- id
480
+ ref
312
481
  });
313
- yield* client.request("PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}", {
482
+ const runs = yield* client.paginate("GET /repos/{owner}/{repo}/commits/{ref}/check-runs", {
314
483
  owner,
315
484
  repo,
316
- check_run_id: id,
317
- ...output !== void 0 ? { output: wireOutput(output) } : {},
485
+ ref,
486
+ ...options?.checkName !== void 0 ? { check_name: options.checkName } : {},
487
+ ...options?.appId !== void 0 ? { app_id: options.appId } : {},
318
488
  ...options?.status !== void 0 ? { status: options.status } : {},
319
- ...options?.status === "in_progress" ? { started_at: yield* isoNow } : {},
320
- ...options?.detailsUrl !== void 0 ? { details_url: options.detailsUrl } : {}
321
- });
489
+ ...options?.filter !== void 0 ? { filter: options.filter } : {}
490
+ }, options?.page);
491
+ return yield* Effect.forEach(runs, (run) => refOf("CheckRun.list", run));
322
492
  }),
323
493
  findByExternalId: Effect.fn("CheckRun.findByExternalId")(function* (headSha, name, externalId) {
324
494
  if (externalId === "") return Option.none();
@@ -357,4 +527,4 @@ const make = (client) => {
357
527
  };
358
528
 
359
529
  //#endregion
360
- export { Annotation, AnnotationLevel, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef };
530
+ export { Annotation, AnnotationLevel, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CheckRunStatus, ReportedCheckConclusion, ReportedCheckRunOutput };
package/GitHubApp.js CHANGED
@@ -4,7 +4,7 @@ import { GitHubClient, makeClientShape } from "./GitHubClient.js";
4
4
  import { numericId } from "./internal/ids.js";
5
5
  import { InstallationTokenStore } from "./InstallationTokenStore.js";
6
6
  import { Jwt, JwtKey } from "@effected/jwt";
7
- import { Cause, Clock, Context, DateTime, Duration, Effect, Layer, Option, Redacted, Ref, Schema, Semaphore, Stream } from "effect";
7
+ import { Cause, Clock, Context, DateTime, Deferred, Duration, Effect, Layer, Option, Redacted, Ref, Schema, Semaphore, Stream } from "effect";
8
8
 
9
9
  //#region src/GitHubApp.ts
10
10
  /**
@@ -163,6 +163,21 @@ var AppIdentity = class extends Schema.Class("AppIdentity")({
163
163
  });
164
164
  }
165
165
  };
166
+ /**
167
+ * An app's bot user: the account its installation tokens act as.
168
+ *
169
+ * @remarks
170
+ * `id` is what to compare against an actor id on an event, such as
171
+ * `workflow_run.triggering_actor.id`: a login can be renamed, an id cannot.
172
+ *
173
+ * @public
174
+ */
175
+ var BotUser = class extends Schema.Class("BotUser")({
176
+ /** The bot user's numeric id. */
177
+ id: Schema.Int,
178
+ /** The bot user's login, `<slug>[bot]`. */
179
+ login: Schema.String
180
+ }) {};
166
181
  /** `suspended_at` as GitHub sends it: an ISO string, or `null` while active. */
167
182
  const SuspendedAt = Schema.OptionFromNullOr(Schema.DateTimeUtcFromString);
168
183
  /**
@@ -358,14 +373,23 @@ var GitHubApp = class GitHubApp extends Context.Service()("@effected/github/GitH
358
373
  * **A cached token is never revoked**: another scope or isolate may be using
359
374
  * it. It expires on its own, within the hour.
360
375
  *
361
- * Two concurrent calls that both miss will both mint, and the later write
362
- * wins. That is expected: the store may span isolates, so the kit cannot
363
- * lock it, and an extra token costs one call and expires on its own.
376
+ * Within one process, concurrent misses for one installation are
377
+ * **single-flight**: the first caller mints and the others wait for that
378
+ * mint and return the same token with `source: "joined"`, so a batch that
379
+ * fans out over one installation on a cold store costs one mint, not one
380
+ * per fiber. The in-flight record lives with the `GitHubApp` service and is
381
+ * released when the mint settles, however it settles: a failed mint fails
382
+ * every waiter with the same `GitHubAppError`, and the next call mints
383
+ * again. Interrupting the leader does not strand the waiters: the mint runs
384
+ * in its own fiber and completes for them. Across isolates, two misses
385
+ * still both mint and the later write wins. That is expected: the store may
386
+ * span isolates, so the kit cannot lock it, and an extra token costs one
387
+ * call and expires on its own.
364
388
  *
365
389
  * The encoded value written to the store contains the raw token, so
366
390
  * encrypting it at rest is the store's job.
367
391
  */
368
- static cachedToken = (request) => cachedTokenFor(request);
392
+ static cachedToken = (request) => Effect.flatMap(GitHubApp, (app) => app.cachedToken(request));
369
393
  /**
370
394
  * A {@link GitHubClient} authenticated with {@link GitHubApp.cachedToken}.
371
395
  *
@@ -407,18 +431,23 @@ var GitHubApp = class GitHubApp extends Context.Service()("@effected/github/GitH
407
431
  * Effect.runPromise(Effect.provide(handle(42), Live));
408
432
  * ```
409
433
  */
410
- static cachedClientLayer = (request, options = {}) => Layer.unwrap(Effect.map(cachedTokenFor(request), (cached) => GitHubClient.layerFromToken({
434
+ static cachedClientLayer = (request, options = {}) => Layer.unwrap(Effect.map(GitHubApp.cachedToken(request), (cached) => GitHubClient.layerFromToken({
411
435
  ...options,
412
436
  token: cached.token.token
413
437
  })));
414
438
  /** An in-memory double; unstubbed members die naming themselves. */
415
- static makeTest = (overrides = {}) => ({
416
- token: overrides.token ?? (() => unstubbed("token")),
417
- scopedToken: overrides.scopedToken ?? (() => unstubbed("scopedToken")),
418
- revoke: overrides.revoke ?? (() => unstubbed("revoke")),
419
- identity: overrides.identity ?? (() => unstubbed("identity")),
420
- installations: overrides.installations ?? (() => unstubbed("installations"))
421
- });
439
+ static makeTest = (overrides = {}) => {
440
+ const token = overrides.token ?? (() => unstubbed("token"));
441
+ return {
442
+ token,
443
+ scopedToken: overrides.scopedToken ?? (() => unstubbed("scopedToken")),
444
+ revoke: overrides.revoke ?? (() => unstubbed("revoke")),
445
+ identity: overrides.identity ?? (() => unstubbed("identity")),
446
+ botUser: overrides.botUser ?? (() => unstubbed("botUser")),
447
+ installations: overrides.installations ?? (() => unstubbed("installations")),
448
+ cachedToken: overrides.cachedToken ?? makeCachedToken(token)
449
+ };
450
+ };
422
451
  /** {@link GitHubApp.makeTest} behind a `Layer`. */
423
452
  static layerTest = (overrides = {}) => Layer.succeed(GitHubApp, GitHubApp.makeTest(overrides));
424
453
  };
@@ -428,33 +457,64 @@ const DEFAULT_CACHE_MARGIN = Duration.minutes(5);
428
457
  const StoredToken = Schema.fromJsonString(InstallationToken);
429
458
  /** A store call that can never fail its caller: failures and defects become `fallback`; interruption propagates. */
430
459
  const swallowStore = (effect, fallback) => Effect.catchCause(effect, (cause) => Cause.hasInterruptsOnly(cause) ? Effect.failCause(cause) : Effect.succeed(fallback));
431
- const cachedTokenFor = Effect.fn("GitHubApp.cachedToken")(function* (request) {
432
- const input = request.margin ?? DEFAULT_CACHE_MARGIN;
433
- const margin = typeof input === "number" && !Number.isFinite(input) ? Option.none() : Option.filter(Duration.fromInput(input), (duration) => Duration.isFinite(duration) && !Duration.isNegative(duration));
434
- if (Option.isNone(margin)) return yield* GitHubAppError.of("token", "the cache margin must be a finite, non-negative duration");
435
- const app = yield* GitHubApp;
436
- const store = yield* InstallationTokenStore;
437
- const stored = yield* swallowStore(store.get(request.installationId), Option.none());
438
- if (Option.isSome(stored)) {
439
- const decoded = yield* Effect.option(Schema.decodeUnknownEffect(StoredToken)(stored.value));
440
- const now = yield* Clock.currentTimeMillis;
441
- if (Option.isSome(decoded) && decoded.value.installationId === request.installationId && !decoded.value.isExpired(now, margin.value)) return {
442
- token: decoded.value,
443
- source: "cached"
460
+ /**
461
+ * The caching read over `token`, with one in-flight mint per installation.
462
+ *
463
+ * @remarks
464
+ * The map is the single-flight record. A key is present exactly while a mint
465
+ * for that installation is running in this process; the first miss creates it
466
+ * and forks the mint, later misses await the same `Deferred`, and the mint's
467
+ * exit finalizer deletes the key before completing the `Deferred` with
468
+ * whatever exit the mint produced, so a failed mint fails every waiter with the
469
+ * same error and never pins the key. The mint is forked detached from the
470
+ * leader, so the leader being interrupted does not interrupt the mint the
471
+ * waiters depend on; the leader itself just stops waiting. The key is the
472
+ * installation id alone because that is also the store's key: a `TokenRequest`
473
+ * cannot narrow a token, so two requests for one installation ask for the same
474
+ * token.
475
+ */
476
+ const makeCachedToken = (token) => {
477
+ const inFlight = /* @__PURE__ */ new Map();
478
+ return Effect.fn("GitHubApp.cachedToken")(function* (request) {
479
+ const input = request.margin ?? DEFAULT_CACHE_MARGIN;
480
+ const margin = typeof input === "number" && !Number.isFinite(input) ? Option.none() : Option.filter(Duration.fromInput(input), (duration) => Duration.isFinite(duration) && !Duration.isNegative(duration));
481
+ if (Option.isNone(margin)) return yield* GitHubAppError.of("token", "the cache margin must be a finite, non-negative duration");
482
+ const store = yield* InstallationTokenStore;
483
+ const stored = yield* swallowStore(store.get(request.installationId), Option.none());
484
+ if (Option.isSome(stored)) {
485
+ const decoded = yield* Effect.option(Schema.decodeUnknownEffect(StoredToken)(stored.value));
486
+ const now = yield* Clock.currentTimeMillis;
487
+ if (Option.isSome(decoded) && decoded.value.installationId === request.installationId && !decoded.value.isExpired(now, margin.value)) return {
488
+ token: decoded.value,
489
+ source: "cached"
490
+ };
491
+ }
492
+ const joined = inFlight.get(request.installationId);
493
+ if (joined !== void 0) return {
494
+ token: yield* Deferred.await(joined),
495
+ source: "joined"
444
496
  };
445
- }
446
- const minted = yield* app.token(request);
447
- const now = yield* Clock.currentTimeMillis;
448
- const ttlMillis = DateTime.toEpochMillis(minted.expiresAt) - Duration.toMillis(margin.value) - now;
449
- if (ttlMillis > 0) {
450
- const encoded = yield* Effect.option(Schema.encodeUnknownEffect(StoredToken)(minted));
451
- if (Option.isSome(encoded)) yield* swallowStore(store.set(request.installationId, encoded.value, Duration.millis(ttlMillis)), void 0);
452
- }
453
- return {
454
- token: minted,
455
- source: "minted"
456
- };
457
- });
497
+ const deferred = Deferred.makeUnsafe();
498
+ const mint = Effect.gen(function* () {
499
+ const minted = yield* token(request);
500
+ const now = yield* Clock.currentTimeMillis;
501
+ const ttlMillis = DateTime.toEpochMillis(minted.expiresAt) - Duration.toMillis(margin.value) - now;
502
+ if (ttlMillis > 0) {
503
+ const encoded = yield* Effect.option(Schema.encodeUnknownEffect(StoredToken)(minted));
504
+ if (Option.isSome(encoded)) yield* swallowStore(store.set(request.installationId, encoded.value, Duration.millis(ttlMillis)), void 0);
505
+ }
506
+ return minted;
507
+ }).pipe(Effect.onExit((exit) => Effect.andThen(Effect.sync(() => inFlight.delete(request.installationId)), Deferred.done(deferred, exit))));
508
+ yield* Effect.uninterruptible(Effect.suspend(() => {
509
+ inFlight.set(request.installationId, deferred);
510
+ return Effect.forkDetach(mint);
511
+ }));
512
+ return {
513
+ token: yield* Deferred.await(deferred),
514
+ source: "minted"
515
+ };
516
+ });
517
+ };
458
518
  const unstubbed = (member) => {
459
519
  throw new Error(`GitHubApp.makeTest: ${member}() was called but not stubbed — pass an override.`);
460
520
  };
@@ -541,7 +601,17 @@ function makeApp(options) {
541
601
  ...Option.isSome(user) ? { userId: numericId(user.value.id) } : {}
542
602
  });
543
603
  }),
544
- installations
604
+ botUser: Effect.fn("GitHubApp.botUser")(function* (request) {
605
+ yield* Effect.annotateCurrentSpan({ slug: request.slug });
606
+ const user = yield* (yield* asBearer(request.installationToken, options)).request("GET /users/{username}", { username: `${request.slug}[bot]` }).pipe(Effect.catch(appFailure("identity")));
607
+ const raw = user;
608
+ return yield* Schema.decodeUnknownEffect(BotUser)(typeof raw === "object" && raw !== null ? {
609
+ id: numericId(user.id),
610
+ login: user.login
611
+ } : raw).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(GitHubAppError.of("identity", "GitHub returned an unexpected bot user", error))));
612
+ }),
613
+ installations,
614
+ cachedToken: makeCachedToken(token)
545
615
  };
546
616
  });
547
617
  }
@@ -614,4 +684,4 @@ const makeRotatingClient = (mint, release, options, operation) => Effect.gen(fun
614
684
  });
615
685
 
616
686
  //#endregion
617
- export { AppIdentity, BotIdentity, GitHubApp, GitHubAppError, Installation, InstallationToken };
687
+ export { AppIdentity, BotIdentity, BotUser, GitHubApp, GitHubAppError, Installation, InstallationToken };
package/index.d.ts CHANGED
@@ -1303,9 +1303,230 @@ export declare class Attestation extends Attestation_base {
1303
1303
  static readonly layerTest: (overrides?: Partial<AttestationShape>) => Layer.Layer<Attestation>;
1304
1304
  }
1305
1305
  //#endregion
1306
+ //#region src/AuthenticatedApp.d.ts
1307
+ declare const AppInfo_base: Schema.Class<AppInfo, Schema.Struct<{
1308
+ /** The app's numeric id. */
1309
+ readonly id: Schema.Int;
1310
+ /**
1311
+ * The URL slug, e.g. `"my-app"`; the app's bot user is `<slug>[bot]`.
1312
+ *
1313
+ * @remarks
1314
+ * Optional because GitHub's schema for an app declares it optional; the
1315
+ * authenticated app's own read is where you would expect it.
1316
+ */
1317
+ readonly slug: Schema.optionalKey<Schema.String>;
1318
+ /** The display name. */
1319
+ readonly name: Schema.String;
1320
+ /** The app's GraphQL node id (wire `node_id`). */
1321
+ readonly nodeId: Schema.String;
1322
+ /** The app's OAuth client id (wire `client_id`), when GitHub reports one. */
1323
+ readonly clientId: Schema.optionalKey<Schema.String>;
1324
+ /** The app's page on GitHub (wire `html_url`). */
1325
+ readonly htmlUrl: Schema.String;
1326
+ }>, {}>;
1327
+ /**
1328
+ * The GitHub App itself, as `GET /app` reports it.
1329
+ *
1330
+ * @public
1331
+ */
1332
+ export declare class AppInfo extends AppInfo_base {}
1333
+ declare const DeliveryAttempt_base: Schema.Class<DeliveryAttempt, Schema.Struct<{
1334
+ /** The delivery's id; pass it to {@link AuthenticatedAppShape.redeliver}. */
1335
+ readonly id: Schema.Int;
1336
+ /**
1337
+ * The event's GUID (the `X-GitHub-Delivery` header). Shared by a delivery
1338
+ * and all its redeliveries, so it identifies the event; `id` identifies
1339
+ * the attempt.
1340
+ */
1341
+ readonly guid: Schema.String;
1342
+ /** When it was delivered, as GitHub's ISO 8601 string (wire `delivered_at`). */
1343
+ readonly deliveredAt: Schema.String;
1344
+ /** Whether this attempt was a redelivery. */
1345
+ readonly redelivery: Schema.Boolean;
1346
+ /** How long the delivery took, in seconds. */
1347
+ readonly duration: Schema.Number;
1348
+ /** GitHub's description of the outcome, e.g. `"OK"`. */
1349
+ readonly status: Schema.String;
1350
+ /** The HTTP status your endpoint answered (wire `status_code`); `0` when it never answered. */
1351
+ readonly statusCode: Schema.Int;
1352
+ /** The event, e.g. `"workflow_run"`. */
1353
+ readonly event: Schema.String;
1354
+ /** The event's action, e.g. `"completed"`; `null` for an event without one. */
1355
+ readonly action: Schema.NullOr<Schema.String>;
1356
+ /** The installation the event concerns (wire `installation_id`); `null` for none. */
1357
+ readonly installationId: Schema.NullOr<Schema.Int>;
1358
+ /** The repository the event concerns (wire `repository_id`); `null` for none. */
1359
+ readonly repositoryId: Schema.NullOr<Schema.Int>;
1360
+ /** When the delivery was throttled (wire `throttled_at`), when GitHub reports it. */
1361
+ readonly throttledAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
1362
+ }>, {}>;
1363
+ /**
1364
+ * One delivery of the app's webhook, as `GET /app/hook/deliveries` lists it.
1365
+ *
1366
+ * @remarks
1367
+ * **Ids are numbers, and refuse to lose precision.** GitHub types a delivery
1368
+ * id (and an installation or repository id) as int64, and octokit as
1369
+ * `number | bigint`. A response body arrives through `JSON.parse`, which
1370
+ * never produces a bigint: an id beyond 2^53 would already have been rounded.
1371
+ * Every id here is decoded as a **safe** integer, so such an id fails the read
1372
+ * with a typed `decode` error instead of handing back a rounded id that names
1373
+ * a different delivery. Today's ids are many orders of magnitude below that
1374
+ * line.
1375
+ *
1376
+ * Encodable: every field is a JSON primitive, so a delivery can be stored as
1377
+ * it is.
1378
+ *
1379
+ * @public
1380
+ */
1381
+ export declare class DeliveryAttempt extends DeliveryAttempt_base {}
1382
+ /**
1383
+ * Options for {@link AuthenticatedAppShape.deliveries}.
1384
+ *
1385
+ * @public
1386
+ */
1387
+ interface DeliveriesOptions {
1388
+ /**
1389
+ * Only deliveries that succeeded or failed, filtered by GitHub. A delivery
1390
+ * is a failure when your endpoint did not answer with a 2xx.
1391
+ */
1392
+ readonly status?: "success" | "failure" | undefined;
1393
+ /** How far to page. Unset, pages of 100 until GitHub stops. */
1394
+ readonly page?: PageOptions | undefined;
1395
+ }
1396
+ /**
1397
+ * The app-level REST surface: the app's own record, its webhook deliveries and
1398
+ * removing an installation.
1399
+ *
1400
+ * @remarks
1401
+ * Every member needs a `GitHubClient` authenticated **as the app** (an App
1402
+ * JWT), which is what {@link GitHubApp.appClientLayer} provides; an
1403
+ * installation token answers these routes with 401. No member needs a `Repo`.
1404
+ *
1405
+ * @public
1406
+ */
1407
+ interface AuthenticatedAppShape {
1408
+ /** The app itself (`GET /app`). */
1409
+ readonly get: () => Effect.Effect<AppInfo, GitHubError>;
1410
+ /**
1411
+ * The app's webhook deliveries, newest first (`GET /app/hook/deliveries`).
1412
+ *
1413
+ * @remarks
1414
+ * **Lazy in requests**: a page is fetched only when the stream is pulled
1415
+ * past the previous one, so `Stream.takeWhile` on `deliveredAt` stops a
1416
+ * sweep at the window's edge without reading the rest of the log. GitHub
1417
+ * pages this route by cursor; the walk follows its `Link` header.
1418
+ *
1419
+ * Each delivery is decoded as it arrives; a malformed one fails the stream
1420
+ * with a `decode` `GitHubError`.
1421
+ */
1422
+ readonly deliveries: (options?: DeliveriesOptions) => Stream.Stream<DeliveryAttempt, GitHubError>;
1423
+ /**
1424
+ * One delivery attempt (`GET /app/hook/deliveries/{delivery_id}`).
1425
+ *
1426
+ * @remarks
1427
+ * Projected onto the same {@link DeliveryAttempt} the listing answers; the
1428
+ * request and response payloads GitHub also returns are not kept. Read them
1429
+ * through the typed request surface when you need them.
1430
+ */
1431
+ readonly delivery: (deliveryId: number) => Effect.Effect<DeliveryAttempt, GitHubError>;
1432
+ /**
1433
+ * Ask GitHub to deliver an attempt's event again
1434
+ * (`POST /app/hook/deliveries/{delivery_id}/attempts`).
1435
+ *
1436
+ * @remarks
1437
+ * GitHub answers 202: the redelivery is queued, not done, and appears in
1438
+ * {@link AuthenticatedAppShape.deliveries} as a new attempt with the same
1439
+ * `guid` and `redelivery: true`.
1440
+ */
1441
+ readonly redeliver: (deliveryId: number) => Effect.Effect<void, GitHubError>;
1442
+ /**
1443
+ * Uninstall the app from an account
1444
+ * (`DELETE /app/installations/{installation_id}`).
1445
+ *
1446
+ * @remarks
1447
+ * Irreversible from the app's side: only the account can install it again.
1448
+ * An installation that does not exist (or is already gone) fails with
1449
+ * `GitHubError { kind: "notFound" }`.
1450
+ */
1451
+ readonly uninstall: (installationId: number) => Effect.Effect<void, GitHubError>;
1452
+ }
1453
+ declare const AuthenticatedApp_base: Context.ServiceClass<AuthenticatedApp, "@effected/github/AuthenticatedApp", AuthenticatedAppShape>;
1454
+ /**
1455
+ * The app-level REST surface: the app's own record, its webhook delivery log
1456
+ * and redelivery, and uninstalling.
1457
+ *
1458
+ * @remarks
1459
+ * Provide {@link AuthenticatedApp.layer} over an App-JWT client from
1460
+ * {@link GitHubApp.appClientLayer}. This module imports no JWT signer: the
1461
+ * credential is the client's business, so a test drives it with any client.
1462
+ *
1463
+ * @example
1464
+ * ```ts
1465
+ * import { AuthenticatedApp, GitHubApp } from "@effected/github";
1466
+ * import { DateTime, Effect, Layer, Redacted, Stream } from "effect";
1467
+ *
1468
+ * // Redeliver every failed delivery from the last hour.
1469
+ * const sweep = Effect.gen(function* () {
1470
+ * const app = yield* AuthenticatedApp;
1471
+ * const since = DateTime.subtract(yield* DateTime.now, { hours: 1 });
1472
+ * yield* app.deliveries({ status: "failure" }).pipe(
1473
+ * Stream.takeWhile((delivery) => DateTime.isGreaterThan(DateTime.makeUnsafe(delivery.deliveredAt), since)),
1474
+ * Stream.runForEach((delivery) => app.redeliver(delivery.id)),
1475
+ * );
1476
+ * });
1477
+ *
1478
+ * const layer = AuthenticatedApp.layer.pipe(
1479
+ * Layer.provide(
1480
+ * GitHubApp.appClientLayer({
1481
+ * appId: "12345",
1482
+ * privateKey: Redacted.make("-----BEGIN RSA PRIVATE KEY-----\n..."),
1483
+ * }),
1484
+ * ),
1485
+ * );
1486
+ *
1487
+ * Effect.runPromise(Effect.provide(sweep, layer));
1488
+ * ```
1489
+ *
1490
+ * @public
1491
+ */
1492
+ export declare class AuthenticatedApp extends AuthenticatedApp_base {
1493
+ /** The live service, built over an App-JWT `GitHubClient`. */
1494
+ static readonly layer: Layer.Layer<AuthenticatedApp, never, GitHubClient>;
1495
+ /** An in-memory double; unstubbed members die naming themselves. */
1496
+ static readonly makeTest: (overrides?: Partial<AuthenticatedAppShape>) => AuthenticatedAppShape;
1497
+ /** {@link AuthenticatedApp.makeTest} behind a `Layer`. */
1498
+ static readonly layerTest: (overrides?: Partial<AuthenticatedAppShape>) => Layer.Layer<AuthenticatedApp>;
1499
+ }
1500
+ //#endregion
1306
1501
  //#region src/CheckRun.d.ts
1307
1502
  /** How a check run finished. @public */
1308
1503
  export declare const CheckConclusion: Schema.Literals<readonly ["success", "failure", "neutral", "cancelled", "timed_out", "action_required", "skipped"]>;
1504
+ /**
1505
+ * The phase of its lifecycle a check run is in, as GitHub reports it.
1506
+ *
1507
+ * @remarks
1508
+ * `"waiting"`, `"requested"` and `"pending"` are reserved for GitHub Actions
1509
+ * runs; an integrator can only write `"queued"`, `"in_progress"` and, through
1510
+ * {@link CheckRunShape.complete}, `"completed"`.
1511
+ *
1512
+ * @public
1513
+ */
1514
+ export declare const CheckRunStatus: Schema.Literals<readonly ["queued", "in_progress", "completed", "waiting", "requested", "pending"]>;
1515
+ /**
1516
+ * How a check run finished, as GitHub reports it: every
1517
+ * {@link CheckConclusion} plus `"stale"`.
1518
+ *
1519
+ * @remarks
1520
+ * GitHub's check-run response schema omits `"stale"`, but its update
1521
+ * endpoint documents it: *"You cannot change a check run conclusion to
1522
+ * `stale`, only GitHub can set this."* GitHub sets it on a run left
1523
+ * incomplete too long, so a read that refused it would fail on any commit
1524
+ * carrying one. It is read-only, which is why {@link CheckConclusion}, the
1525
+ * write set, does not include it.
1526
+ *
1527
+ * @public
1528
+ */
1529
+ export declare const ReportedCheckConclusion: Schema.Literals<readonly ["success", "failure", "neutral", "cancelled", "timed_out", "action_required", "skipped", "stale"]>;
1309
1530
  /** How serious an annotation is. @public */
1310
1531
  export declare const AnnotationLevel: Schema.Literals<readonly ["notice", "warning", "failure"]>;
1311
1532
  declare const Annotation_base: Schema.Class<Annotation, Schema.Struct<{
@@ -1363,22 +1584,77 @@ export declare class CheckRunOutput extends CheckRunOutput_base {
1363
1584
  */
1364
1585
  truncated(): CheckRunOutput;
1365
1586
  }
1587
+ declare const ReportedCheckRunOutput_base: Schema.Class<ReportedCheckRunOutput, Schema.Struct<{
1588
+ /** The output's title; `null` when the run has none. */
1589
+ readonly title: Schema.NullOr<Schema.String>;
1590
+ /** The output's markdown summary; `null` when the run has none. */
1591
+ readonly summary: Schema.NullOr<Schema.String>;
1592
+ /** How many annotations the run carries (wire `annotations_count`). */
1593
+ readonly annotationsCount: Schema.Int;
1594
+ }>, {}>;
1595
+ /**
1596
+ * The rendered output a check run reports: its title and summary, and how
1597
+ * many annotations it carries.
1598
+ *
1599
+ * @remarks
1600
+ * The read-side counterpart of {@link CheckRunOutput}. It leaves out the
1601
+ * long-form `text` deliberately: it can run to 65535 bytes, and a caller
1602
+ * listing a commit's runs rarely wants it. Read the run's full output through
1603
+ * the typed request surface when you do.
1604
+ *
1605
+ * @public
1606
+ */
1607
+ export declare class ReportedCheckRunOutput extends ReportedCheckRunOutput_base {}
1366
1608
  declare const CheckRunRef_base: Schema.Class<CheckRunRef, Schema.Struct<{
1367
1609
  readonly id: Schema.Int;
1368
1610
  readonly name: Schema.String;
1369
- /** The web URL. */
1611
+ /** The web URL (wire `html_url`), or `""` when GitHub reported none. See also `htmlUrl`. */
1370
1612
  readonly url: Schema.String;
1371
- readonly status: Schema.String;
1613
+ /** The run's lifecycle phase. */
1614
+ readonly status: Schema.Literals<readonly ["queued", "in_progress", "completed", "waiting", "requested", "pending"]>;
1372
1615
  /**
1373
1616
  * The integrator's own id for the run (wire `external_id`), when it has
1374
1617
  * one. GitHub reports a run created without one as `null` or `""`; both
1375
1618
  * leave this absent.
1376
1619
  */
1377
1620
  readonly externalId: Schema.optionalKey<Schema.String>;
1621
+ /** The commit the run checks (wire `head_sha`). */
1622
+ readonly headSha: Schema.optionalKey<Schema.String>;
1623
+ /** The run's GraphQL node id (wire `node_id`). */
1624
+ readonly nodeId: Schema.optionalKey<Schema.String>;
1625
+ /** How the run finished; `null` until it completes. */
1626
+ readonly conclusion: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["success", "failure", "neutral", "cancelled", "timed_out", "action_required", "skipped", "stale"]>>>;
1627
+ /** When the run started, as GitHub's ISO 8601 string; `null` for a run that has not. */
1628
+ readonly startedAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
1629
+ /** When the run completed, as GitHub's ISO 8601 string; `null` for a run that has not. */
1630
+ readonly completedAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
1631
+ /** The integrator's link for the run (wire `details_url`). */
1632
+ readonly detailsUrl: Schema.optionalKey<Schema.NullOr<Schema.String>>;
1633
+ /** The web URL (wire `html_url`), `null` preserved. */
1634
+ readonly htmlUrl: Schema.optionalKey<Schema.NullOr<Schema.String>>;
1635
+ /** The run's REST API URL (wire `url`). */
1636
+ readonly apiUrl: Schema.optionalKey<Schema.String>;
1637
+ /** The check suite the run belongs to (wire `check_suite.id`); `null` when GitHub reported none. */
1638
+ readonly checkSuiteId: Schema.optionalKey<Schema.NullOr<Schema.Int>>;
1639
+ /** The run's title, summary and annotation count. */
1640
+ readonly output: Schema.optionalKey<typeof ReportedCheckRunOutput>;
1378
1641
  }>, {}>;
1379
1642
  /**
1380
1643
  * A check run as GitHub reports it.
1381
1644
  *
1645
+ * @remarks
1646
+ * Every field beyond the original five (the four required ones and
1647
+ * `externalId`) is optional, so a test double built with
1648
+ * `CheckRunRef.make({ id, name, url, status })` stays valid; a run decoded
1649
+ * from a GitHub response carries all of them, because GitHub always sends
1650
+ * them. A nullable field is `null` when GitHub reported `null`.
1651
+ *
1652
+ * **Three URLs, named apart.** `url` is the **web** URL (wire `html_url`, or
1653
+ * `""` when GitHub reported none), kept under that name so existing callers
1654
+ * read what they always read. `htmlUrl` is the same wire field with its
1655
+ * `null` preserved, `apiUrl` is the REST URL (wire `url`), and `detailsUrl`
1656
+ * is the integrator's own link (wire `details_url`).
1657
+ *
1382
1658
  * @public
1383
1659
  */
1384
1660
  export declare class CheckRunRef extends CheckRunRef_base {}
@@ -1419,6 +1695,29 @@ interface UpdateCheckRunOptions {
1419
1695
  /** Where the integrator's full details live (wire `details_url`). */
1420
1696
  readonly detailsUrl?: string | undefined;
1421
1697
  }
1698
+ /**
1699
+ * Options for {@link CheckRunShape.list}.
1700
+ *
1701
+ * @public
1702
+ */
1703
+ interface ListCheckRunsOptions {
1704
+ /** Only runs with this name (wire `check_name`). */
1705
+ readonly checkName?: string | undefined;
1706
+ /** Only runs created by this GitHub App (wire `app_id`). */
1707
+ readonly appId?: number | undefined;
1708
+ /**
1709
+ * Only runs in this phase. GitHub filters on these three only; the
1710
+ * Actions-reserved phases are not a filter it accepts.
1711
+ */
1712
+ readonly status?: "queued" | "in_progress" | "completed" | undefined;
1713
+ /**
1714
+ * `"latest"` (GitHub's default) answers only the newest run per name;
1715
+ * `"all"` answers every run, re-runs included.
1716
+ */
1717
+ readonly filter?: "latest" | "all" | undefined;
1718
+ /** How far to page. Unset, every page is read, 100 runs at a time. */
1719
+ readonly page?: PageOptions | undefined;
1720
+ }
1422
1721
  /**
1423
1722
  * Options for {@link CheckRunShape.complete}.
1424
1723
  *
@@ -1480,6 +1779,28 @@ interface CheckRunShape {
1480
1779
  * handling sees a missing run or a revoked token the same way either way.
1481
1780
  */
1482
1781
  readonly update: (id: number, output?: CheckRunOutput, options?: UpdateCheckRunOptions) => Effect.Effect<void, GitHubError, Repo>;
1782
+ /**
1783
+ * {@link CheckRunShape.update}, answering the run as GitHub reports it
1784
+ * after the PATCH.
1785
+ *
1786
+ * @remarks
1787
+ * The same single request, with the same omission rules; the difference is
1788
+ * only that GitHub's response is decoded into a {@link CheckRunRef} rather
1789
+ * than discarded. A separate member rather than a new return type on
1790
+ * `update`, so a test double that stubs `update` with `Effect.void` keeps
1791
+ * compiling.
1792
+ */
1793
+ readonly updateRef: (id: number, output?: CheckRunOutput, options?: UpdateCheckRunOptions) => Effect.Effect<CheckRunRef, GitHubError, Repo>;
1794
+ /**
1795
+ * The check runs on a commit, newest per name unless `options.filter` is
1796
+ * `"all"`.
1797
+ *
1798
+ * @remarks
1799
+ * `ref` is a commit SHA, a branch name or a tag name. Every page is read
1800
+ * unless `options.page` bounds the walk, so a filter that matches past
1801
+ * page one is still answered in full.
1802
+ */
1803
+ readonly list: (ref: string, options?: ListCheckRunsOptions) => Effect.Effect<ReadonlyArray<CheckRunRef>, GitHubError, Repo>;
1483
1804
  /**
1484
1805
  * The newest run on `headSha` named `name` whose external id is
1485
1806
  * `externalId`; none when there is no such run.
@@ -1504,6 +1825,17 @@ interface CheckRunShape {
1504
1825
  * workflow run that produced it.
1505
1826
  */
1506
1827
  readonly complete: (id: number, conclusion: (typeof CheckConclusion.literals)[number], output?: CheckRunOutput, options?: CompleteCheckRunOptions) => Effect.Effect<void, GitHubError, Repo>;
1828
+ /**
1829
+ * {@link CheckRunShape.complete}, answering the finished run as GitHub
1830
+ * reports it after the PATCH.
1831
+ *
1832
+ * @remarks
1833
+ * The same single request, with the same `completed_at` stamp and output
1834
+ * byte cap; GitHub's response is decoded into a {@link CheckRunRef} rather
1835
+ * than discarded. A separate member for the same reason as
1836
+ * {@link CheckRunShape.updateRef}.
1837
+ */
1838
+ readonly completeRef: (id: number, conclusion: (typeof CheckConclusion.literals)[number], output?: CheckRunOutput, options?: CompleteCheckRunOptions) => Effect.Effect<CheckRunRef, GitHubError, Repo>;
1507
1839
  /**
1508
1840
  * Run `use` inside a check run, concluding it however `use` exits.
1509
1841
  *
@@ -2142,8 +2474,17 @@ interface CachedTokenRequest extends TokenRequest {
2142
2474
  interface CachedToken {
2143
2475
  /** The token. */
2144
2476
  readonly token: InstallationToken;
2145
- /** `"cached"` when it was read from the store, `"minted"` when GitHub issued it just now. */
2146
- readonly source: "cached" | "minted";
2477
+ /**
2478
+ * `"cached"` when it was read from the store, `"minted"` when GitHub
2479
+ * issued it to this call just now, `"joined"` when this call missed the
2480
+ * store but another call in the same process was already minting for the
2481
+ * installation and this one took that token instead of minting its own.
2482
+ *
2483
+ * @remarks
2484
+ * A `"joined"` token is as fresh as a `"minted"` one; the label exists so
2485
+ * a caller counting mints against GitHub can tell the two apart.
2486
+ */
2487
+ readonly source: "cached" | "minted" | "joined";
2147
2488
  }
2148
2489
  declare const InstallationToken_base: Schema.Class<InstallationToken, Schema.Struct<{
2149
2490
  /** The token. Decodes to `Redacted`, encodes back to the raw string. */
@@ -2243,6 +2584,37 @@ export declare class AppIdentity extends AppIdentity_base {
2243
2584
  /** The committer identity for this app. */
2244
2585
  botIdentity(): BotIdentity;
2245
2586
  }
2587
+ declare const BotUser_base: Schema.Class<BotUser, Schema.Struct<{
2588
+ /** The bot user's numeric id. */
2589
+ readonly id: Schema.Int;
2590
+ /** The bot user's login, `<slug>[bot]`. */
2591
+ readonly login: Schema.String;
2592
+ }>, {}>;
2593
+ /**
2594
+ * An app's bot user: the account its installation tokens act as.
2595
+ *
2596
+ * @remarks
2597
+ * `id` is what to compare against an actor id on an event, such as
2598
+ * `workflow_run.triggering_actor.id`: a login can be renamed, an id cannot.
2599
+ *
2600
+ * @public
2601
+ */
2602
+ export declare class BotUser extends BotUser_base {}
2603
+ /**
2604
+ * What {@link GitHubAppShape.botUser} looks up.
2605
+ *
2606
+ * @public
2607
+ */
2608
+ interface BotUserRequest {
2609
+ /** The app's slug; the bot user is `<slug>[bot]`. */
2610
+ readonly slug: string;
2611
+ /**
2612
+ * An installation token to authenticate the lookup with. Without one the
2613
+ * lookup runs unauthenticated, at GitHub's 60-requests-per-hour-per-IP
2614
+ * limit: `GET /users/{username}` rejects an App JWT.
2615
+ */
2616
+ readonly installationToken?: Redacted.Redacted<string> | undefined;
2617
+ }
2246
2618
  declare const Installation_base: Schema.Class<Installation, Schema.Struct<{
2247
2619
  /** The installation id, which is what a token is minted against. */
2248
2620
  readonly id: Schema.Int;
@@ -2440,9 +2812,18 @@ export declare class GitHubApp extends GitHubApp_base {
2440
2812
  * **A cached token is never revoked**: another scope or isolate may be using
2441
2813
  * it. It expires on its own, within the hour.
2442
2814
  *
2443
- * Two concurrent calls that both miss will both mint, and the later write
2444
- * wins. That is expected: the store may span isolates, so the kit cannot
2445
- * lock it, and an extra token costs one call and expires on its own.
2815
+ * Within one process, concurrent misses for one installation are
2816
+ * **single-flight**: the first caller mints and the others wait for that
2817
+ * mint and return the same token with `source: "joined"`, so a batch that
2818
+ * fans out over one installation on a cold store costs one mint, not one
2819
+ * per fiber. The in-flight record lives with the `GitHubApp` service and is
2820
+ * released when the mint settles, however it settles: a failed mint fails
2821
+ * every waiter with the same `GitHubAppError`, and the next call mints
2822
+ * again. Interrupting the leader does not strand the waiters: the mint runs
2823
+ * in its own fiber and completes for them. Across isolates, two misses
2824
+ * still both mint and the later write wins. That is expected: the store may
2825
+ * span isolates, so the kit cannot lock it, and an extra token costs one
2826
+ * call and expires on its own.
2446
2827
  *
2447
2828
  * The encoded value written to the store contains the raw token, so
2448
2829
  * encrypting it at rest is the store's job.
@@ -2536,8 +2917,32 @@ interface GitHubAppShape {
2536
2917
  readonly identity: (request: AppCredentials & {
2537
2918
  readonly installationToken?: Redacted.Redacted<string> | undefined;
2538
2919
  }) => Effect.Effect<AppIdentity, GitHubAppError>;
2920
+ /**
2921
+ * The app's bot user, `GET /users/{slug}[bot]`.
2922
+ *
2923
+ * @remarks
2924
+ * Unlike {@link GitHubAppShape.identity}, which treats the bot user as
2925
+ * optional enrichment and omits it when the lookup fails, this fails with
2926
+ * `kind: "identity"` — for a caller that authorizes on the bot's id, a
2927
+ * missing id is an error, not a degraded answer. Get the slug from
2928
+ * `identity` or from `AuthenticatedApp.get`.
2929
+ */
2930
+ readonly botUser: (request: BotUserRequest) => Effect.Effect<BotUser, GitHubAppError>;
2539
2931
  /** Every installation of the app. */
2540
2932
  readonly installations: (credentials: AppCredentials) => Effect.Effect<ReadonlyArray<Installation>, GitHubAppError>;
2933
+ /**
2934
+ * An installation token, reused from the {@link InstallationTokenStore}
2935
+ * while it has `margin` left to live; {@link GitHubApp.cachedToken} is this
2936
+ * member on the provided service.
2937
+ *
2938
+ * @remarks
2939
+ * A member rather than a free function because the in-process
2940
+ * single-flight record for concurrent misses lives with the service: it is
2941
+ * created with the layer and shared by every call through it.
2942
+ * {@link GitHubApp.makeTest} builds it over the double's `token`, so a test
2943
+ * that stubs `token` gets the real caching and single-flight behaviour.
2944
+ */
2945
+ readonly cachedToken: (request: CachedTokenRequest) => Effect.Effect<CachedToken, GitHubAppError, InstallationTokenStore>;
2541
2946
  }
2542
2947
  //#endregion
2543
2948
  //#region src/GitHubCommit.d.ts
@@ -4426,5 +4831,5 @@ export declare class WorkflowDispatch extends WorkflowDispatch_base {
4426
4831
  static readonly layerTest: (overrides?: Partial<WorkflowDispatchShape>) => Layer.Layer<WorkflowDispatch>;
4427
4832
  }
4428
4833
  //#endregion
4429
- export { type ActionsOidcVerifyOptions, type AppCredentials, type AppliedSettings, type ArtifactMetadataShape, type AttestationShape, type BareLineReference, type BranchOutcome, CLOSING_KEYWORDS, type CachedToken, type CachedTokenRequest, type CheckRunShape, type ClosingKeyword, type CodeScanningSetup, type CodeScanningShape, type CompleteCheckRunOptions, type ConcludeCheckRun, type CreateCheckRunOptions, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, type GitBranchShape, type GitCommitShape, type GitHubAppOptions, type GitHubAppShape, type GitHubClientOptions, type GitHubClientShape, type GitHubCommitShape, type GitHubContentShape, type GitHubIssueShape, type GitHubReleaseShape, type GitHubRepositoryShape, type GitTagShape, type InstallationTokenStoreShape, type IssueReference, type LatestSemverOptions, type OwnerType, type PollOptions, type PullRequestCommentShape, type PullRequestShape, type RecordedCall, type RepositoryPatch, type RepositoryPatchDraft, type RepositorySecretShape, type RepositorySecurityShape, type RepositorySettings, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, type RetryableFailure, type RulesetInfo, type RulesetPayload, type RulesetShape, type SecretInfo, type SecretScope, type TokenRequest, type UpdateCheckRunOptions, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, type WorkflowDispatchShape, type WorkflowInfo, harvestIssueReferences, parseBareLineReference };
4834
+ export { type ActionsOidcVerifyOptions, type AppCredentials, type AppliedSettings, type ArtifactMetadataShape, type AttestationShape, type AuthenticatedAppShape, type BareLineReference, type BotUserRequest, type BranchOutcome, CLOSING_KEYWORDS, type CachedToken, type CachedTokenRequest, type CheckRunShape, type ClosingKeyword, type CodeScanningSetup, type CodeScanningShape, type CompleteCheckRunOptions, type ConcludeCheckRun, type CreateCheckRunOptions, type DeliveriesOptions, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, type GitBranchShape, type GitCommitShape, type GitHubAppOptions, type GitHubAppShape, type GitHubClientOptions, type GitHubClientShape, type GitHubCommitShape, type GitHubContentShape, type GitHubIssueShape, type GitHubReleaseShape, type GitHubRepositoryShape, type GitTagShape, type InstallationTokenStoreShape, type IssueReference, type LatestSemverOptions, type ListCheckRunsOptions, type OwnerType, type PollOptions, type PullRequestCommentShape, type PullRequestShape, type RecordedCall, type RepositoryPatch, type RepositoryPatchDraft, type RepositorySecretShape, type RepositorySecurityShape, type RepositorySettings, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, type RetryableFailure, type RulesetInfo, type RulesetPayload, type RulesetShape, type SecretInfo, type SecretScope, type TokenRequest, type UpdateCheckRunOptions, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, type WorkflowDispatchShape, type WorkflowInfo, harvestIssueReferences, parseBareLineReference };
4430
4835
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -6,13 +6,14 @@ import { GitHubClient, GitHubFixtures, RawFailure } from "./GitHubClient.js";
6
6
  import { InvalidRepoRefError, Repo, RepoRef } from "./Repo.js";
7
7
  import { ArtifactMetadata, StorageRecordInput } from "./ArtifactMetadata.js";
8
8
  import { Attestation, AttestationListEntry, AttestationRecord } from "./Attestation.js";
9
- import { Annotation, AnnotationLevel, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef } from "./CheckRun.js";
9
+ import { AppInfo, AuthenticatedApp, DeliveryAttempt } from "./AuthenticatedApp.js";
10
+ import { Annotation, AnnotationLevel, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CheckRunStatus, ReportedCheckConclusion, ReportedCheckRunOutput } from "./CheckRun.js";
10
11
  import { CodeScanning } from "./CodeScanning.js";
11
12
  import { DeploymentEnvironment } from "./DeploymentEnvironment.js";
12
13
  import { GitBranch } from "./GitBranch.js";
13
14
  import { CommitRef, FileChange, FileContent, FileDeletion, FileMode, GitCommit } from "./GitCommit.js";
14
15
  import { InstallationTokenStore } from "./InstallationTokenStore.js";
15
- import { AppIdentity, BotIdentity, GitHubApp, GitHubAppError, Installation, InstallationToken } from "./GitHubApp.js";
16
+ import { AppIdentity, BotIdentity, BotUser, GitHubApp, GitHubAppError, Installation, InstallationToken } from "./GitHubApp.js";
16
17
  import { CommitComparison, CommitFile, CommitSummary, FileStatus, GitHubCommit } from "./GitHubCommit.js";
17
18
  import { GitHubContent } from "./GitHubContent.js";
18
19
  import { CommentMarker, CommentRecord, PullRequestComment } from "./PullRequestComment.js";
@@ -30,4 +31,4 @@ import { ExtraPermission, PermissionGap, PermissionLevel, PermissionResult, Toke
30
31
  import { DispatchedRun, WorkflowDispatch, WorkflowRunStatus } from "./WorkflowDispatch.js";
31
32
  import { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference } from "@effected/github-references";
32
33
 
33
- export { ActionsOidc, ActionsOidcClaims, Annotation, AnnotationLevel, AppIdentity, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, BotIdentity, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeploymentEnvironment, DispatchedRun, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubFixtures, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitHubValidationCode, GitHubValidationEntry, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InstallationTokenStore, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, RawFailure, ReleaseAsset, ReleaseInfo, Repo, RepoRef, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
34
+ export { ActionsOidc, ActionsOidcClaims, Annotation, AnnotationLevel, AppIdentity, AppInfo, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, AuthenticatedApp, BotIdentity, BotUser, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CheckRunStatus, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeliveryAttempt, DeploymentEnvironment, DispatchedRun, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubFixtures, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitHubValidationCode, GitHubValidationEntry, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InstallationTokenStore, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, RawFailure, ReleaseAsset, ReleaseInfo, Repo, RepoRef, ReportedCheckConclusion, ReportedCheckRunOutput, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/github",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "private": false,
5
5
  "description": "Typed GitHub REST and GraphQL services over the octokit core request surface, with app auth and resource helpers.",
6
6
  "keywords": [
@@ -38,9 +38,9 @@
38
38
  "./package.json": "./package.json"
39
39
  },
40
40
  "dependencies": {
41
- "@effected/github-references": "^0.7.0",
42
- "@effected/jwt": "^0.1.0",
43
- "@effected/semver": "^0.11.0",
41
+ "@effected/github-references": "^0.8.0",
42
+ "@effected/jwt": "^0.2.0",
43
+ "@effected/semver": "^0.12.0",
44
44
  "@octokit/core": "^7.0.6",
45
45
  "@octokit/plugin-paginate-rest": "^16.0.0",
46
46
  "@octokit/types": "^18.0.0",