@effected/github 0.1.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.
package/index.d.ts ADDED
@@ -0,0 +1,2427 @@
1
+ import { Config, Context, Duration, Effect, Layer, Option, Redacted, Result, Schedule, Schema, SchemaError, Scope, Stream } from "effect";
2
+ import { PaginatingEndpoints } from "@octokit/plugin-paginate-rest";
3
+ import { Endpoints, RequestHeaders } from "@octokit/types";
4
+ import { SemVer } from "@effected/semver";
5
+ //#region src/GitHubError.d.ts
6
+ /**
7
+ * Why a GitHub call failed, as a value you can branch on.
8
+ *
9
+ * @remarks
10
+ * This discriminant is what replaces string-matching an error message. The
11
+ * package this replaces carried a free-form `reason` string and nothing else
12
+ * structural, so consumers grepped it: one repo lowercased a GraphQL message and
13
+ * tested `includes("already") || includes("exists")`, and another re-issued an
14
+ * existence check after every failed branch creation because it could not tell
15
+ * "someone else created it" from "that failed".
16
+ *
17
+ * @public
18
+ */
19
+ declare const GitHubErrorKind: Schema.Literals<readonly ["notFound", "alreadyExists", "rejected", "unauthorized", "rateLimited", "transport", "decode"]>;
20
+ declare const GitHubError_base: Schema.Class<GitHubError, Schema.TaggedStruct<"GitHubError", {
21
+ /** Structural routing. Branch on this, never on the rendered message. */
22
+ readonly kind: Schema.Literals<readonly ["notFound", "alreadyExists", "rejected", "unauthorized", "rateLimited", "transport", "decode"]>;
23
+ /** What was attempted: a resource method (`"GitBranch.upsert"`) or a raw route. */
24
+ readonly operation: Schema.String;
25
+ /** Human-readable cause, for logs and messages. Never a routing surface. */
26
+ readonly reason: Schema.String;
27
+ /** GitHub's HTTP status, when the request reached GitHub at all. */
28
+ readonly status: Schema.optionalKey<Schema.Int>;
29
+ /**
30
+ * A server-advised delay before retrying, in milliseconds.
31
+ *
32
+ * @remarks
33
+ * Written by the client from `retry-after` or the rate-limit reset, and read
34
+ * by exactly one thing: the retry `Schedule`. It is a policy input, not
35
+ * information for a caller — which is why it is optional and why the
36
+ * `retryable` boolean it used to travel with is now a derived getter.
37
+ */
38
+ readonly retryAfterMillis: Schema.optionalKey<Schema.Int>;
39
+ /** The underlying throwable, when one exists. */
40
+ readonly cause: Schema.optionalKey<Schema.Defect>;
41
+ }>, import("effect/Cause").YieldableError>;
42
+ /**
43
+ * Every REST failure this package produces, from every resource.
44
+ *
45
+ * @remarks
46
+ * One error class, not one per resource. Across the six repos surveyed for this
47
+ * port, consumers read `reason` about forty times, `status` twice, `operation`
48
+ * twice, and matched a resource-specific `_tag` exactly **once** — at a call
49
+ * site that disappears entirely now that `GitBranch.upsert` exists. Eighteen
50
+ * near-identical error classes and thirteen near-identical mapper closures
51
+ * bought that one match.
52
+ *
53
+ * What replaces them is {@link GitHubErrorKind} for routing and `operation` for
54
+ * identification. This mirrors `@effected/git`, where the rule is that no
55
+ * consumer ever string-matches stderr because classification happens once.
56
+ *
57
+ * @public
58
+ */
59
+ declare class GitHubError extends GitHubError_base {
60
+ /** `"GitBranch.upsert failed (422): Reference already exists"`. */
61
+ get message(): string;
62
+ /**
63
+ * Whether retrying could plausibly succeed.
64
+ *
65
+ * @remarks
66
+ * Derived from `kind` rather than stored. A 404 or a
67
+ * validation rejection will fail identically on every attempt; only a
68
+ * transport failure or a rate limit can change its mind.
69
+ */
70
+ get retryable(): boolean;
71
+ /** The requested thing is not there. */
72
+ static notFound(operation: string, subject: string): GitHubError;
73
+ /** The thing you asked to create is already there. */
74
+ static alreadyExists(operation: string, subject: string): GitHubError;
75
+ /** GitHub understood the request and refused it. */
76
+ static rejected(operation: string, status: number, reason: string): GitHubError;
77
+ /** A response did not match the schema it was decoded against. */
78
+ static decode(operation: string, reason: string, cause?: unknown): GitHubError;
79
+ /**
80
+ * Classify anything octokit threw.
81
+ *
82
+ * @remarks
83
+ * The single classification step for the whole package — every resource
84
+ * method's failures come through here, so the taxonomy cannot drift between
85
+ * resources the way thirteen hand-written mapper closures did.
86
+ *
87
+ * `nowMillis` is passed in rather than read from the wall clock so the
88
+ * function stays pure and total: the rate-limit reset header is an absolute
89
+ * epoch second, and turning it into a delay needs a "now" the caller controls.
90
+ * The client supplies `Clock.currentTimeMillis`, which is the `TestClock`
91
+ * under test.
92
+ */
93
+ static fromOctokit(operation: string, error: unknown, nowMillis: number): GitHubError;
94
+ /**
95
+ * A predicate over one or more kinds, for `Effect.catchIf`.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { GitHubError } from "@effected/github";
100
+ * import { Effect } from "effect";
101
+ *
102
+ * declare const read: Effect.Effect<string, GitHubError>;
103
+ *
104
+ * const orDefault = read.pipe(
105
+ * Effect.catchIf(GitHubError.hasKind("notFound"), () => Effect.succeed("")),
106
+ * );
107
+ * ```
108
+ */
109
+ static hasKind(...kinds: ReadonlyArray<(typeof GitHubErrorKind.literals)[number]>): (error: GitHubError) => boolean;
110
+ }
111
+ //#endregion
112
+ //#region src/GraphQL.d.ts
113
+ declare const GraphQLErrorEntry_base: Schema.Class<GraphQLErrorEntry, Schema.Struct<{
114
+ /** GitHub's prose. */
115
+ readonly message: Schema.String;
116
+ /** GitHub's own classification, e.g. `"NOT_FOUND"` or `"FORBIDDEN"`. */
117
+ readonly type: Schema.optionalKey<Schema.String>;
118
+ }>, {}>;
119
+ /**
120
+ * One entry from a GraphQL response's `errors` array.
121
+ *
122
+ * @public
123
+ */
124
+ declare class GraphQLErrorEntry extends GraphQLErrorEntry_base {}
125
+ declare const GitHubGraphQLError_base: Schema.Class<GitHubGraphQLError, Schema.TaggedStruct<"GitHubGraphQLError", {
126
+ /**
127
+ * Structural routing, mirroring `GitHubError`'s.
128
+ *
129
+ * @remarks
130
+ * `"alreadyExists"` exists here for the same reason it exists on the REST
131
+ * error: without it a consumer lowercases the message and greps it for
132
+ * `"already"` and `"exists"`, which is exactly what one surveyed repo did to
133
+ * make project creation idempotent.
134
+ */
135
+ readonly kind: Schema.Literals<readonly ["alreadyExists", "notFound", "rejected", "unauthorized", "rateLimited", "transport", "decode"]>;
136
+ /** The document's name, e.g. `"linkedIssues"` — never the literal `"graphql"`. */
137
+ readonly operation: Schema.String;
138
+ /** Human-readable cause, for logs. */
139
+ readonly reason: Schema.String;
140
+ /** Everything GitHub reported, in order. */
141
+ readonly errors: Schema.$Array<typeof GraphQLErrorEntry>;
142
+ /** A server-advised delay in milliseconds, read only by the retry schedule. */
143
+ readonly retryAfterMillis: Schema.optionalKey<Schema.Int>;
144
+ /** The underlying throwable, when one exists. */
145
+ readonly cause: Schema.optionalKey<Schema.Defect>;
146
+ }>, import("effect/Cause").YieldableError>;
147
+ /**
148
+ * A GraphQL call failed.
149
+ *
150
+ * @remarks
151
+ * Separate from `GitHubError` because GraphQL genuinely answers differently:
152
+ * a 200 response can still carry failures, and it carries a **list** of them.
153
+ * `errors` is the one structured field a surveyed consumer actually read.
154
+ *
155
+ * @public
156
+ */
157
+ declare class GitHubGraphQLError extends GitHubGraphQLError_base {
158
+ get message(): string;
159
+ /** Whether retrying could plausibly succeed. Derived, like the REST error's. */
160
+ get retryable(): boolean;
161
+ /** A response arrived but did not match the document's declared schema. */
162
+ static decode(operation: string, reason: string, cause?: unknown): GitHubGraphQLError;
163
+ /**
164
+ * Classify anything the GraphQL transport threw.
165
+ *
166
+ * @remarks
167
+ * octokit surfaces two different failures here: a `GraphqlResponseError`,
168
+ * which is an HTTP 200 whose body carries `errors`, and an ordinary HTTP
169
+ * failure with a `status`. Both arrive as throwables and both are read
170
+ * structurally, for the same reason the REST classifier does it — the error
171
+ * classes live in packages this one does not declare.
172
+ */
173
+ static fromThrowable(operation: string, error: unknown, nowMillis: number): GitHubGraphQLError;
174
+ }
175
+ /**
176
+ * A named GraphQL document, its variables, and how to read its answer.
177
+ *
178
+ * @remarks
179
+ * This is the mechanism that makes `client.graphql` return a **domain value**
180
+ * rather than an `unknown` the caller casts. The package this replaces took a
181
+ * query string and a caller-chosen type parameter with nothing connecting them,
182
+ * so every consumer wrote its own response interface and hoped.
183
+ *
184
+ * The kit owns the documents its resources need; a consumer with a domain of
185
+ * its own — silk-sync-action's ProjectV2 work, for instance — builds its own
186
+ * `GraphQLDocument` and gets the same typing and the same error taxonomy
187
+ * without this package having to know about its schema.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * import { GraphQLDocument } from "@effected/github";
192
+ * import { Schema } from "effect";
193
+ *
194
+ * const ViewerLogin = GraphQLDocument.make({
195
+ * name: "viewerLogin",
196
+ * document: `query { viewer { login } }`,
197
+ * response: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) }),
198
+ * })<{ readonly login: string }>();
199
+ * ```
200
+ *
201
+ * @public
202
+ */
203
+ declare class GraphQLDocument<A, V extends Record<string, unknown>> {
204
+ /** Names the span and the error's `operation`. */
205
+ readonly name: string;
206
+ /** The document text sent to GitHub. */
207
+ readonly document: string;
208
+ /** Decodes the raw `data` payload into the domain value. */
209
+ readonly decode: (raw: unknown) => Effect.Effect<A, SchemaError.SchemaError>;
210
+ /**
211
+ * Turns the caller's variables into the wire object.
212
+ *
213
+ * @remarks
214
+ * Identity by default. It exists so `V` is genuinely load-bearing: without
215
+ * a member mentioning it, TypeScript's structural typing would make
216
+ * documents with different variable shapes interchangeable and the
217
+ * call-site checking would be decorative.
218
+ */
219
+ readonly encodeVariables: (variables: V) => Record<string, unknown>;
220
+ private constructor();
221
+ /**
222
+ * Build a document from a response schema.
223
+ *
224
+ * @remarks
225
+ * Curried, because `A` is inferred from `response` while `V` is stated:
226
+ * TypeScript takes explicit type arguments all-or-nothing, so a single call
227
+ * would force the caller to spell out the decoded type as well.
228
+ */
229
+ static make<A, I>(options: {
230
+ readonly name: string;
231
+ readonly document: string;
232
+ readonly response: Schema.Codec<A, I>;
233
+ }): <V extends Record<string, unknown>>(encodeVariables?: (variables: V) => Record<string, unknown>) => GraphQLDocument<A, V>;
234
+ }
235
+ //#endregion
236
+ //#region src/Resilience.d.ts
237
+ declare const RateLimitSnapshot_base: Schema.Class<RateLimitSnapshot, Schema.Struct<{
238
+ /** Requests left in the current window. */
239
+ readonly remaining: Schema.Int;
240
+ /** The window's ceiling. */
241
+ readonly limit: Schema.Int;
242
+ /** When the window resets, as epoch **seconds** — GitHub's own unit. */
243
+ readonly resetEpochSeconds: Schema.Int;
244
+ }>, {}>;
245
+ /**
246
+ * What GitHub's rate-limit headers said on the most recent REST response.
247
+ *
248
+ * @remarks
249
+ * Every REST response carries `x-ratelimit-remaining`, `x-ratelimit-limit` and
250
+ * `x-ratelimit-reset`; the client parses them into this and keeps the latest
251
+ * one. Read it through the client's `rateLimit` member when you want to pace
252
+ * yourself — **nothing in this package throttles on your behalf.**
253
+ *
254
+ * The package this replaces coupled the writer and the reader through an
255
+ * optional shared `Ref` service that both resolved with `Effect.serviceOption`,
256
+ * so an application that forgot to provide it got two private cells and a
257
+ * silently dead feature. Here the cell lives inside the client layer that writes
258
+ * it, and this is the only way to read it.
259
+ *
260
+ * @public
261
+ */
262
+ declare class RateLimitSnapshot extends RateLimitSnapshot_base {
263
+ /** Milliseconds until the window resets, relative to `nowMillis`, floored at zero. */
264
+ millisUntilReset(nowMillis: number): number;
265
+ /** True when the budget is spent. */
266
+ get isExhausted(): boolean;
267
+ }
268
+ /**
269
+ * The shape {@link RetryPolicy} needs from a failure to decide anything.
270
+ *
271
+ * @remarks
272
+ * Declared structurally so this module imports no error class. That keeps the
273
+ * policy usable for both the REST and the GraphQL error without either of them
274
+ * importing the other, and it makes every policy decision testable against a
275
+ * two-field literal instead of a constructed error.
276
+ *
277
+ * @public
278
+ */
279
+ interface RetryableFailure {
280
+ /** Whether retrying could plausibly succeed. */
281
+ readonly retryable: boolean;
282
+ /** A server-advised delay in milliseconds, when GitHub sent one. */
283
+ readonly retryAfterMillis?: number | undefined;
284
+ }
285
+ declare const RetryPolicy_base: Schema.Class<RetryPolicy, Schema.Struct<{
286
+ /** Retries after the first attempt. `0` disables retrying. */
287
+ readonly maxRetries: Schema.Int;
288
+ /** The first backoff step; doubles per attempt. */
289
+ readonly baseDelay: Schema.DurationFromMillis;
290
+ /** The computed backoff never exceeds this. */
291
+ readonly maxDelay: Schema.DurationFromMillis;
292
+ /** Prefer GitHub's `retry-after` / rate-limit reset over the computed backoff. */
293
+ readonly respectRetryAfter: Schema.Boolean;
294
+ /**
295
+ * Refuse to wait longer than this for a server-advised delay.
296
+ *
297
+ * @remarks
298
+ * A primary rate-limit window can be three quarters of an hour out. Sleeping
299
+ * through it converts a failure into a hang, so past this ceiling the error
300
+ * is re-failed immediately and the caller decides what to do.
301
+ */
302
+ readonly maxServerAdvisedDelay: Schema.DurationFromMillis;
303
+ }>, {}>;
304
+ /**
305
+ * How the client retries a failed request.
306
+ *
307
+ * @remarks
308
+ * There is exactly **one** retry policy in this package, and it is wired into
309
+ * the client so every resource inherits it and no resource carries its own. The
310
+ * package this replaces shipped four mutually inconsistent policies — a
311
+ * hand-rolled recursive loop, a second exported `Schedule` that ignored
312
+ * server-advised delays, a per-operation branch retry layered on top of the
313
+ * client's, and a rate-limiter retry with no predicate at all, which cheerfully
314
+ * retried permission denials — and consumers added two more on top.
315
+ *
316
+ * Only failures that report `retryable` are retried, which for `GitHubError` means a transport failure or a rate limit. A 404, a
317
+ * validation rejection and an authorization failure fail on the first attempt.
318
+ *
319
+ * @public
320
+ */
321
+ declare class RetryPolicy extends RetryPolicy_base {
322
+ /** Four retries, 1s base, 30s cap, honoring server-advised delays up to a minute. */
323
+ static readonly default: RetryPolicy;
324
+ /** Retries nothing; every failure surfaces on the first attempt. */
325
+ static readonly none: RetryPolicy;
326
+ /**
327
+ * Whether this policy would retry `failure` at all, ignoring attempt counts.
328
+ *
329
+ * @remarks
330
+ * Pure and total, so the classification is testable without a clock, a
331
+ * runtime or a schedule.
332
+ */
333
+ retries(failure: RetryableFailure): boolean;
334
+ /**
335
+ * The delay before the given attempt, for a failure and a `[0, 1)` draw.
336
+ *
337
+ * @remarks
338
+ * A server-advised delay wins outright when `respectRetryAfter`
339
+ * is set: GitHub knows when its window reopens and a computed backoff can only
340
+ * guess. Otherwise this is **full jitter** — a uniform draw from
341
+ * `[0, min(baseDelay * 2^(attempt-1), maxDelay)]` — which spreads a fleet of
342
+ * retrying callers rather than synchronizing them into a second herd.
343
+ *
344
+ * `random` is a parameter so the arithmetic is checkable without stubbing a
345
+ * generator.
346
+ */
347
+ delayFor(failure: RetryableFailure, attempt: number, random: number): Duration.Duration;
348
+ /** The server-advised delay, when there is one and this policy honors it. */
349
+ private advisedMillis;
350
+ /**
351
+ * The `Schedule` this policy compiles to, for `Effect.retry`.
352
+ *
353
+ * @remarks
354
+ * Built on `Schedule.modifyDelay`, whose callback receives the schedule's
355
+ * `Metadata` — including the **input that failed**. That is what makes a
356
+ * header-driven policy expressible as a `Schedule` at all: the delay is a
357
+ * function of the error, not only of the attempt number. Not knowing this was
358
+ * available is why the package this replaces hand-rolled a recursive retry
359
+ * loop instead of using `Effect.retry`.
360
+ */
361
+ schedule<E extends RetryableFailure>(): Schedule.Schedule<number, E>;
362
+ }
363
+ //#endregion
364
+ //#region src/Rest.d.ts
365
+ /**
366
+ * Every REST route GitHub documents, as a `"<METHOD> <path>"` literal — for
367
+ * example `"GET /repos/{owner}/{repo}"`.
368
+ *
369
+ * @remarks
370
+ * This is the key the whole typed surface turns on. `@octokit/types` generates
371
+ * the `Endpoints` map from GitHub's own OpenAPI description, so a route literal
372
+ * carries both its parameter shape and its response shape with it, and neither
373
+ * a caller nor an implementation ever has to name a payload type by hand.
374
+ *
375
+ * The generated map is **types only** — `@octokit/types` ships no JavaScript at
376
+ * all — so leaning on it costs zero runtime bytes.
377
+ *
378
+ * @public
379
+ */
380
+ type Route = keyof Endpoints;
381
+ /**
382
+ * Transport knobs octokit accepts on any route, narrowed to the three this
383
+ * package allows.
384
+ *
385
+ * @remarks
386
+ * octokit's own `RequestParameters` carries an `[parameter: string]: unknown`
387
+ * index signature, so intersecting it would silently accept every misspelled
388
+ * parameter. These three are the ones the surveyed call sites genuinely need:
389
+ * `headers` for a release asset's `content-type` and the attestations API
390
+ * version pin, `mediaType.format` for raw content reads, and `baseUrl` for the
391
+ * `uploads.github.com` host that release-asset uploads go to. Everything else a
392
+ * caller might reach for is a real endpoint parameter and is already typed.
393
+ *
394
+ * @public
395
+ */
396
+ interface RequestExtras {
397
+ /** Extra request headers. Keys must be lowercase. */
398
+ readonly headers?: RequestHeaders;
399
+ /** Media-type negotiation, e.g. `{ format: "raw" }`. */
400
+ readonly mediaType?: {
401
+ readonly format?: string;
402
+ };
403
+ /** Overrides the API host for this one request. */
404
+ readonly baseUrl?: string;
405
+ }
406
+ /**
407
+ * The parameters `Route` accepts — path, query and body parameters from
408
+ * GitHub's OpenAPI description, plus the extras below.
409
+ *
410
+ * @public
411
+ */
412
+ type Params<R extends Route> = Endpoints[R]["parameters"] & RequestExtras;
413
+ /**
414
+ * The full response `Route` returns, including `status`, `headers` and `data`.
415
+ *
416
+ * @public
417
+ */
418
+ type Response<R extends Route> = Endpoints[R]["response"];
419
+ /**
420
+ * The `data` payload `Route` returns.
421
+ *
422
+ * @public
423
+ */
424
+ type Data<R extends Route> = Endpoints[R]["response"]["data"];
425
+ /**
426
+ * The subset of routes that paginate.
427
+ *
428
+ * @remarks
429
+ * Handing a non-paginating route to a paginating call is a **compile** error,
430
+ * which the string-keyed surface this package replaces could not express.
431
+ *
432
+ * @public
433
+ */
434
+ type PaginatingRoute = keyof PaginatingEndpoints;
435
+ /**
436
+ * One element of a paginating route's collection.
437
+ *
438
+ * @remarks
439
+ * Derived here rather than imported: `@octokit/plugin-paginate-rest` computes
440
+ * the same thing internally as `GetResultsType`, but does not export it. The
441
+ * second branch covers the search-shaped endpoints whose payload is
442
+ * `{ total_count, items }` rather than a bare array — octokit normalizes those
443
+ * to the inner array at runtime, and this mirrors that at the type level.
444
+ *
445
+ * @public
446
+ */
447
+ type Item<R extends PaginatingRoute> = PaginatingEndpoints[R]["response"]["data"] extends ReadonlyArray<infer T> ? T : PaginatingEndpoints[R]["response"]["data"] extends {
448
+ readonly items: ReadonlyArray<infer T>;
449
+ } ? T : never;
450
+ declare const PageOptions_base: Schema.Class<PageOptions, Schema.Struct<{
451
+ /** Items requested per page. GitHub's ceiling is 100. */
452
+ readonly perPage: Schema.optionalKey<Schema.Int>;
453
+ /** Stop after this many pages. Absent means "until GitHub stops". */
454
+ readonly maxPages: Schema.optionalKey<Schema.Int>;
455
+ }>, {}>;
456
+ /**
457
+ * How far a paginated read should go.
458
+ *
459
+ * @remarks
460
+ * Both fields are honored by every paginating method in this package. The
461
+ * package it replaces accepted them on the client and then passed `{}` at six
462
+ * of its eight call sites, so callers silently got 100-item pages and an
463
+ * unbounded walk with no way to say otherwise.
464
+ *
465
+ * `perPage` is **validated, not clamped**: GitHub caps a page at 100 and
466
+ * silently ignores anything larger, so a caller asking for 250 has a bug whose
467
+ * arithmetic is already wrong. Failing at the boundary is cheaper than
468
+ * discovering it in production.
469
+ *
470
+ * @public
471
+ */
472
+ declare class PageOptions extends PageOptions_base {
473
+ /** Reads every page, 100 at a time — GitHub's maximum page size. */
474
+ static readonly all: PageOptions;
475
+ /**
476
+ * Reads at most one page of `perPage` items.
477
+ *
478
+ * @remarks
479
+ * The shape a "is there any?" or "give me the newest few" read wants, where
480
+ * walking every page is waste.
481
+ */
482
+ static first(perPage: number): PageOptions;
483
+ }
484
+ //#endregion
485
+ //#region src/GitHubClient.d.ts
486
+ /**
487
+ * The typed GitHub transport: one request, one paginated read, one GraphQL
488
+ * document, and whatever the rate-limit headers last said.
489
+ *
490
+ * @remarks
491
+ * Every member is an `Effect`, a `Stream`, or a function returning one — the
492
+ * rule that keeps `Layer.mock` and `layerTest(Partial<Shape>)` useful. That
493
+ * includes `rateLimit`, which is an `Effect`-valued property rather than a
494
+ * getter for exactly this reason.
495
+ *
496
+ * @public
497
+ */
498
+ interface GitHubClientShape {
499
+ /**
500
+ * One request. The route types both the parameters and the returned `data`.
501
+ *
502
+ * @example
503
+ * ```ts
504
+ * import { GitHubClient } from "@effected/github";
505
+ * import { Effect } from "effect";
506
+ *
507
+ * const defaultBranch = Effect.gen(function* () {
508
+ * const client = yield* GitHubClient;
509
+ * const repo = yield* client.request("GET /repos/{owner}/{repo}", { owner: "o", repo: "r" });
510
+ * return repo.default_branch; // string — no cast, no hand-written interface
511
+ * });
512
+ * ```
513
+ */
514
+ readonly request: <R extends Route>(route: R, params: Params<R>) => Effect.Effect<Data<R>, GitHubError>;
515
+ /**
516
+ * A route GitHub does not describe in its OpenAPI schema, or one whose live
517
+ * shape differs from it.
518
+ *
519
+ * @remarks
520
+ * The `schema` is **mandatory**. This is an escape hatch from the route
521
+ * table, never from typing: the payload still arrives decoded, and a shape
522
+ * mismatch fails as `kind: "decode"` rather than surfacing as a value nobody
523
+ * checked. The attestations read uses it, because pinning
524
+ * `X-GitHub-Api-Version` puts the response on a contract the generated types
525
+ * do not describe.
526
+ */
527
+ readonly requestDecoded: <A, I>(route: string, params: Record<string, unknown> & RequestExtras, schema: Schema.Codec<A, I>) => Effect.Effect<A, GitHubError>;
528
+ /**
529
+ * Collect every page of a paginating route, honoring {@link PageOptions}.
530
+ *
531
+ * @remarks
532
+ * Handing this a non-paginating route is a compile error.
533
+ */
534
+ readonly paginate: <R extends PaginatingRoute>(route: R, params: Params<R>, options?: PageOptions) => Effect.Effect<ReadonlyArray<Item<R>>, GitHubError>;
535
+ /**
536
+ * The same traversal as a `Stream`, for when the caller decides where to stop.
537
+ *
538
+ * @remarks
539
+ * Lazy in requests: a downstream `Stream.take` stops the walk rather than
540
+ * filtering pages that were already fetched.
541
+ */
542
+ readonly paginateStream: <R extends PaginatingRoute>(route: R, params: Params<R>, options?: PageOptions) => Stream.Stream<Item<R>, GitHubError>;
543
+ /** Run an owned GraphQL document and decode its answer. */
544
+ readonly graphql: <A, V extends Record<string, unknown>>(document: GraphQLDocument<A, V>, variables: V) => Effect.Effect<A, GitHubGraphQLError>;
545
+ /**
546
+ * What GitHub's rate-limit headers said on the most recent response.
547
+ *
548
+ * @remarks
549
+ * Observation, not policy: **nothing here throttles on your behalf.** The
550
+ * client retries a rate-limited failure with GitHub's own advised delay, and
551
+ * a caller that wants to pace itself proactively reads this.
552
+ */
553
+ readonly rateLimit: Effect.Effect<Option.Option<RateLimitSnapshot>>;
554
+ }
555
+ /**
556
+ * How a client layer is built.
557
+ *
558
+ * @public
559
+ */
560
+ interface GitHubClientOptions {
561
+ /** The token every request authenticates with. */
562
+ readonly token: Redacted.Redacted<string>;
563
+ /** Retry behavior. Defaults to {@link RetryPolicy.default}; `"off"` disables it. */
564
+ readonly retry?: RetryPolicy | "off" | undefined;
565
+ /** A GitHub Enterprise API root, e.g. `https://github.acme.com/api/v3`. */
566
+ readonly baseUrl?: string | undefined;
567
+ /** Appended to octokit's own user agent. */
568
+ readonly userAgent?: string | undefined;
569
+ /**
570
+ * A replacement for the global `fetch`.
571
+ *
572
+ * @remarks
573
+ * octokit's own documented hook. It is the seam a test drives the **real**
574
+ * request path through — classification, header capture, retry and
575
+ * pagination all exercised against canned HTTP responses instead of against
576
+ * a hand-written double of this service.
577
+ */
578
+ readonly fetch?: typeof globalThis.fetch | undefined;
579
+ }
580
+ /**
581
+ * A recorded response table for {@link GitHubClient.layerFixture}.
582
+ *
583
+ * @public
584
+ */
585
+ interface GitHubFixtures {
586
+ /** Keyed by route; the value is the `data` payload a request answers with. */
587
+ readonly request?: Readonly<Record<string, unknown>> | undefined;
588
+ /** Keyed by route; the value is the whole collection, paged on demand. */
589
+ readonly paginate?: Readonly<Record<string, ReadonlyArray<unknown>>> | undefined;
590
+ /** Keyed by document name; the value is the raw payload to decode. */
591
+ readonly graphql?: Readonly<Record<string, unknown>> | undefined;
592
+ /** What `rateLimit` answers. */
593
+ readonly rateLimit?: RateLimitSnapshot | undefined;
594
+ /**
595
+ * Every route a paginated read requested, in order, with the page size asked
596
+ * for. Populated by the fixture as the test runs.
597
+ */
598
+ readonly requested?: Array<{
599
+ readonly route: string;
600
+ readonly perPage: number;
601
+ }> | undefined;
602
+ }
603
+ declare const GitHubClient_base: Context.ServiceClass<GitHubClient, "@effected/github/GitHubClient", GitHubClientShape>;
604
+ /**
605
+ * The typed GitHub API client.
606
+ *
607
+ * @remarks
608
+ * The route is the key. `@octokit/types` generates a map from GitHub's OpenAPI
609
+ * description that carries every endpoint's parameter and response shapes, and
610
+ * `@octokit/core`'s `request` already consumes it — so a caller writes a route
611
+ * literal and gets both sides typed, with no callback, no type parameter to
612
+ * invent, and no cast.
613
+ *
614
+ * That is the whole point of this package. The surface it replaces was
615
+ * `rest<T>(operation: string, fn: (octokit: any) => Promise<{ data: T }>)`,
616
+ * where `T` was whatever the caller wrote and nothing connected it to the
617
+ * endpoint. Four consumer repos paid for that with sixteen cast sites and three
618
+ * hand-written octokit interfaces, one of which gave up and typed its methods as
619
+ * `Record<string, (p: unknown) => Promise<{ data: unknown }>>`.
620
+ *
621
+ * @public
622
+ */
623
+ declare class GitHubClient extends GitHubClient_base {
624
+ /**
625
+ * A client authenticated with a token you already hold.
626
+ *
627
+ * @remarks
628
+ * This module imports `@octokit/core` and nothing heavier. A consumer that
629
+ * only ever authenticates with a token never links the GitHub App JWT signer,
630
+ * because the App-authenticated layer lives in `GitHubApp` — a different
631
+ * module — rather than as a third static here.
632
+ */
633
+ static readonly layerFromToken: (options: GitHubClientOptions) => Layer.Layer<GitHubClient>;
634
+ /**
635
+ * A client authenticated from configuration, `GITHUB_TOKEN` by default.
636
+ *
637
+ * @remarks
638
+ * Reads through the ambient `ConfigProvider`, not `process.env`, so a test
639
+ * provides a provider instead of mutating the environment and a non-Actions
640
+ * consumer can source the token however it likes.
641
+ *
642
+ * Construction fails with core's `ConfigError` — an honest "no token is
643
+ * configured". The layer this replaces failed with a **wire-failure** error
644
+ * type instead, which is why one consumer wrapped it in `Layer.orDie` under a
645
+ * five-line comment explaining that the error did not mean what it said.
646
+ */
647
+ static readonly layerFromConfig: (options?: Omit<GitHubClientOptions, "token"> & {
648
+ readonly name?: string | undefined;
649
+ }) => Layer.Layer<GitHubClient, Config.ConfigError>;
650
+ /**
651
+ * An in-memory double: stub the members a test exercises, and every other
652
+ * member **dies** naming itself.
653
+ *
654
+ * @remarks
655
+ * No member has an honest default. A fabricated response — an empty list, a
656
+ * made-up sha — would leak into the code under test as fact, so the double
657
+ * fails loudly instead, which also makes it proof that a test touches nothing
658
+ * but what it stubbed.
659
+ *
660
+ * For recorded responses that page for real, use
661
+ * {@link GitHubClient.layerFixture}.
662
+ */
663
+ static readonly makeTest: (overrides?: Partial<GitHubClientShape>) => GitHubClientShape;
664
+ /** {@link GitHubClient.makeTest} behind a `Layer`. */
665
+ static readonly layerTest: (overrides?: Partial<GitHubClientShape>) => Layer.Layer<GitHubClient>;
666
+ /**
667
+ * A double over recorded responses that **pages them for real**.
668
+ *
669
+ * @remarks
670
+ * The one recorded-response double in this package, and the single narrow
671
+ * exception to the no-behavior-reimplementing-doubles rule — safe precisely
672
+ * because it reimplements nothing: it builds a `PageSource` over the recorded
673
+ * array and hands it to the same `paginate` engine the live client uses, so
674
+ * `perPage` and `maxPages` cannot behave differently here than in production.
675
+ *
676
+ * The double it replaces named its pagination parameters `_options` and
677
+ * ignored them, returning every recorded page regardless of what the caller
678
+ * asked for — which made every truncation path in every consumer
679
+ * structurally untestable.
680
+ *
681
+ * `fixtures.requested` is appended to as the test runs, so a suite can assert
682
+ * which routes were walked and at what page size.
683
+ */
684
+ static readonly layerFixture: (fixtures: GitHubFixtures) => Layer.Layer<GitHubClient>;
685
+ }
686
+ //#endregion
687
+ //#region src/ArtifactMetadata.d.ts
688
+ declare const StorageRecordInput_base: Schema.Class<StorageRecordInput, Schema.Struct<{
689
+ /** The artifact's package URL (purl). */
690
+ readonly name: Schema.NonEmptyString;
691
+ /** Its content digest, as `algorithm:hex`. */
692
+ readonly digest: Schema.NonEmptyString;
693
+ /** The registry's base URL. */
694
+ readonly registryUrl: Schema.NonEmptyString;
695
+ /** The repository name **within the registry**. */
696
+ readonly repository: Schema.NonEmptyString;
697
+ /** Where the artifact is stored, when there is a direct URL. */
698
+ readonly artifactUrl: Schema.optionalKey<Schema.String>;
699
+ /** The artifact's path within the registry, when there is one. */
700
+ readonly path: Schema.optionalKey<Schema.String>;
701
+ }>, {}>;
702
+ /**
703
+ * What to record about a published artifact.
704
+ *
705
+ * @remarks
706
+ * These are the fields the endpoint actually accepts. The version this replaces
707
+ * declared a `version` field the endpoint has no notion of — a fabricated key
708
+ * that a `Record<string, unknown>` body accepted silently and the generated
709
+ * types reject outright.
710
+ *
711
+ * @public
712
+ */
713
+ declare class StorageRecordInput extends StorageRecordInput_base {}
714
+ /**
715
+ * Organization-level artifact metadata.
716
+ *
717
+ * @remarks
718
+ * Org-scoped rather than repository-scoped, so it takes the organization as an
719
+ * argument and does **not** read {@link Repo}.
720
+ *
721
+ * @public
722
+ */
723
+ interface ArtifactMetadataShape {
724
+ /** Record where a published artifact lives; returns the ids GitHub stored. */
725
+ readonly createStorageRecord: (org: string, input: StorageRecordInput) => Effect.Effect<ReadonlyArray<number>, GitHubError>;
726
+ }
727
+ declare const ArtifactMetadata_base: Context.ServiceClass<ArtifactMetadata, "@effected/github/ArtifactMetadata", ArtifactMetadataShape>;
728
+ /**
729
+ * Artifact metadata.
730
+ *
731
+ * @public
732
+ */
733
+ declare class ArtifactMetadata extends ArtifactMetadata_base {
734
+ static readonly layer: Layer.Layer<ArtifactMetadata, never, GitHubClient>;
735
+ /** An in-memory double; unstubbed members die naming themselves. */
736
+ static readonly makeTest: (overrides?: Partial<ArtifactMetadataShape>) => ArtifactMetadataShape;
737
+ /** {@link ArtifactMetadata.makeTest} behind a `Layer`. */
738
+ static readonly layerTest: (overrides?: Partial<ArtifactMetadataShape>) => Layer.Layer<ArtifactMetadata>;
739
+ }
740
+ //#endregion
741
+ //#region src/Repo.d.ts
742
+ declare const InvalidRepoRefError_base: Schema.Class<InvalidRepoRefError, Schema.TaggedStruct<"InvalidRepoRefError", {
743
+ /** What was handed in. */
744
+ readonly input: Schema.String;
745
+ }>, import("effect/Cause").YieldableError>;
746
+ /**
747
+ * A repository slug was not `owner/repo`.
748
+ *
749
+ * @public
750
+ */
751
+ declare class InvalidRepoRefError extends InvalidRepoRefError_base {
752
+ get message(): string;
753
+ }
754
+ declare const RepoRef_base: Schema.Class<RepoRef, Schema.Struct<{
755
+ /** The user or organization. */
756
+ readonly owner: Schema.NonEmptyString;
757
+ /** The repository name, without the owner. */
758
+ readonly repo: Schema.NonEmptyString;
759
+ }>, {}>;
760
+ /**
761
+ * Which repository an operation acts on.
762
+ *
763
+ * @public
764
+ */
765
+ declare class RepoRef extends RepoRef_base {
766
+ /**
767
+ * Parse `"owner/repo"`, synchronously.
768
+ *
769
+ * @remarks
770
+ * The sync `Result` primitive; {@link RepoRef.parse} is the `Effect` form over
771
+ * it. `make` is reserved by the class factory for the validated field
772
+ * constructor, which is why string parsing is named rather than overloaded.
773
+ */
774
+ static parseResult(slug: string): Result.Result<RepoRef, InvalidRepoRefError>;
775
+ /** Parse `"owner/repo"`. */
776
+ static readonly parse: (slug: string) => Effect.Effect<RepoRef, InvalidRepoRefError, never>;
777
+ /** `"owner/repo"`. */
778
+ get slug(): string;
779
+ }
780
+ declare const Repo_base: Context.ServiceClass<Repo, "@effected/github/Repo", RepoRef>;
781
+ /**
782
+ * The repository the surrounding program acts on.
783
+ *
784
+ * @remarks
785
+ * Every resource service takes this in its `R` and **no method takes an
786
+ * `{ owner, repo }` argument**, which is what makes a read like
787
+ * `GitHubRepository.defaultBranch` a single expression instead of a preamble.
788
+ *
789
+ * The package this replaces read `process.env.GITHUB_REPOSITORY` in three
790
+ * places — inside the client, inside the App layer, and transitively in every
791
+ * caller of `client.repo` — which is most of what coupled a GitHub API client to
792
+ * the GitHub Actions runtime. Here the coordinate is a value, the env-driven way
793
+ * to get one is a layer variant **named for being env-driven**, and a program
794
+ * that acts on several repositories uses {@link Repo.provide}:
795
+ *
796
+ * @example
797
+ * ```ts
798
+ * import { Repo } from "@effected/github";
799
+ * import { Effect } from "effect";
800
+ *
801
+ * declare const syncOne: Effect.Effect<void, never, Repo>;
802
+ * declare const targets: ReadonlyArray<Repo["Service"]>;
803
+ *
804
+ * const syncAll = Effect.forEach(targets, (target) => syncOne.pipe(Repo.provide(target)), {
805
+ * concurrency: 4,
806
+ * });
807
+ * ```
808
+ *
809
+ * **A deliberate exception to "no non-effectful members on a service shape."**
810
+ * This shape is entirely one immutable value: there is nothing to leave
811
+ * unimplemented, so `Layer.mock` has nothing to degrade and `Layer.succeed` is
812
+ * the correct double. The rule exists to stop a sync member from quietly
813
+ * degrading a *mixed* shape's partial mock. The boundary to hold: the moment a
814
+ * method appears here, this is a service again and the rule applies.
815
+ *
816
+ * @public
817
+ */
818
+ declare class Repo extends Repo_base {
819
+ /** The repository, as a value you already have. */
820
+ static readonly layer: (ref: RepoRef) => Layer.Layer<Repo>;
821
+ /** The repository, from an `"owner/repo"` slug. */
822
+ static readonly layerFromSlug: (slug: string) => Layer.Layer<Repo, InvalidRepoRefError>;
823
+ /**
824
+ * The repository from configuration, `GITHUB_REPOSITORY` by default.
825
+ *
826
+ * @remarks
827
+ * The one env-driven variant, read through the ambient `ConfigProvider` rather
828
+ * than `process.env` — so a test provides a provider instead of mutating the
829
+ * environment, and a consumer outside Actions can source it however it likes.
830
+ */
831
+ static readonly layerFromConfig: (options?: {
832
+ readonly name?: string | undefined;
833
+ }) => Layer.Layer<Repo, Config.ConfigError | InvalidRepoRefError>;
834
+ /** Run `effect` against a different repository. */
835
+ static readonly provide: (ref: RepoRef) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Repo>>;
836
+ }
837
+ //#endregion
838
+ //#region src/Attestation.d.ts
839
+ declare const AttestationRecord_base: Schema.Class<AttestationRecord, Schema.Struct<{
840
+ /** GitHub's id for it, when the response carried one. */
841
+ readonly id: Schema.optionalKey<Schema.Int>;
842
+ /** Where a human can look at it. */
843
+ readonly url: Schema.String;
844
+ }>, {}>;
845
+ /**
846
+ * A stored attestation.
847
+ *
848
+ * @public
849
+ */
850
+ declare class AttestationRecord extends AttestationRecord_base {}
851
+ declare const AttestationListEntry_base: Schema.Class<AttestationListEntry, Schema.Struct<{
852
+ /** Where the bundle lives. */
853
+ readonly url: Schema.String;
854
+ /** The in-toto predicate type, when the listing reported one. */
855
+ readonly predicateType: Schema.optionalKey<Schema.String>;
856
+ }>, {}>;
857
+ /**
858
+ * One entry from an attestation listing.
859
+ *
860
+ * @public
861
+ */
862
+ declare class AttestationListEntry extends AttestationListEntry_base {}
863
+ /**
864
+ * The attestation REST surface.
865
+ *
866
+ * @remarks
867
+ * Upload and listing only. Building a statement, signing it and producing the
868
+ * bundle belong to `@effected/sbom`; assembling those into a pipeline belongs to
869
+ * the consumer. That split is what dissolves the five-service knot the previous
870
+ * package needed a mega-layer to test.
871
+ *
872
+ * @public
873
+ */
874
+ interface AttestationShape {
875
+ /** Store a signed bundle against the repository. */
876
+ readonly upload: (bundle: unknown) => Effect.Effect<AttestationRecord, GitHubError, Repo>;
877
+ /**
878
+ * Everything attested about a subject digest.
879
+ *
880
+ * @remarks
881
+ * **404 and 422 both mean "none"**, not "broken" — GitHub answers a digest it
882
+ * has never seen either way depending on the path, and a caller asking "is
883
+ * this attested?" wants an empty list for both.
884
+ */
885
+ readonly listForSubject: (sha256: string, options?: {
886
+ readonly predicateType?: string | undefined;
887
+ }) => Effect.Effect<ReadonlyArray<AttestationListEntry>, GitHubError, Repo>;
888
+ }
889
+ declare const Attestation_base: Context.ServiceClass<Attestation, "@effected/github/Attestation", AttestationShape>;
890
+ /**
891
+ * Attestations.
892
+ *
893
+ * @public
894
+ */
895
+ declare class Attestation extends Attestation_base {
896
+ static readonly layer: Layer.Layer<Attestation, never, GitHubClient>;
897
+ /** An in-memory double; unstubbed members die naming themselves. */
898
+ static readonly makeTest: (overrides?: Partial<AttestationShape>) => AttestationShape;
899
+ /** {@link Attestation.makeTest} behind a `Layer`. */
900
+ static readonly layerTest: (overrides?: Partial<AttestationShape>) => Layer.Layer<Attestation>;
901
+ }
902
+ //#endregion
903
+ //#region src/CheckRun.d.ts
904
+ /** How a check run finished. @public */
905
+ declare const CheckConclusion: Schema.Literals<readonly ["success", "failure", "neutral", "cancelled", "timed_out", "action_required", "skipped"]>;
906
+ /** How serious an annotation is. @public */
907
+ declare const AnnotationLevel: Schema.Literals<readonly ["notice", "warning", "failure"]>;
908
+ declare const Annotation_base: Schema.Class<Annotation, Schema.Struct<{
909
+ /** Repository-relative path. */
910
+ readonly path: Schema.String;
911
+ /** First line of the range, 1-based. */
912
+ readonly startLine: Schema.Int;
913
+ /** Last line of the range, 1-based. */
914
+ readonly endLine: Schema.Int;
915
+ readonly level: Schema.Literals<readonly ["notice", "warning", "failure"]>;
916
+ readonly message: Schema.String;
917
+ readonly title: Schema.optionalKey<Schema.String>;
918
+ }>, {}>;
919
+ /**
920
+ * One annotation on a check run.
921
+ *
922
+ * @public
923
+ */
924
+ declare class Annotation extends Annotation_base {}
925
+ declare const CheckRunOutput_base: Schema.Class<CheckRunOutput, Schema.Struct<{
926
+ readonly title: Schema.String;
927
+ /** Markdown shown under the title. Capped at 65535 **bytes**. */
928
+ readonly summary: Schema.String;
929
+ /** Longer markdown. Capped at 65535 **bytes**. */
930
+ readonly text: Schema.optionalKey<Schema.String>;
931
+ /** At most 50 per request; the rest are dropped by {@link CheckRunOutput.truncated}. */
932
+ readonly annotations: Schema.optionalKey<Schema.$Array<typeof Annotation>>;
933
+ }>, {}>;
934
+ /**
935
+ * A check run's rendered output.
936
+ *
937
+ * @remarks
938
+ * GitHub's limits are **byte** limits, and that distinction is the whole reason
939
+ * this class exists rather than a struct: `✅`, `❌`, `🦋` and `│` cost several
940
+ * bytes each, so a character-count check passes while the request comes back
941
+ * 422 saying *"summary exceeds a maximum bytesize of 65535"*. One consumer hit
942
+ * exactly that and wrote the truncation by hand.
943
+ *
944
+ * @public
945
+ */
946
+ declare class CheckRunOutput extends CheckRunOutput_base {
947
+ /** GitHub's cap on `summary` and `text`, in UTF-8 bytes. */
948
+ static readonly LIMIT_BYTES = 65535;
949
+ /** GitHub's cap on annotations per request. */
950
+ static readonly MAX_ANNOTATIONS = 50;
951
+ /** Appended when a field had to be cut. */
952
+ static readonly NOTICE = "\n\n_…truncated (exceeded GitHub's 65535-byte check limit)._";
953
+ /**
954
+ * This output, cut to fit GitHub's limits.
955
+ *
956
+ * @remarks
957
+ * Pure, so the byte arithmetic is testable with no client, no layer and no
958
+ * network — which is what lets a property test hammer it with arbitrary
959
+ * multi-byte input.
960
+ */
961
+ truncated(): CheckRunOutput;
962
+ }
963
+ declare const CheckRunRef_base: Schema.Class<CheckRunRef, Schema.Struct<{
964
+ readonly id: Schema.Int;
965
+ readonly name: Schema.String;
966
+ /** The web URL. */
967
+ readonly url: Schema.String;
968
+ readonly status: Schema.String;
969
+ }>, {}>;
970
+ /**
971
+ * A check run as GitHub reports it.
972
+ *
973
+ * @public
974
+ */
975
+ declare class CheckRunRef extends CheckRunRef_base {}
976
+ /**
977
+ * Conclude the surrounding {@link CheckRunShape.withCheckRun} explicitly.
978
+ *
979
+ * @remarks
980
+ * **Recording, not sending.** The call stores the verdict; the bracket's
981
+ * finalizer writes it exactly once, on whichever path `use` leaves by. That is
982
+ * what makes an explicit conclusion survive a later failure or an interrupt,
983
+ * and what keeps the completion a single request no matter how many times this
984
+ * is called. Calling it twice keeps the **last** verdict.
985
+ *
986
+ * Its error channel is `never` because the finalizer owns the reporting: a
987
+ * caller that could observe a failed `complete` here would have to decide what
988
+ * to do about it while already on the way out.
989
+ *
990
+ * Omit `output` to conclude without touching the run's rendered output —
991
+ * whatever the last {@link CheckRunShape.update} wrote stays.
992
+ *
993
+ * @public
994
+ */
995
+ type ConcludeCheckRun = (conclusion: (typeof CheckConclusion.literals)[number], output?: CheckRunOutput) => Effect.Effect<void>;
996
+ /**
997
+ * Check runs.
998
+ *
999
+ * @public
1000
+ */
1001
+ interface CheckRunShape {
1002
+ /** Start an in-progress check run against a commit. */
1003
+ readonly create: (name: string, headSha: string) => Effect.Effect<CheckRunRef, GitHubError, Repo>;
1004
+ readonly get: (id: number) => Effect.Effect<CheckRunRef, GitHubError, Repo>;
1005
+ /** Update an in-flight run's output. */
1006
+ readonly update: (id: number, output: CheckRunOutput) => Effect.Effect<void, GitHubError, Repo>;
1007
+ /** Finish a run. */
1008
+ readonly complete: (id: number, conclusion: (typeof CheckConclusion.literals)[number], output?: CheckRunOutput) => Effect.Effect<void, GitHubError, Repo>;
1009
+ /**
1010
+ * Run `use` inside a check run, concluding it however `use` exits.
1011
+ *
1012
+ * @remarks
1013
+ * **Every exit reaches a terminal state.** Left to itself the bracket
1014
+ * concludes `"success"` on success, `"failure"` on a typed failure or a
1015
+ * defect, and `"cancelled"` on an interrupt. A run left `in_progress` is
1016
+ * never reaped by GitHub and blocks branch protection until someone deletes
1017
+ * it by hand, so the finalizer is exit-aware rather than a `tap`/`tapError`
1018
+ * pair — which fires on the first two only.
1019
+ *
1020
+ * **`use` can override that verdict**, which is how the other four
1021
+ * conclusions are reachable. `conclude` records one; a recorded verdict
1022
+ * **wins on every exit path**, including failure and interruption, because
1023
+ * how a check ran and how the surrounding program ended are different
1024
+ * questions. A findings-derived `"neutral"` is the motivating case: the work
1025
+ * ran fine and the result is advisory.
1026
+ *
1027
+ * Only the success path can fail the effect on the conclusion's behalf.
1028
+ * Neither an interrupt nor an existing failure is replaced by whatever went
1029
+ * wrong while reporting it.
1030
+ *
1031
+ * `use` keeps its own `R` and its own `A`, unlike the version this replaces,
1032
+ * whose callback was `R`-less and so forced consumers to build
1033
+ * self-contained layers just to use the bracket.
1034
+ *
1035
+ * @example
1036
+ * ```ts
1037
+ * check.withCheckRun("lint", sha, (id, conclude) =>
1038
+ * Effect.gen(function* () {
1039
+ * const findings = yield* lint();
1040
+ * yield* conclude(deriveConclusion(findings), report(findings));
1041
+ * return findings;
1042
+ * }),
1043
+ * );
1044
+ * ```
1045
+ */
1046
+ readonly withCheckRun: <A, E, R>(name: string, headSha: string, use: (id: number, conclude: ConcludeCheckRun) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | GitHubError, R | Repo>;
1047
+ }
1048
+ declare const CheckRun_base: Context.ServiceClass<CheckRun, "@effected/github/CheckRun", CheckRunShape>;
1049
+ /**
1050
+ * Check runs.
1051
+ *
1052
+ * @public
1053
+ */
1054
+ declare class CheckRun extends CheckRun_base {
1055
+ static readonly layer: Layer.Layer<CheckRun, never, GitHubClient>;
1056
+ /** An in-memory double; unstubbed members die naming themselves. */
1057
+ static readonly makeTest: (overrides?: Partial<CheckRunShape>) => CheckRunShape;
1058
+ /** {@link CheckRun.makeTest} behind a `Layer`. */
1059
+ static readonly layerTest: (overrides?: Partial<CheckRunShape>) => Layer.Layer<CheckRun>;
1060
+ }
1061
+ //#endregion
1062
+ //#region src/GitBranch.d.ts
1063
+ /**
1064
+ * What {@link GitBranchShape.upsert} did.
1065
+ *
1066
+ * @public
1067
+ */
1068
+ type BranchOutcome = "created" | "reset";
1069
+ /**
1070
+ * Branch refs in GitHub's Git Database API.
1071
+ *
1072
+ * @remarks
1073
+ * **Not local git.** Despite the name this is `POST /repos/…/git/refs` and
1074
+ * friends — no subprocess, no working tree, no checkout. `@effected/git` is the
1075
+ * package that runs git.
1076
+ *
1077
+ * @public
1078
+ */
1079
+ interface GitBranchShape {
1080
+ /** Create a branch at `sha`. Fails `alreadyExists` when it is already there. */
1081
+ readonly create: (name: string, sha: string) => Effect.Effect<void, GitHubError, Repo>;
1082
+ /**
1083
+ * Point `name` at `sha`, creating it if needed.
1084
+ *
1085
+ * @remarks
1086
+ * **One call, one intent.** Creating a branch that may already exist is the
1087
+ * single most-repeated dance in the surveyed consumers: the marketplace
1088
+ * manager spent a seven-line comment and a nine-line workaround on it, doing
1089
+ * `getSha` → `exists` → `create` → on failure `exists` again → `reset`, up to
1090
+ * four round trips, because the error it caught carried no structured
1091
+ * "already exists". silk-release-action wrote the mirror image of the same
1092
+ * dance a few files away.
1093
+ *
1094
+ * This is one round trip in the common case and two in the raced one, and the
1095
+ * recovery **resets** rather than inheriting a branch a concurrent creator
1096
+ * rooted somewhere else — which is the semantics that comment was defending.
1097
+ */
1098
+ readonly upsert: (name: string, sha: string) => Effect.Effect<BranchOutcome, GitHubError, Repo>;
1099
+ /** Is the branch there? A 404 is `false`, not an error. */
1100
+ readonly exists: (name: string) => Effect.Effect<boolean, GitHubError, Repo>;
1101
+ /** The commit the branch points at. Fails `notFound` when it does not exist. */
1102
+ readonly sha: (name: string) => Effect.Effect<string, GitHubError, Repo>;
1103
+ /** As {@link GitBranchShape.sha}, with absence as `Option.none`. */
1104
+ readonly shaOption: (name: string) => Effect.Effect<Option.Option<string>, GitHubError, Repo>;
1105
+ /** Force the branch to `sha`. Fails `notFound` when it does not exist. */
1106
+ readonly reset: (name: string, sha: string) => Effect.Effect<void, GitHubError, Repo>;
1107
+ /** Delete the branch. */
1108
+ readonly delete: (name: string) => Effect.Effect<void, GitHubError, Repo>;
1109
+ /**
1110
+ * Create a branch **linked to an issue**, as the GitHub UI's "create a branch"
1111
+ * button does.
1112
+ *
1113
+ * @remarks
1114
+ * The one operation in this package with **no REST equivalent** — GitHub
1115
+ * exposes `createLinkedBranch` only through GraphQL, which is why the document
1116
+ * is owned here rather than left in a consumer. A linked branch shows up on the
1117
+ * issue and closes it when the branch's pull request merges; a branch created
1118
+ * with {@link GitBranchShape.create} does neither.
1119
+ */
1120
+ readonly createLinked: (input: {
1121
+ readonly issueNodeId: string;
1122
+ readonly repositoryNodeId: string;
1123
+ readonly name: string;
1124
+ readonly sha: string;
1125
+ }) => Effect.Effect<void, GitHubGraphQLError, Repo>;
1126
+ }
1127
+ declare const GitBranch_base: Context.ServiceClass<GitBranch, "@effected/github/GitBranch", GitBranchShape>;
1128
+ /**
1129
+ * Branches, as refs.
1130
+ *
1131
+ * @public
1132
+ */
1133
+ declare class GitBranch extends GitBranch_base {
1134
+ /**
1135
+ * @remarks
1136
+ * The callback is written `(client) => make(client)` rather than passed as
1137
+ * `make` directly, and that is load-bearing: a static initializer runs while
1138
+ * the module body is still evaluating, so naming a `const` declared further
1139
+ * down throws `Cannot access 'make' before initialization` **at import time**,
1140
+ * with a clean typecheck. Wrapping it in an arrow defers the read to when the
1141
+ * layer is built.
1142
+ */
1143
+ static readonly layer: Layer.Layer<GitBranch, never, GitHubClient>;
1144
+ /** An in-memory double; unstubbed members die naming themselves. */
1145
+ static readonly makeTest: (overrides?: Partial<GitBranchShape>) => GitBranchShape;
1146
+ /** {@link GitBranch.makeTest} behind a `Layer`. */
1147
+ static readonly layerTest: (overrides?: Partial<GitBranchShape>) => Layer.Layer<GitBranch>;
1148
+ }
1149
+ //#endregion
1150
+ //#region src/GitCommit.d.ts
1151
+ /**
1152
+ * A blob's file mode, as the Git Database API spells it.
1153
+ *
1154
+ * @public
1155
+ */
1156
+ declare const FileMode: Schema.Literals<readonly ["100644", "100755", "120000"]>;
1157
+ declare const FileContent_base: Schema.Class<FileContent, Schema.TaggedStruct<"FileContent", {
1158
+ /** Repository-relative path. */
1159
+ readonly path: Schema.NonEmptyString;
1160
+ /** The file's new contents. */
1161
+ readonly content: Schema.String;
1162
+ /** Defaults to a regular file. */
1163
+ readonly mode: Schema.optionalKey<Schema.Literals<readonly ["100644", "100755", "120000"]>>;
1164
+ }>, {}>;
1165
+ /**
1166
+ * A file to write in a commit.
1167
+ *
1168
+ * @public
1169
+ */
1170
+ declare class FileContent extends FileContent_base {}
1171
+ declare const FileDeletion_base: Schema.Class<FileDeletion, Schema.TaggedStruct<"FileDeletion", {
1172
+ /** Repository-relative path. */
1173
+ readonly path: Schema.NonEmptyString;
1174
+ }>, {}>;
1175
+ /**
1176
+ * A file to remove in a commit.
1177
+ *
1178
+ * @public
1179
+ */
1180
+ declare class FileDeletion extends FileDeletion_base {}
1181
+ /**
1182
+ * One change in a commit.
1183
+ *
1184
+ * @public
1185
+ */
1186
+ declare const FileChange: Schema.Union<readonly [typeof FileContent, typeof FileDeletion]>;
1187
+ /** One change in a commit. @public */
1188
+ type FileChange = FileContent | FileDeletion;
1189
+ declare const CommitRef_base: Schema.Class<CommitRef, Schema.Struct<{
1190
+ /** The commit's own sha. */
1191
+ readonly sha: Schema.String;
1192
+ /** The tree the commit points at — what `baseTree` wants. */
1193
+ readonly treeSha: Schema.String;
1194
+ /** Parent commit shas, in order. */
1195
+ readonly parents: Schema.$Array<Schema.String>;
1196
+ }>, {}>;
1197
+ /**
1198
+ * A commit, projected to the three fields callers actually use.
1199
+ *
1200
+ * @remarks
1201
+ * `treeSha` is here because two surveyed call sites dropped to a raw octokit
1202
+ * cast for it alone, both with the comment *"the Git Data API's `base_tree`
1203
+ * wants a tree SHA, not a commit SHA"* — the same eight lines written twice, in
1204
+ * two files, for one string.
1205
+ *
1206
+ * @public
1207
+ */
1208
+ declare class CommitRef extends CommitRef_base {}
1209
+ /**
1210
+ * Commits and trees in GitHub's Git Database API.
1211
+ *
1212
+ * @public
1213
+ */
1214
+ interface GitCommitShape {
1215
+ /** Read a commit's sha, tree and parents. */
1216
+ readonly get: (sha: string) => Effect.Effect<CommitRef, GitHubError, Repo>;
1217
+ /** Build a tree, optionally on top of an existing one. */
1218
+ readonly createTree: (options: {
1219
+ readonly changes: ReadonlyArray<FileChange>;
1220
+ readonly baseTree?: string | undefined;
1221
+ }) => Effect.Effect<string, GitHubError, Repo>;
1222
+ /** Create a commit object. */
1223
+ readonly createCommit: (options: {
1224
+ readonly message: string;
1225
+ readonly tree: string;
1226
+ readonly parents: ReadonlyArray<string>;
1227
+ }) => Effect.Effect<string, GitHubError, Repo>;
1228
+ /**
1229
+ * Write `changes` onto `branch` as one commit, returning its sha.
1230
+ *
1231
+ * @remarks
1232
+ * The four-call sequence — read the branch, build a tree on its commit's
1233
+ * tree, create the commit, move the ref — as one operation. The ref update is
1234
+ * **not** forced: a branch that moved underneath you is a conflict worth
1235
+ * hearing about, not one to overwrite.
1236
+ */
1237
+ readonly commitFiles: (options: {
1238
+ readonly branch: string;
1239
+ readonly message: string;
1240
+ readonly changes: ReadonlyArray<FileChange>;
1241
+ }) => Effect.Effect<string, GitHubError, Repo>;
1242
+ }
1243
+ declare const GitCommit_base: Context.ServiceClass<GitCommit, "@effected/github/GitCommit", GitCommitShape>;
1244
+ /**
1245
+ * Commits, trees and blobs.
1246
+ *
1247
+ * @public
1248
+ */
1249
+ declare class GitCommit extends GitCommit_base {
1250
+ static readonly layer: Layer.Layer<GitCommit, never, GitHubClient>;
1251
+ /** An in-memory double; unstubbed members die naming themselves. */
1252
+ static readonly makeTest: (overrides?: Partial<GitCommitShape>) => GitCommitShape;
1253
+ /** {@link GitCommit.makeTest} behind a `Layer`. */
1254
+ static readonly layerTest: (overrides?: Partial<GitCommitShape>) => Layer.Layer<GitCommit>;
1255
+ }
1256
+ //#endregion
1257
+ //#region src/GitHubApp.d.ts
1258
+ declare const GitHubAppError_base: Schema.Class<GitHubAppError, Schema.TaggedStruct<"GitHubAppError", {
1259
+ /** Which step failed. */
1260
+ readonly kind: Schema.Literals<readonly ["jwt", "token", "revoke", "identity", "installation"]>;
1261
+ /** Human-readable cause. */
1262
+ readonly reason: Schema.String;
1263
+ /** The underlying failure, when there is one. */
1264
+ readonly cause: Schema.optionalKey<Schema.Defect>;
1265
+ }>, import("effect/Cause").YieldableError>;
1266
+ /**
1267
+ * A GitHub App call failed.
1268
+ *
1269
+ * @remarks
1270
+ * Distinct from `GitHubError` because "I could not obtain credentials" and "the
1271
+ * API call failed" are different problems with different fixes: the first is a
1272
+ * misconfigured app, a wrong private key or a missing installation; the second
1273
+ * is the request that used the credentials.
1274
+ *
1275
+ * @public
1276
+ */
1277
+ declare class GitHubAppError extends GitHubAppError_base {
1278
+ get message(): string;
1279
+ /** @internal */
1280
+ static of(kind: GitHubAppError["kind"], reason: string, cause?: unknown): GitHubAppError;
1281
+ }
1282
+ /**
1283
+ * The credentials that identify a GitHub App.
1284
+ *
1285
+ * @remarks
1286
+ * `appId` accepts either the numeric app id or the newer client id — GitHub
1287
+ * accepts both as the JWT issuer, and this package does not care which you use.
1288
+ *
1289
+ * @public
1290
+ */
1291
+ interface AppCredentials {
1292
+ /** The app id or client id. */
1293
+ readonly appId: string;
1294
+ /**
1295
+ * The app's private key, in PEM.
1296
+ *
1297
+ * @remarks
1298
+ * PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`, which is what github.com hands
1299
+ * you) is converted to PKCS#8 automatically **on Node**. On a runtime without
1300
+ * `node:crypto` a PKCS#1 key fails with an explicit `kind: "jwt"` error, and
1301
+ * the fix is to convert the key once with
1302
+ * `openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt`. This constraint is
1303
+ * inherited from the JWT signer and is identical to `@octokit/auth-app`'s.
1304
+ */
1305
+ readonly privateKey: Redacted.Redacted<string>;
1306
+ }
1307
+ /**
1308
+ * What to mint an installation token for.
1309
+ *
1310
+ * @public
1311
+ */
1312
+ interface TokenRequest extends AppCredentials {
1313
+ /** The installation. Discovered from `owner` when omitted. */
1314
+ readonly installationId?: number | undefined;
1315
+ /**
1316
+ * The account whose installation to use, when `installationId` is omitted.
1317
+ *
1318
+ * @remarks
1319
+ * Discovery costs a JWT mint plus a paginated walk of `GET /app/installations`,
1320
+ * so supplying `installationId` is strictly cheaper. When both are omitted and
1321
+ * the app has exactly one installation, that one is used; with several, the
1322
+ * failure names them.
1323
+ */
1324
+ readonly owner?: string | undefined;
1325
+ }
1326
+ declare const InstallationToken_base: Schema.Class<InstallationToken, Schema.Struct<{
1327
+ /** The token. Decodes to `Redacted`, encodes back to the raw string. */
1328
+ readonly token: Schema.RedactedFromValue<Schema.String>;
1329
+ /** When GitHub will stop accepting it — about an hour out. */
1330
+ readonly expiresAt: Schema.DateTimeUtcFromString;
1331
+ /** The installation it is scoped to. */
1332
+ readonly installationId: Schema.Int;
1333
+ /** The permissions GitHub actually granted, which may be narrower than requested. */
1334
+ readonly permissions: Schema.$Record<Schema.String, Schema.String>;
1335
+ /** The app's slug, when identity was resolved. */
1336
+ readonly appSlug: Schema.optionalKey<Schema.String>;
1337
+ /** The app's bot user id, when identity was resolved. */
1338
+ readonly appUserId: Schema.optionalKey<Schema.Int>;
1339
+ /** The app's display name, when identity was resolved. */
1340
+ readonly appName: Schema.optionalKey<Schema.String>;
1341
+ }>, {}>;
1342
+ /**
1343
+ * An installation access token and what GitHub said about it.
1344
+ *
1345
+ * @remarks
1346
+ * Encodable on purpose. `@effected/github-actions` persists one across the
1347
+ * `pre`/`main`/`post` process boundary through `GITHUB_STATE`, and
1348
+ * `Schema.encodeUnknownEffect` produces JSON with the token as a plain string
1349
+ * and `expiresAt` as an ISO instant. A `Redacted` cannot survive serialization
1350
+ * by design, so masking the encoded value is the caller's job — Actions calls
1351
+ * `::add-mask::`.
1352
+ *
1353
+ * @public
1354
+ */
1355
+ declare class InstallationToken extends InstallationToken_base {
1356
+ /**
1357
+ * Whether this token is spent, `skew` before its stated expiry.
1358
+ *
1359
+ * @remarks
1360
+ * Modelled **and enforced**. The package this replaces persisted `expiresAt`
1361
+ * and read it nowhere, so a long `main` phase that outlived the hour simply
1362
+ * started answering 401 with no explanation.
1363
+ */
1364
+ isExpired(nowMillis: number, skew?: Duration.Duration): boolean;
1365
+ /** The committer identity a commit made with this token should carry. */
1366
+ botIdentity(): BotIdentity;
1367
+ }
1368
+ declare const BotIdentity_base: Schema.Class<BotIdentity, Schema.Struct<{
1369
+ /** The git author/committer name, e.g. `"my-app[bot]"`. */
1370
+ readonly name: Schema.String;
1371
+ /** The no-reply address GitHub attributes to that account. */
1372
+ readonly email: Schema.String;
1373
+ }>, {}>;
1374
+ /**
1375
+ * Who a bot commits as.
1376
+ *
1377
+ * @remarks
1378
+ * A **pure class**, not a service member. The package this replaces put
1379
+ * `botIdentity(source?)` on the `GitHubApp` service shape as a plain synchronous
1380
+ * method, which makes it required in every `Layer.mock` and silently degrades
1381
+ * every partial double to a full implementation.
1382
+ *
1383
+ * @public
1384
+ */
1385
+ declare class BotIdentity extends BotIdentity_base {
1386
+ /** The identity for an app, given whatever of its identity is known. */
1387
+ static forApp(source: {
1388
+ readonly appSlug: string;
1389
+ readonly appUserId?: number | undefined;
1390
+ }): BotIdentity;
1391
+ /** The well-known identity of the `github-actions` bot. */
1392
+ static readonly githubActions: BotIdentity;
1393
+ }
1394
+ declare const AppIdentity_base: Schema.Class<AppIdentity, Schema.Struct<{
1395
+ /** The URL slug, e.g. `"my-app"`. */
1396
+ readonly slug: Schema.String;
1397
+ /** The display name. */
1398
+ readonly name: Schema.String;
1399
+ /** The bot user's numeric id, when it could be resolved. */
1400
+ readonly userId: Schema.optionalKey<Schema.Int>;
1401
+ }>, {}>;
1402
+ /**
1403
+ * What GitHub knows about the app itself.
1404
+ *
1405
+ * @public
1406
+ */
1407
+ declare class AppIdentity extends AppIdentity_base {
1408
+ /** The committer identity for this app. */
1409
+ botIdentity(): BotIdentity;
1410
+ }
1411
+ declare const Installation_base: Schema.Class<Installation, Schema.Struct<{
1412
+ /** The installation id, which is what a token is minted against. */
1413
+ readonly id: Schema.Int;
1414
+ /** The account the app is installed on, when GitHub reported one. */
1415
+ readonly account: Schema.optionalKey<Schema.String>;
1416
+ }>, {}>;
1417
+ /**
1418
+ * One installation of the app.
1419
+ *
1420
+ * @public
1421
+ */
1422
+ declare class Installation extends Installation_base {}
1423
+ /**
1424
+ * Transport settings for the app's own API calls.
1425
+ *
1426
+ * @public
1427
+ */
1428
+ interface GitHubAppOptions {
1429
+ /** A GitHub Enterprise API root. */
1430
+ readonly baseUrl?: string | undefined;
1431
+ /** Appended to octokit's user agent. */
1432
+ readonly userAgent?: string | undefined;
1433
+ /** Retry behavior for the app's own calls. */
1434
+ readonly retry?: RetryPolicy | "off" | undefined;
1435
+ /** A replacement `fetch`, for tests and proxies. */
1436
+ readonly fetch?: typeof globalThis.fetch | undefined;
1437
+ }
1438
+ declare const GitHubApp_base: Context.ServiceClass<GitHubApp, "@effected/github/GitHubApp", GitHubAppShape>;
1439
+ /**
1440
+ * GitHub App authentication: mint, revoke and identify.
1441
+ *
1442
+ * @remarks
1443
+ * **This is the only module in the package that imports a JWT signer**, which is
1444
+ * what makes the tree-shaking invariant structural rather than aspirational: a
1445
+ * consumer that authenticates with a token it already holds imports
1446
+ * `GitHubClient` and never reaches this module or its dependency.
1447
+ *
1448
+ * That constraint is also why the App-authenticated **client** layer lives here
1449
+ * as {@link GitHubApp.clientLayer} rather than as a third static on
1450
+ * `GitHubClient`: statics on one class share one module, and putting it there
1451
+ * would make every token-only consumer link the signer. The kit has this shape
1452
+ * already — `@effected/workspaces` ships `localExecLayer`, which builds
1453
+ * `@effected/commands`' service, for the same reason.
1454
+ *
1455
+ * The JWT signer is `universal-github-app-jwt` — zero dependencies, and
1456
+ * `@octokit/auth-app`'s own JWT dependency. Taking it directly rather than
1457
+ * taking `auth-app` leaves behind roughly half a megabyte of OAuth app, user and
1458
+ * device-flow machinery that this package never calls.
1459
+ *
1460
+ * @public
1461
+ */
1462
+ declare class GitHubApp extends GitHubApp_base {
1463
+ /** The default transport. Bind it once; layers are memoized by reference. */
1464
+ static readonly layer: Layer.Layer<GitHubApp>;
1465
+ /**
1466
+ * A transport with custom settings.
1467
+ *
1468
+ * @remarks
1469
+ * Parameterized, so **bind the result to a `const`** and reuse it. Calling
1470
+ * this at two provide sites builds two instances, because layers are
1471
+ * memoized by reference.
1472
+ */
1473
+ static readonly layerWith: (options: GitHubAppOptions) => Layer.Layer<GitHubApp>;
1474
+ /**
1475
+ * A {@link GitHubClient} authenticated as an app installation.
1476
+ *
1477
+ * @remarks
1478
+ * The token's lifetime is the layer's scope: it is minted on build and
1479
+ * **revoked on release**, best-effort, so a workflow does not leave live
1480
+ * credentials behind. It is also **re-minted automatically** a minute before
1481
+ * it expires, which the package this replaces did not do — it persisted
1482
+ * `expiresAt` and read it nowhere, so a `main` phase outliving the hour
1483
+ * started answering 401 with nothing explaining why.
1484
+ *
1485
+ * A failure to obtain credentials surfaces to the caller as a
1486
+ * `GitHubError { kind: "unauthorized" }` carrying the `GitHubAppError` as its
1487
+ * cause: from a request's point of view, "could not authenticate" is an
1488
+ * authorization failure, and widening every method's error channel to say so
1489
+ * would tax every caller for a case only this layer can produce.
1490
+ */
1491
+ static readonly clientLayer: (request: TokenRequest, options?: GitHubAppOptions) => Layer.Layer<GitHubClient, GitHubAppError>;
1492
+ /** An in-memory double; unstubbed members die naming themselves. */
1493
+ static readonly makeTest: (overrides?: Partial<GitHubAppShape>) => GitHubAppShape;
1494
+ /** {@link GitHubApp.makeTest} behind a `Layer`. */
1495
+ static readonly layerTest: (overrides?: Partial<GitHubAppShape>) => Layer.Layer<GitHubApp>;
1496
+ }
1497
+ /**
1498
+ * The app-authentication surface.
1499
+ *
1500
+ * @remarks
1501
+ * Every member is a function returning an `Effect`, so a partial double stays
1502
+ * partial. `installations` takes credentials rather than being an
1503
+ * `Effect`-valued property because the credentials are per-call, not per-layer.
1504
+ *
1505
+ * @public
1506
+ */
1507
+ interface GitHubAppShape {
1508
+ /**
1509
+ * Mint an installation token.
1510
+ *
1511
+ * @remarks
1512
+ * Used by `@effected/github-actions`' token bridge in a workflow's `pre`
1513
+ * phase. Touches: nothing else on this shape.
1514
+ */
1515
+ readonly token: (request: TokenRequest) => Effect.Effect<InstallationToken, GitHubAppError>;
1516
+ /**
1517
+ * Mint a token that is revoked when the scope closes.
1518
+ *
1519
+ * @remarks
1520
+ * Touches: `token`, `revoke`.
1521
+ */
1522
+ readonly scopedToken: (request: TokenRequest) => Effect.Effect<InstallationToken, GitHubAppError, Scope.Scope>;
1523
+ /**
1524
+ * Revoke a token now.
1525
+ *
1526
+ * @remarks
1527
+ * Used by the token bridge's `post` phase. Touches: nothing else.
1528
+ */
1529
+ readonly revoke: (token: Redacted.Redacted<string>) => Effect.Effect<void, GitHubAppError>;
1530
+ /**
1531
+ * Resolve the app's slug, name and bot user id.
1532
+ *
1533
+ * @remarks
1534
+ * Supply `installationToken` when you have one: `GET /users/{slug}[bot]`
1535
+ * rejects an app JWT, so without it the lookup runs unauthenticated at
1536
+ * GitHub's 60-requests-per-hour-per-IP limit. Touches: nothing else.
1537
+ */
1538
+ readonly identity: (request: AppCredentials & {
1539
+ readonly installationToken?: Redacted.Redacted<string> | undefined;
1540
+ }) => Effect.Effect<AppIdentity, GitHubAppError>;
1541
+ /**
1542
+ * Every installation of the app.
1543
+ *
1544
+ * @remarks
1545
+ * Touches: nothing else.
1546
+ */
1547
+ readonly installations: (credentials: AppCredentials) => Effect.Effect<ReadonlyArray<Installation>, GitHubAppError>;
1548
+ }
1549
+ //#endregion
1550
+ //#region src/GitHubCommit.d.ts
1551
+ declare const CommitSummary_base: Schema.Class<CommitSummary, Schema.Struct<{
1552
+ /** The commit sha. */
1553
+ readonly sha: Schema.String;
1554
+ /** The full commit message, untrimmed — this package does not decide what "the message" means. */
1555
+ readonly message: Schema.String;
1556
+ /** The author's name as git recorded it, or `"Unknown"` when GitHub reports none. */
1557
+ readonly author: Schema.String;
1558
+ /** The GitHub login of the authoring account, when GitHub could attribute one. */
1559
+ readonly authorLogin: Schema.optionalKey<Schema.String>;
1560
+ /** The web URL for the commit. */
1561
+ readonly url: Schema.String;
1562
+ }>, {}>;
1563
+ /**
1564
+ * A commit, projected to what callers read.
1565
+ *
1566
+ * @public
1567
+ */
1568
+ declare class CommitSummary extends CommitSummary_base {
1569
+ /** The message's first line. */
1570
+ get subject(): string;
1571
+ }
1572
+ /**
1573
+ * How a file changed in a commit or a comparison.
1574
+ *
1575
+ * @public
1576
+ */
1577
+ declare const FileStatus: Schema.Literals<readonly ["added", "removed", "modified", "renamed", "copied", "changed", "unchanged"]>;
1578
+ declare const CommitFile_base: Schema.Class<CommitFile, Schema.Struct<{
1579
+ /** Repository-relative path, after any rename. */
1580
+ readonly path: Schema.String;
1581
+ /** What happened to it. */
1582
+ readonly status: Schema.Literals<readonly ["added", "removed", "modified", "renamed", "copied", "changed", "unchanged"]>;
1583
+ /** Lines added. */
1584
+ readonly additions: Schema.Int;
1585
+ /** Lines removed. */
1586
+ readonly deletions: Schema.Int;
1587
+ /** The path before a rename or copy. */
1588
+ readonly previousPath: Schema.optionalKey<Schema.String>;
1589
+ }>, {}>;
1590
+ /**
1591
+ * One changed file.
1592
+ *
1593
+ * @public
1594
+ */
1595
+ declare class CommitFile extends CommitFile_base {}
1596
+ declare const CommitComparison_base: Schema.Class<CommitComparison, Schema.Struct<{
1597
+ /** How head relates to base. */
1598
+ readonly status: Schema.Literals<readonly ["diverged", "ahead", "behind", "identical"]>;
1599
+ /** Commits head has that base does not. */
1600
+ readonly aheadBy: Schema.Int;
1601
+ /** Commits base has that head does not. */
1602
+ readonly behindBy: Schema.Int;
1603
+ /** The commits in the range. */
1604
+ readonly commits: Schema.$Array<typeof CommitSummary>;
1605
+ /** The files that differ, subject to GitHub's own 300-file cap on this endpoint. */
1606
+ readonly files: Schema.$Array<typeof CommitFile>;
1607
+ }>, {}>;
1608
+ /**
1609
+ * The result of comparing two refs.
1610
+ *
1611
+ * @public
1612
+ */
1613
+ declare class CommitComparison extends CommitComparison_base {}
1614
+ /**
1615
+ * Reading commits.
1616
+ *
1617
+ * @public
1618
+ */
1619
+ interface GitHubCommitShape {
1620
+ /** One commit. */
1621
+ readonly get: (ref: string) => Effect.Effect<CommitSummary, GitHubError, Repo>;
1622
+ /** Commits on a ref, newest first. */
1623
+ readonly list: (options?: {
1624
+ readonly ref?: string | undefined;
1625
+ readonly path?: string | undefined;
1626
+ readonly page?: PageOptions | undefined;
1627
+ }) => Effect.Effect<ReadonlyArray<CommitSummary>, GitHubError, Repo>;
1628
+ /**
1629
+ * Compare two refs.
1630
+ *
1631
+ * @remarks
1632
+ * GitHub paginates this **by commit**, while the single-commit read paginates
1633
+ * **by file** at 300 per page — so a one-commit comparison is permanently
1634
+ * truncated at 300 files no matter what you pass. That is GitHub's constraint,
1635
+ * recorded here rather than discovered later.
1636
+ */
1637
+ readonly compare: (base: string, head: string) => Effect.Effect<CommitComparison, GitHubError, Repo>;
1638
+ /** The files one commit touched, paginated by file. */
1639
+ readonly changedFiles: (ref: string, options?: {
1640
+ readonly page?: PageOptions | undefined;
1641
+ }) => Effect.Effect<ReadonlyArray<CommitFile>, GitHubError, Repo>;
1642
+ }
1643
+ declare const GitHubCommit_base: Context.ServiceClass<GitHubCommit, "@effected/github/GitHubCommit", GitHubCommitShape>;
1644
+ /**
1645
+ * Commits, as GitHub reports them.
1646
+ *
1647
+ * @public
1648
+ */
1649
+ declare class GitHubCommit extends GitHubCommit_base {
1650
+ static readonly layer: Layer.Layer<GitHubCommit, never, GitHubClient>;
1651
+ /** An in-memory double; unstubbed members die naming themselves. */
1652
+ static readonly makeTest: (overrides?: Partial<GitHubCommitShape>) => GitHubCommitShape;
1653
+ /** {@link GitHubCommit.makeTest} behind a `Layer`. */
1654
+ static readonly layerTest: (overrides?: Partial<GitHubCommitShape>) => Layer.Layer<GitHubCommit>;
1655
+ }
1656
+ //#endregion
1657
+ //#region src/GitHubContent.d.ts
1658
+ /**
1659
+ * Reading a file out of a repository.
1660
+ *
1661
+ * @public
1662
+ */
1663
+ interface GitHubContentShape {
1664
+ /**
1665
+ * A text file's contents at `ref`, or the default branch when `ref` is
1666
+ * omitted.
1667
+ */
1668
+ readonly getFile: (path: string, options?: {
1669
+ readonly ref?: string | undefined;
1670
+ }) => Effect.Effect<string, GitHubError, Repo>;
1671
+ /** As {@link GitHubContentShape.getFile}, with absence as `Option.none`. */
1672
+ readonly getFileOption: (path: string, options?: {
1673
+ readonly ref?: string | undefined;
1674
+ }) => Effect.Effect<Option.Option<string>, GitHubError, Repo>;
1675
+ }
1676
+ declare const GitHubContent_base: Context.ServiceClass<GitHubContent, "@effected/github/GitHubContent", GitHubContentShape>;
1677
+ /**
1678
+ * Repository file contents.
1679
+ *
1680
+ * @public
1681
+ */
1682
+ declare class GitHubContent extends GitHubContent_base {
1683
+ static readonly layer: Layer.Layer<GitHubContent, never, GitHubClient>;
1684
+ /** An in-memory double; unstubbed members die naming themselves. */
1685
+ static readonly makeTest: (overrides?: Partial<GitHubContentShape>) => GitHubContentShape;
1686
+ /** {@link GitHubContent.makeTest} behind a `Layer`. */
1687
+ static readonly layerTest: (overrides?: Partial<GitHubContentShape>) => Layer.Layer<GitHubContent>;
1688
+ }
1689
+ //#endregion
1690
+ //#region src/GitHubIssue.d.ts
1691
+ declare const IssueInfo_base: Schema.Class<IssueInfo, Schema.Struct<{
1692
+ readonly number: Schema.Int;
1693
+ readonly title: Schema.String;
1694
+ readonly state: Schema.Literals<readonly ["open", "closed"]>;
1695
+ /** Label names, normalized from GitHub's `string | { name }` union. */
1696
+ readonly labels: Schema.$Array<Schema.String>;
1697
+ readonly url: Schema.String;
1698
+ /** The GraphQL node id. */
1699
+ readonly nodeId: Schema.String;
1700
+ }>, {}>;
1701
+ /**
1702
+ * An issue, projected to what callers read.
1703
+ *
1704
+ * @public
1705
+ */
1706
+ declare class IssueInfo extends IssueInfo_base {}
1707
+ declare const LinkedIssue_base: Schema.Class<LinkedIssue, Schema.Struct<{
1708
+ readonly number: Schema.Int;
1709
+ readonly title: Schema.String;
1710
+ readonly state: Schema.String;
1711
+ readonly url: Schema.String;
1712
+ readonly nodeId: Schema.String;
1713
+ /**
1714
+ * Whether a human wrote the link, rather than GitHub inferring it from the
1715
+ * branch or commit messages.
1716
+ *
1717
+ * @remarks
1718
+ * This is the field the whole document exists for. The version this replaces
1719
+ * could not express `userLinkedOnly`, so one consumer re-declared the query
1720
+ * with the field aliased twice to get it — the single largest duplicated
1721
+ * document in the survey.
1722
+ */
1723
+ readonly userLinked: Schema.Boolean;
1724
+ }>, {}>;
1725
+ /**
1726
+ * An issue a pull request closes.
1727
+ *
1728
+ * @public
1729
+ */
1730
+ declare class LinkedIssue extends LinkedIssue_base {}
1731
+ /**
1732
+ * Issues.
1733
+ *
1734
+ * @public
1735
+ */
1736
+ interface GitHubIssueShape {
1737
+ readonly get: (number: number) => Effect.Effect<IssueInfo, GitHubError, Repo>;
1738
+ readonly list: (options?: {
1739
+ readonly state?: "open" | "closed" | "all" | undefined;
1740
+ readonly labels?: ReadonlyArray<string> | undefined;
1741
+ readonly page?: PageOptions | undefined;
1742
+ }) => Effect.Effect<ReadonlyArray<IssueInfo>, GitHubError, Repo>;
1743
+ readonly close: (number: number, reason?: "completed" | "not_planned") => Effect.Effect<void, GitHubError, Repo>;
1744
+ /** Post a comment. */
1745
+ readonly comment: (number: number, body: string) => Effect.Effect<number, GitHubError, Repo>;
1746
+ /** The issues a pull request closes, with `userLinked` telling you who linked them. */
1747
+ readonly linkedIssues: (prNumber: number) => Effect.Effect<ReadonlyArray<LinkedIssue>, GitHubGraphQLError, Repo>;
1748
+ /**
1749
+ * Has `prNumber` already been cross-referenced on this issue?
1750
+ *
1751
+ * @remarks
1752
+ * The idempotence guard one consumer wrote a bespoke timeline query for,
1753
+ * so that re-running a workflow does not comment twice.
1754
+ */
1755
+ readonly isCrossReferencedBy: (issueNumber: number, prNumber: number) => Effect.Effect<boolean, GitHubGraphQLError, Repo>;
1756
+ }
1757
+ declare const GitHubIssue_base: Context.ServiceClass<GitHubIssue, "@effected/github/GitHubIssue", GitHubIssueShape>;
1758
+ /**
1759
+ * Issues.
1760
+ *
1761
+ * @public
1762
+ */
1763
+ declare class GitHubIssue extends GitHubIssue_base {
1764
+ static readonly layer: Layer.Layer<GitHubIssue, never, GitHubClient>;
1765
+ /** An in-memory double; unstubbed members die naming themselves. */
1766
+ static readonly makeTest: (overrides?: Partial<GitHubIssueShape>) => GitHubIssueShape;
1767
+ /** {@link GitHubIssue.makeTest} behind a `Layer`. */
1768
+ static readonly layerTest: (overrides?: Partial<GitHubIssueShape>) => Layer.Layer<GitHubIssue>;
1769
+ }
1770
+ //#endregion
1771
+ //#region src/GitHubRelease.d.ts
1772
+ declare const ReleaseInfo_base: Schema.Class<ReleaseInfo, Schema.Struct<{
1773
+ readonly id: Schema.Int;
1774
+ readonly tag: Schema.String;
1775
+ readonly name: Schema.String;
1776
+ readonly body: Schema.String;
1777
+ readonly draft: Schema.Boolean;
1778
+ readonly prerelease: Schema.Boolean;
1779
+ /** The web URL. */
1780
+ readonly url: Schema.String;
1781
+ /** The templated upload endpoint GitHub hands back for assets. */
1782
+ readonly uploadUrl: Schema.String;
1783
+ }>, {}>;
1784
+ /**
1785
+ * A release.
1786
+ *
1787
+ * @public
1788
+ */
1789
+ declare class ReleaseInfo extends ReleaseInfo_base {}
1790
+ declare const ReleaseAsset_base: Schema.Class<ReleaseAsset, Schema.Struct<{
1791
+ readonly id: Schema.Int;
1792
+ readonly name: Schema.String;
1793
+ /** The browser download URL. */
1794
+ readonly url: Schema.String;
1795
+ /** Size in bytes. */
1796
+ readonly size: Schema.Int;
1797
+ }>, {}>;
1798
+ /**
1799
+ * A file attached to a release.
1800
+ *
1801
+ * @public
1802
+ */
1803
+ declare class ReleaseAsset extends ReleaseAsset_base {}
1804
+ /**
1805
+ * Releases and their assets.
1806
+ *
1807
+ * @public
1808
+ */
1809
+ interface GitHubReleaseShape {
1810
+ readonly create: (input: {
1811
+ readonly tag: string;
1812
+ readonly name?: string | undefined;
1813
+ readonly body?: string | undefined;
1814
+ readonly draft?: boolean | undefined;
1815
+ readonly prerelease?: boolean | undefined;
1816
+ readonly generateReleaseNotes?: boolean | undefined;
1817
+ }) => Effect.Effect<ReleaseInfo, GitHubError, Repo>;
1818
+ readonly getByTag: (tag: string) => Effect.Effect<ReleaseInfo, GitHubError, Repo>;
1819
+ /** As {@link GitHubReleaseShape.getByTag}, with absence as `Option.none`. */
1820
+ readonly getByTagOption: (tag: string) => Effect.Effect<Option.Option<ReleaseInfo>, GitHubError, Repo>;
1821
+ readonly list: (options?: {
1822
+ readonly page?: PageOptions | undefined;
1823
+ }) => Effect.Effect<ReadonlyArray<ReleaseInfo>, GitHubError, Repo>;
1824
+ readonly update: (id: number, patch: {
1825
+ readonly name?: string | undefined;
1826
+ readonly body?: string | undefined;
1827
+ readonly draft?: boolean | undefined;
1828
+ readonly prerelease?: boolean | undefined;
1829
+ }) => Effect.Effect<ReleaseInfo, GitHubError, Repo>;
1830
+ /**
1831
+ * Attach a file to a release.
1832
+ *
1833
+ * @remarks
1834
+ * The one route in this package that is **not** in GitHub's generated
1835
+ * endpoint map: asset upload goes to `uploads.github.com` with a raw binary
1836
+ * body, and the map omits it. So it goes through `requestDecoded` with an
1837
+ * owned schema — the escape hatch is from the route table, never from typing.
1838
+ */
1839
+ readonly uploadAsset: (release: ReleaseInfo, asset: {
1840
+ readonly name: string;
1841
+ readonly data: Uint8Array | string;
1842
+ readonly contentType: string;
1843
+ }) => Effect.Effect<ReleaseAsset, GitHubError, Repo>;
1844
+ readonly listAssets: (id: number, options?: {
1845
+ readonly page?: PageOptions | undefined;
1846
+ }) => Effect.Effect<ReadonlyArray<ReleaseAsset>, GitHubError, Repo>;
1847
+ }
1848
+ declare const GitHubRelease_base: Context.ServiceClass<GitHubRelease, "@effected/github/GitHubRelease", GitHubReleaseShape>;
1849
+ /**
1850
+ * Releases.
1851
+ *
1852
+ * @public
1853
+ */
1854
+ declare class GitHubRelease extends GitHubRelease_base {
1855
+ static readonly layer: Layer.Layer<GitHubRelease, never, GitHubClient>;
1856
+ /** An in-memory double; unstubbed members die naming themselves. */
1857
+ static readonly makeTest: (overrides?: Partial<GitHubReleaseShape>) => GitHubReleaseShape;
1858
+ /** {@link GitHubRelease.makeTest} behind a `Layer`. */
1859
+ static readonly layerTest: (overrides?: Partial<GitHubReleaseShape>) => Layer.Layer<GitHubRelease>;
1860
+ }
1861
+ //#endregion
1862
+ //#region src/GitHubRepository.d.ts
1863
+ /**
1864
+ * Everything GitHub reports about a repository.
1865
+ *
1866
+ * @remarks
1867
+ * The **generated** response type, not a hand-written projection. One surveyed
1868
+ * consumer declared a sixteen-field interface for this endpoint and round-tripped
1869
+ * those fields back through `PATCH` — and every one of the sixteen already
1870
+ * existed, verbatim, in the OpenAPI types the package now leans on. Re-declaring
1871
+ * them would have been the same mistake with our name on it.
1872
+ *
1873
+ * @public
1874
+ */
1875
+ type RepositorySettings = Data<"GET /repos/{owner}/{repo}">;
1876
+ /**
1877
+ * The fields `PATCH /repos/{owner}/{repo}` accepts, minus the coordinate.
1878
+ *
1879
+ * @public
1880
+ */
1881
+ type RepositoryPatch = Omit<Params<"PATCH /repos/{owner}/{repo}">, "owner" | "repo">;
1882
+ /**
1883
+ * The repository itself.
1884
+ *
1885
+ * @public
1886
+ */
1887
+ interface GitHubRepositoryShape {
1888
+ /** The full, faithfully typed repository payload. */
1889
+ readonly settings: Effect.Effect<RepositorySettings, GitHubError, Repo>;
1890
+ /** Apply a settings patch and return what GitHub then reports. */
1891
+ readonly updateSettings: (patch: RepositoryPatch) => Effect.Effect<RepositorySettings, GitHubError, Repo>;
1892
+ /**
1893
+ * The default branch's name.
1894
+ *
1895
+ * @remarks
1896
+ * One surveyed consumer spent eight lines of hand-written octokit interface
1897
+ * plus eleven lines of code to read this one string.
1898
+ */
1899
+ readonly defaultBranch: Effect.Effect<string, GitHubError, Repo>;
1900
+ /**
1901
+ * The repository's GraphQL node id.
1902
+ *
1903
+ * @remarks
1904
+ * Needed as `repositoryId` by the `createLinkedBranch` and `createPullRequest`
1905
+ * mutations, which is why a second consumer cast `repos.get` for it alone.
1906
+ */
1907
+ readonly nodeId: Effect.Effect<string, GitHubError, Repo>;
1908
+ }
1909
+ declare const GitHubRepository_base: Context.ServiceClass<GitHubRepository, "@effected/github/GitHubRepository", GitHubRepositoryShape>;
1910
+ /**
1911
+ * Repository settings and coordinates.
1912
+ *
1913
+ * @public
1914
+ */
1915
+ declare class GitHubRepository extends GitHubRepository_base {
1916
+ static readonly layer: Layer.Layer<GitHubRepository, never, GitHubClient>;
1917
+ /** An in-memory double; unstubbed members die naming themselves. */
1918
+ static readonly makeTest: (overrides?: Partial<GitHubRepositoryShape>) => GitHubRepositoryShape;
1919
+ /** {@link GitHubRepository.makeTest} behind a `Layer`. */
1920
+ static readonly layerTest: (overrides?: Partial<GitHubRepositoryShape>) => Layer.Layer<GitHubRepository>;
1921
+ }
1922
+ //#endregion
1923
+ //#region src/GitTag.d.ts
1924
+ declare const TagRef_base: Schema.Class<TagRef, Schema.Struct<{
1925
+ /** The tag name, without `refs/tags/`. */
1926
+ readonly tag: Schema.NonEmptyString;
1927
+ /** The **commit** sha, with annotated tags already dereferenced. */
1928
+ readonly sha: Schema.String;
1929
+ }>, {}>;
1930
+ /**
1931
+ * A tag and the commit it ultimately points at.
1932
+ *
1933
+ * @public
1934
+ */
1935
+ declare class TagRef extends TagRef_base {}
1936
+ declare const SemverTag_base: Schema.Class<SemverTag, Schema.Struct<{
1937
+ /** The tag name as GitHub has it. */
1938
+ readonly tag: Schema.NonEmptyString;
1939
+ /** The commit sha. */
1940
+ readonly sha: Schema.String;
1941
+ /** The version read out of the name. */
1942
+ readonly version: typeof SemVer;
1943
+ }>, {}>;
1944
+ /**
1945
+ * A tag whose name carries a version.
1946
+ *
1947
+ * @public
1948
+ */
1949
+ declare class SemverTag extends SemverTag_base {}
1950
+ /**
1951
+ * Read a version out of a tag name.
1952
+ *
1953
+ * @remarks
1954
+ * The default covers the three shapes `@effected/workspaces`' `ReleaseTag`
1955
+ * produces and the surveyed repos actually cut: `v1.2.3`, `pkg@v1.2.3` and
1956
+ * `@scope/pkg@1.2.3`. Taking the substring after the **last** `@` is what makes
1957
+ * the scoped form work, since the scope itself contains one.
1958
+ *
1959
+ * @public
1960
+ */
1961
+ type VersionFromTag = (tag: string) => Option.Option<string>;
1962
+ /** The default {@link VersionFromTag}. @public */
1963
+ declare const versionFromTag: VersionFromTag;
1964
+ /**
1965
+ * How to pick the newest version-shaped tag.
1966
+ *
1967
+ * @public
1968
+ */
1969
+ interface LatestSemverOptions {
1970
+ /** Only consider tags starting with this. */
1971
+ readonly prefix?: string | undefined;
1972
+ /** Consider prereleases too. Off by default: `1.0.0-rc.1` is not the latest release. */
1973
+ readonly includePrerelease?: boolean | undefined;
1974
+ /** Override the tag-name → version convention. */
1975
+ readonly extract?: VersionFromTag | undefined;
1976
+ /** How far to walk. */
1977
+ readonly page?: PageOptions | undefined;
1978
+ }
1979
+ /**
1980
+ * Tag refs in GitHub's Git Database API.
1981
+ *
1982
+ * @public
1983
+ */
1984
+ interface GitTagShape {
1985
+ /** Create a tag ref at `sha`. Fails `alreadyExists` when it is already there. */
1986
+ readonly create: (tag: string, sha: string) => Effect.Effect<void, GitHubError, Repo>;
1987
+ /** Point `tag` at `sha`, creating it if needed. */
1988
+ readonly upsert: (tag: string, sha: string) => Effect.Effect<void, GitHubError, Repo>;
1989
+ /** Delete the tag ref. */
1990
+ readonly delete: (tag: string) => Effect.Effect<void, GitHubError, Repo>;
1991
+ /** Every tag, newest GitHub-order first. `prefix` filters client-side. */
1992
+ readonly list: (options?: {
1993
+ readonly prefix?: string | undefined;
1994
+ readonly page?: PageOptions | undefined;
1995
+ }) => Effect.Effect<ReadonlyArray<TagRef>, GitHubError, Repo>;
1996
+ /**
1997
+ * The commit a tag points at, dereferencing annotated tags.
1998
+ *
1999
+ * @remarks
2000
+ * Fails typed past five levels of nesting rather than looping.
2001
+ */
2002
+ readonly resolve: (tag: string) => Effect.Effect<string, GitHubError, Repo>;
2003
+ /**
2004
+ * The newest version-shaped tag.
2005
+ *
2006
+ * @remarks
2007
+ * Replaces thirty-five lines at one surveyed call site that ran **one
2008
+ * `Effect.result` per parse and another per comparison** to answer this. Both
2009
+ * are synchronous in `@effected/semver` (`parseResult`, `compare`), so this is
2010
+ * a single pass over the page stream with no round trips at all.
2011
+ */
2012
+ readonly latestSemver: (options?: LatestSemverOptions) => Effect.Effect<Option.Option<SemverTag>, GitHubError, Repo>;
2013
+ }
2014
+ declare const GitTag_base: Context.ServiceClass<GitTag, "@effected/github/GitTag", GitTagShape>;
2015
+ /**
2016
+ * Tags.
2017
+ *
2018
+ * @public
2019
+ */
2020
+ declare class GitTag extends GitTag_base {
2021
+ static readonly layer: Layer.Layer<GitTag, never, GitHubClient>;
2022
+ /** An in-memory double; unstubbed members die naming themselves. */
2023
+ static readonly makeTest: (overrides?: Partial<GitTagShape>) => GitTagShape;
2024
+ /** {@link GitTag.makeTest} behind a `Layer`. */
2025
+ static readonly layerTest: (overrides?: Partial<GitTagShape>) => Layer.Layer<GitTag>;
2026
+ }
2027
+ //#endregion
2028
+ //#region src/PullRequest.d.ts
2029
+ /** How a pull request is merged. @public */
2030
+ declare const MergeMethod: Schema.Literals<readonly ["merge", "squash", "rebase"]>;
2031
+ declare const PullRequestInfo_base: Schema.Class<PullRequestInfo, Schema.Struct<{
2032
+ /** The number in `#123`. */
2033
+ readonly number: Schema.Int;
2034
+ /** The GraphQL node id, which the auto-merge mutations need. */
2035
+ readonly nodeId: Schema.String;
2036
+ /** The web URL. */
2037
+ readonly url: Schema.String;
2038
+ readonly title: Schema.String;
2039
+ readonly state: Schema.Literals<readonly ["open", "closed"]>;
2040
+ /** The source branch name. */
2041
+ readonly head: Schema.String;
2042
+ /** The target branch name. */
2043
+ readonly base: Schema.String;
2044
+ readonly draft: Schema.Boolean;
2045
+ readonly merged: Schema.Boolean;
2046
+ /**
2047
+ * When it merged, if it did.
2048
+ *
2049
+ * @remarks
2050
+ * An `Option`, not an optional field. Whether a pull request has merged is a
2051
+ * fact GitHub always reports, so modelling it as "maybe absent" would be
2052
+ * modelling a gap in our fixtures rather than a gap in the domain.
2053
+ */
2054
+ readonly mergedAt: Schema.Option<Schema.DateTimeUtcFromString>;
2055
+ /** The description, when GitHub sent one. */
2056
+ readonly body: Schema.optionalKey<Schema.String>;
2057
+ /** The merge commit, once there is one. */
2058
+ readonly mergeCommitSha: Schema.optionalKey<Schema.String>;
2059
+ }>, {}>;
2060
+ /**
2061
+ * A pull request, projected to what callers read.
2062
+ *
2063
+ * @public
2064
+ */
2065
+ declare class PullRequestInfo extends PullRequestInfo_base {}
2066
+ /** What {@link PullRequestShape.upsert} did. @public */
2067
+ interface UpsertedPullRequest {
2068
+ readonly pullRequest: PullRequestInfo;
2069
+ readonly created: boolean;
2070
+ }
2071
+ /**
2072
+ * Pull requests.
2073
+ *
2074
+ * @public
2075
+ */
2076
+ interface PullRequestShape {
2077
+ readonly get: (number: number) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
2078
+ readonly list: (options?: {
2079
+ readonly head?: string | undefined;
2080
+ readonly base?: string | undefined;
2081
+ readonly state?: "open" | "closed" | "all" | undefined;
2082
+ readonly page?: PageOptions | undefined;
2083
+ }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError, Repo>;
2084
+ /** The files a pull request changes. */
2085
+ readonly listFiles: (number: number, options?: {
2086
+ readonly page?: PageOptions | undefined;
2087
+ }) => Effect.Effect<ReadonlyArray<string>, GitHubError, Repo>;
2088
+ /**
2089
+ * The pull requests associated with a commit.
2090
+ *
2091
+ * @remarks
2092
+ * Named for the question it answers, because the previous surface had this
2093
+ * method and one consumer never found it — dropping to a raw octokit callback
2094
+ * with the only `noExplicitAny` suppression in the entire survey. It also
2095
+ * paginates now, which the previous one did not.
2096
+ */
2097
+ readonly listAssociatedWithCommit: (sha: string, options?: {
2098
+ readonly page?: PageOptions | undefined;
2099
+ }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError, Repo>;
2100
+ readonly create: (input: {
2101
+ readonly title: string;
2102
+ readonly head: string;
2103
+ readonly base: string;
2104
+ readonly body?: string | undefined;
2105
+ readonly draft?: boolean | undefined;
2106
+ }) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
2107
+ readonly update: (number: number, patch: {
2108
+ readonly title?: string | undefined;
2109
+ readonly body?: string | undefined;
2110
+ readonly state?: "open" | "closed" | undefined;
2111
+ readonly base?: string | undefined;
2112
+ }) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
2113
+ /** Update the open pull request for `head`→`base`, or open one. */
2114
+ readonly upsert: (input: {
2115
+ readonly title: string;
2116
+ readonly head: string;
2117
+ readonly base: string;
2118
+ readonly body?: string | undefined;
2119
+ readonly draft?: boolean | undefined;
2120
+ }) => Effect.Effect<UpsertedPullRequest, GitHubError, Repo>;
2121
+ readonly merge: (number: number, options?: {
2122
+ readonly method?: "merge" | "squash" | "rebase" | undefined;
2123
+ readonly commitTitle?: string | undefined;
2124
+ readonly commitMessage?: string | undefined;
2125
+ }) => Effect.Effect<string, GitHubError, Repo>;
2126
+ readonly addLabels: (number: number, labels: ReadonlyArray<string>) => Effect.Effect<void, GitHubError, Repo>;
2127
+ readonly requestReviewers: (number: number, reviewers: {
2128
+ readonly users?: ReadonlyArray<string> | undefined;
2129
+ readonly teams?: ReadonlyArray<string> | undefined;
2130
+ }) => Effect.Effect<void, GitHubError, Repo>;
2131
+ /**
2132
+ * Turn auto-merge on or off.
2133
+ *
2134
+ * @remarks
2135
+ * An explicit call, not an option on `create`/`update`. The previous surface
2136
+ * fired these mutations from an `Effect.tap` **after** the create succeeded,
2137
+ * so a create that worked could still surface an auto-merge failure as if the
2138
+ * create had failed.
2139
+ */
2140
+ readonly setAutoMerge: (pullRequest: PullRequestInfo, method: "merge" | "squash" | "rebase" | "off") => Effect.Effect<void, GitHubGraphQLError, Repo>;
2141
+ }
2142
+ declare const PullRequest_base: Context.ServiceClass<PullRequest, "@effected/github/PullRequest", PullRequestShape>;
2143
+ /**
2144
+ * Pull requests.
2145
+ *
2146
+ * @public
2147
+ */
2148
+ declare class PullRequest extends PullRequest_base {
2149
+ static readonly layer: Layer.Layer<PullRequest, never, GitHubClient>;
2150
+ /** An in-memory double; unstubbed members die naming themselves. */
2151
+ static readonly makeTest: (overrides?: Partial<PullRequestShape>) => PullRequestShape;
2152
+ /** {@link PullRequest.makeTest} behind a `Layer`. */
2153
+ static readonly layerTest: (overrides?: Partial<PullRequestShape>) => Layer.Layer<PullRequest>;
2154
+ }
2155
+ //#endregion
2156
+ //#region src/PullRequestComment.d.ts
2157
+ declare const CommentMarker_base: Schema.Class<CommentMarker, Schema.Struct<{
2158
+ /** Whose comments these are, e.g. your action's name. */
2159
+ readonly namespace: Schema.NonEmptyString;
2160
+ /** Which comment, within that namespace. */
2161
+ readonly key: Schema.NonEmptyString;
2162
+ }>, {}>;
2163
+ /**
2164
+ * The hidden marker that makes a comment findable again.
2165
+ *
2166
+ * @remarks
2167
+ * A pure class, not a hardcoded string. The surface this replaces baked
2168
+ * `<!-- savvy-web:${key} -->` into the library — one vendor's name, inside a
2169
+ * package meant to be general. Here the namespace is the caller's, the marker is
2170
+ * testable without a client, and the library has no opinion about whose comments
2171
+ * these are.
2172
+ *
2173
+ * @public
2174
+ */
2175
+ declare class CommentMarker extends CommentMarker_base {
2176
+ /** The HTML comment appended to a body so the comment can be found again. */
2177
+ get html(): string;
2178
+ /** Does this body carry the marker? */
2179
+ matches(body: string): boolean;
2180
+ }
2181
+ declare const CommentRecord_base: Schema.Class<CommentRecord, Schema.Struct<{
2182
+ readonly id: Schema.Int;
2183
+ readonly body: Schema.String;
2184
+ readonly url: Schema.String;
2185
+ }>, {}>;
2186
+ /**
2187
+ * A comment this package wrote or found.
2188
+ *
2189
+ * @public
2190
+ */
2191
+ declare class CommentRecord extends CommentRecord_base {}
2192
+ /**
2193
+ * Sticky comments on a pull request or issue.
2194
+ *
2195
+ * @public
2196
+ */
2197
+ interface PullRequestCommentShape {
2198
+ /** Post a new comment. */
2199
+ readonly create: (issueNumber: number, body: string) => Effect.Effect<CommentRecord, GitHubError, Repo>;
2200
+ /**
2201
+ * Update the marked comment if there is one, or post it.
2202
+ *
2203
+ * @remarks
2204
+ * The marker is appended to the body, so a comment written by `upsert` is
2205
+ * always findable by the same marker afterwards.
2206
+ */
2207
+ readonly upsert: (issueNumber: number, marker: CommentMarker, body: string) => Effect.Effect<CommentRecord, GitHubError, Repo>;
2208
+ /**
2209
+ * Find the marked comment.
2210
+ *
2211
+ * @remarks
2212
+ * **Paginates.** The version this replaces requested a single page of 100 and
2213
+ * stopped, so on a busy pull request the marker silently vanished and every
2214
+ * update posted a new comment instead.
2215
+ */
2216
+ readonly find: (issueNumber: number, marker: CommentMarker, options?: {
2217
+ readonly page?: PageOptions | undefined;
2218
+ }) => Effect.Effect<Option.Option<CommentRecord>, GitHubError, Repo>;
2219
+ readonly delete: (commentId: number) => Effect.Effect<void, GitHubError, Repo>;
2220
+ }
2221
+ declare const PullRequestComment_base: Context.ServiceClass<PullRequestComment, "@effected/github/PullRequestComment", PullRequestCommentShape>;
2222
+ /**
2223
+ * Sticky comments.
2224
+ *
2225
+ * @public
2226
+ */
2227
+ declare class PullRequestComment extends PullRequestComment_base {
2228
+ static readonly layer: Layer.Layer<PullRequestComment, never, GitHubClient>;
2229
+ /** An in-memory double; unstubbed members die naming themselves. */
2230
+ static readonly makeTest: (overrides?: Partial<PullRequestCommentShape>) => PullRequestCommentShape;
2231
+ /** {@link PullRequestComment.makeTest} behind a `Layer`. */
2232
+ static readonly layerTest: (overrides?: Partial<PullRequestCommentShape>) => Layer.Layer<PullRequestComment>;
2233
+ }
2234
+ //#endregion
2235
+ //#region src/TokenPermissions.d.ts
2236
+ /**
2237
+ * How much access a permission grants.
2238
+ *
2239
+ * @public
2240
+ */
2241
+ declare const PermissionLevel: Schema.Literals<readonly ["read", "write", "admin"]>;
2242
+ /** How much access a permission grants. @public */
2243
+ type PermissionLevel = (typeof PermissionLevel.literals)[number];
2244
+ declare const PermissionGap_base: Schema.Class<PermissionGap, Schema.Struct<{
2245
+ /** The permission's name, e.g. `"contents"`. */
2246
+ readonly permission: Schema.String;
2247
+ /** What was asked for. */
2248
+ readonly required: Schema.Literals<readonly ["read", "write", "admin"]>;
2249
+ /** What the token has, when it has any at all. */
2250
+ readonly granted: Schema.optionalKey<Schema.Literals<readonly ["read", "write", "admin"]>>;
2251
+ }>, {}>;
2252
+ /**
2253
+ * A permission the token does not have enough of.
2254
+ *
2255
+ * @public
2256
+ */
2257
+ declare class PermissionGap extends PermissionGap_base {}
2258
+ declare const ExtraPermission_base: Schema.Class<ExtraPermission, Schema.Struct<{
2259
+ readonly permission: Schema.String;
2260
+ readonly granted: Schema.Literals<readonly ["read", "write", "admin"]>;
2261
+ /** What was asked for, when anything was. */
2262
+ readonly required: Schema.optionalKey<Schema.Literals<readonly ["read", "write", "admin"]>>;
2263
+ }>, {}>;
2264
+ /**
2265
+ * A permission the token has and did not need.
2266
+ *
2267
+ * @public
2268
+ */
2269
+ declare class ExtraPermission extends ExtraPermission_base {}
2270
+ declare const PermissionResult_base: Schema.Class<PermissionResult, Schema.Struct<{
2271
+ /** Permissions that are missing or too weak. */
2272
+ readonly missing: Schema.$Array<typeof PermissionGap>;
2273
+ /** Permissions granted beyond what was asked for. */
2274
+ readonly extra: Schema.$Array<typeof ExtraPermission>;
2275
+ }>, {}>;
2276
+ /**
2277
+ * What comparing a token's permissions against a requirement found.
2278
+ *
2279
+ * @public
2280
+ */
2281
+ declare class PermissionResult extends PermissionResult_base {
2282
+ /** Nothing missing. */
2283
+ get satisfied(): boolean;
2284
+ /** Nothing missing and nothing spare. */
2285
+ get exact(): boolean;
2286
+ }
2287
+ declare const TokenPermissionError_base: Schema.Class<TokenPermissionError, Schema.TaggedStruct<"TokenPermissionError", {
2288
+ /** Which assertion failed. */
2289
+ readonly kind: Schema.Literals<readonly ["insufficient", "excess"]>;
2290
+ /** The comparison that produced it. */
2291
+ readonly result: typeof PermissionResult;
2292
+ }>, import("effect/Cause").YieldableError>;
2293
+ /**
2294
+ * A token asked for access it does not have, or has access it did not ask for.
2295
+ *
2296
+ * @public
2297
+ */
2298
+ declare class TokenPermissionError extends TokenPermissionError_base {
2299
+ get message(): string;
2300
+ }
2301
+ declare const TokenPermissions_base: Schema.Class<TokenPermissions, Schema.Struct<{
2302
+ /** Permission name to level. */
2303
+ readonly granted: Schema.$Record<Schema.String, Schema.Literals<readonly ["read", "write", "admin"]>>;
2304
+ }>, {}>;
2305
+ /**
2306
+ * The permissions a token was granted, and what they satisfy.
2307
+ *
2308
+ * @remarks
2309
+ * **A pure class, not a service.** The version this replaces was a
2310
+ * `Context.Service` whose live layer was a `Layer.succeed` with zero octokit
2311
+ * calls and an empty `R` — a `read < write < admin` comparator behind a service
2312
+ * boundary that bought nothing. It cost something, though: its test double
2313
+ * reimplemented the entire ranking and every assertion branch, making it the
2314
+ * heaviest of the thirty-eight doubles in the package.
2315
+ *
2316
+ * Here there is no service, no layer and no double: a caller holds the
2317
+ * permissions GitHub already gave it (`InstallationToken.permissions`) and
2318
+ * compares them. The only `Effect`s are the two assertions, and they exist only
2319
+ * because failing typed is more useful than returning a boolean.
2320
+ *
2321
+ * @example
2322
+ * ```ts
2323
+ * import { TokenPermissions } from "@effected/github";
2324
+ * import { Effect } from "effect";
2325
+ *
2326
+ * declare const permissions: Record<string, string>;
2327
+ *
2328
+ * const check = Effect.gen(function* () {
2329
+ * const granted = TokenPermissions.fromGitHub(permissions);
2330
+ * yield* granted.assertSufficient({ contents: "write", pull_requests: "write" });
2331
+ * });
2332
+ * ```
2333
+ *
2334
+ * @public
2335
+ */
2336
+ declare class TokenPermissions extends TokenPermissions_base {
2337
+ /**
2338
+ * Read GitHub's permission map, ignoring anything unrecognized.
2339
+ *
2340
+ * @remarks
2341
+ * GitHub adds permission levels over time; a token carrying one this package
2342
+ * does not know about is not a reason to fail a comparison about a different
2343
+ * permission entirely.
2344
+ */
2345
+ static fromGitHub(permissions: Readonly<Record<string, string>>): TokenPermissions;
2346
+ /** Compare against a requirement. Pure and total. */
2347
+ compare(required: Readonly<Record<string, PermissionLevel>>): PermissionResult;
2348
+ /** Fail unless every required permission is held at least at the level asked for. */
2349
+ assertSufficient(required: Readonly<Record<string, PermissionLevel>>): Effect.Effect<void, TokenPermissionError>;
2350
+ /**
2351
+ * Fail unless the token holds exactly what was asked for.
2352
+ *
2353
+ * @remarks
2354
+ * For the workflow that wants a least-privilege token and treats a broader
2355
+ * one as a misconfiguration worth stopping for.
2356
+ */
2357
+ assertExact(required: Readonly<Record<string, PermissionLevel>>): Effect.Effect<void, TokenPermissionError>;
2358
+ }
2359
+ //#endregion
2360
+ //#region src/WorkflowDispatch.d.ts
2361
+ declare const WorkflowRunStatus_base: Schema.Class<WorkflowRunStatus, Schema.Struct<{
2362
+ readonly id: Schema.Int;
2363
+ /** `queued`, `in_progress`, `completed`, … */
2364
+ readonly status: Schema.String;
2365
+ /** Set once `status` is `completed`. */
2366
+ readonly conclusion: Schema.optionalKey<Schema.String>;
2367
+ readonly url: Schema.String;
2368
+ }>, {}>;
2369
+ /**
2370
+ * Where a workflow run has got to.
2371
+ *
2372
+ * @public
2373
+ */
2374
+ declare class WorkflowRunStatus extends WorkflowRunStatus_base {
2375
+ /** Has the run finished, whatever the outcome? */
2376
+ get isDone(): boolean;
2377
+ }
2378
+ /**
2379
+ * How long to wait for a dispatched run.
2380
+ *
2381
+ * @public
2382
+ */
2383
+ interface PollOptions {
2384
+ /** How often to check. Defaults to ten seconds. */
2385
+ readonly interval?: Duration.Duration | undefined;
2386
+ /** How long to keep checking. Defaults to five minutes. */
2387
+ readonly timeout?: Duration.Duration | undefined;
2388
+ }
2389
+ /**
2390
+ * Triggering workflows.
2391
+ *
2392
+ * @public
2393
+ */
2394
+ interface WorkflowDispatchShape {
2395
+ /** Fire a `workflow_dispatch` event. GitHub answers 204 with no run id. */
2396
+ readonly dispatch: (workflow: string, ref: string, inputs?: Record<string, string>) => Effect.Effect<void, GitHubError, Repo>;
2397
+ readonly runStatus: (runId: number) => Effect.Effect<WorkflowRunStatus, GitHubError, Repo>;
2398
+ /**
2399
+ * Dispatch, find the run it created, and wait for it to finish.
2400
+ *
2401
+ * @remarks
2402
+ * The wait is `Effect.repeat` with a predicate over the **success** value.
2403
+ * The version this replaces encoded "not finished yet" as a sentinel *error*
2404
+ * baked into a user-visible error union — control flow in the error channel,
2405
+ * which every consumer then had to know not to treat as a failure.
2406
+ */
2407
+ readonly dispatchAndWait: (workflow: string, ref: string, options?: {
2408
+ readonly inputs?: Record<string, string> | undefined;
2409
+ readonly poll?: PollOptions | undefined;
2410
+ }) => Effect.Effect<WorkflowRunStatus, GitHubError, Repo>;
2411
+ }
2412
+ declare const WorkflowDispatch_base: Context.ServiceClass<WorkflowDispatch, "@effected/github/WorkflowDispatch", WorkflowDispatchShape>;
2413
+ /**
2414
+ * Workflow dispatch.
2415
+ *
2416
+ * @public
2417
+ */
2418
+ declare class WorkflowDispatch extends WorkflowDispatch_base {
2419
+ static readonly layer: Layer.Layer<WorkflowDispatch, never, GitHubClient>;
2420
+ /** An in-memory double; unstubbed members die naming themselves. */
2421
+ static readonly makeTest: (overrides?: Partial<WorkflowDispatchShape>) => WorkflowDispatchShape;
2422
+ /** {@link WorkflowDispatch.makeTest} behind a `Layer`. */
2423
+ static readonly layerTest: (overrides?: Partial<WorkflowDispatchShape>) => Layer.Layer<WorkflowDispatch>;
2424
+ }
2425
+ //#endregion
2426
+ export { Annotation, AnnotationLevel, type AppCredentials, AppIdentity, ArtifactMetadata, type ArtifactMetadataShape, Attestation, AttestationListEntry, AttestationRecord, type AttestationShape, BotIdentity, type BranchOutcome, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, type CheckRunShape, CommentMarker, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, type ConcludeCheckRun, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GitBranch, type GitBranchShape, GitCommit, type GitCommitShape, GitHubApp, GitHubAppError, type GitHubAppOptions, type GitHubAppShape, GitHubClient, type GitHubClientOptions, type GitHubClientShape, GitHubCommit, type GitHubCommitShape, GitHubContent, type GitHubContentShape, GitHubError, GitHubErrorKind, type GitHubFixtures, GitHubGraphQLError, GitHubIssue, type GitHubIssueShape, GitHubRelease, type GitHubReleaseShape, GitHubRepository, type GitHubRepositoryShape, GitTag, type GitTagShape, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, type LatestSemverOptions, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, type PollOptions, PullRequest, PullRequestComment, type PullRequestCommentShape, PullRequestInfo, type PullRequestShape, RateLimitSnapshot, ReleaseAsset, ReleaseInfo, Repo, RepoRef, type RepositoryPatch, type RepositorySettings, 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, RetryPolicy, type RetryableFailure, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, type TokenRequest, type UpsertedPullRequest, type VersionFromTag, WorkflowDispatch, type WorkflowDispatchShape, WorkflowRunStatus, versionFromTag };
2427
+ //# sourceMappingURL=index.d.ts.map