@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/ArtifactMetadata.js +62 -0
- package/Attestation.js +106 -0
- package/CheckRun.js +286 -0
- package/GitBranch.js +171 -0
- package/GitCommit.js +183 -0
- package/GitHubApp.js +363 -0
- package/GitHubClient.js +192 -0
- package/GitHubCommit.js +198 -0
- package/GitHubContent.js +54 -0
- package/GitHubError.js +254 -0
- package/GitHubIssue.js +216 -0
- package/GitHubRelease.js +188 -0
- package/GitHubRepository.js +59 -0
- package/GitTag.js +191 -0
- package/GraphQL.js +183 -0
- package/LICENSE +21 -0
- package/PullRequest.js +300 -0
- package/PullRequestComment.js +132 -0
- package/Repo.js +107 -0
- package/Resilience.js +146 -0
- package/Rest.js +47 -0
- package/TokenPermissions.js +188 -0
- package/WorkflowDispatch.js +124 -0
- package/index.d.ts +2427 -0
- package/index.js +24 -0
- package/internal/headers.js +52 -0
- package/internal/octokit.js +115 -0
- package/internal/paginate.js +54 -0
- package/package.json +53 -0
- package/tsdoc-metadata.json +11 -0
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
|