@theholocron/github-client 1.31.0 → 1.32.1
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/dist/index.d.mts +64 -19
- package/dist/index.mjs +121 -25
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "@theholocron/http-client";
|
|
2
2
|
import { ErrorSink, Logger } from "@theholocron/observability/core";
|
|
3
|
-
//#region src/utils.d.ts
|
|
3
|
+
//#region ../../../../../src/utils.d.ts
|
|
4
4
|
interface GitHubClientOptions {
|
|
5
5
|
token: string;
|
|
6
6
|
baseUrl?: string;
|
|
@@ -11,7 +11,7 @@ interface GitHubClientOptions {
|
|
|
11
11
|
errors?: ErrorSink;
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
|
-
//#region src/checks/checks.d.ts
|
|
14
|
+
//#region ../../../../../src/checks/checks.d.ts
|
|
15
15
|
type CheckRunStatus = "queued" | "in_progress" | "completed";
|
|
16
16
|
type CheckRunConclusion = "success" | "failure" | "neutral" | "cancelled" | "timed_out" | "action_required" | "skipped";
|
|
17
17
|
type CheckRunAnnotationLevel = "notice" | "warning" | "failure";
|
|
@@ -72,7 +72,7 @@ interface UpdateCheckRunInput {
|
|
|
72
72
|
details_url?: string;
|
|
73
73
|
}
|
|
74
74
|
//#endregion
|
|
75
|
-
//#region src/environments/environments.d.ts
|
|
75
|
+
//#region ../../../../../src/environments/environments.d.ts
|
|
76
76
|
interface GitHubEnvironment {
|
|
77
77
|
name: string;
|
|
78
78
|
wait_timer?: number;
|
|
@@ -88,7 +88,7 @@ interface GitHubEnvironment {
|
|
|
88
88
|
}>;
|
|
89
89
|
}
|
|
90
90
|
//#endregion
|
|
91
|
-
//#region src/git/git.d.ts
|
|
91
|
+
//#region ../../../../../src/git/git.d.ts
|
|
92
92
|
interface GitRef {
|
|
93
93
|
object: {
|
|
94
94
|
sha: string;
|
|
@@ -140,7 +140,7 @@ interface CreatePullInput {
|
|
|
140
140
|
body?: string;
|
|
141
141
|
}
|
|
142
142
|
//#endregion
|
|
143
|
-
//#region src/issues/issues.d.ts
|
|
143
|
+
//#region ../../../../../src/issues/issues.d.ts
|
|
144
144
|
interface GitHubIssue {
|
|
145
145
|
id: number;
|
|
146
146
|
number: number;
|
|
@@ -172,14 +172,14 @@ interface IssueSearchParams {
|
|
|
172
172
|
assignee?: string;
|
|
173
173
|
}
|
|
174
174
|
//#endregion
|
|
175
|
-
//#region src/labels/labels.d.ts
|
|
175
|
+
//#region ../../../../../src/labels/labels.d.ts
|
|
176
176
|
interface GitHubLabel {
|
|
177
177
|
name: string;
|
|
178
178
|
color: string;
|
|
179
179
|
description: string | null;
|
|
180
180
|
}
|
|
181
181
|
//#endregion
|
|
182
|
-
//#region src/pages/pages.d.ts
|
|
182
|
+
//#region ../../../../../src/pages/pages.d.ts
|
|
183
183
|
type PagesBuildType = "workflow" | "legacy";
|
|
184
184
|
type PagesBuildStatus = "built" | "building" | "errored" | "unknown";
|
|
185
185
|
interface GitHubPages {
|
|
@@ -210,7 +210,7 @@ interface UpdatePagesPayload {
|
|
|
210
210
|
https_enforced?: boolean;
|
|
211
211
|
}
|
|
212
212
|
//#endregion
|
|
213
|
-
//#region src/pulls/pulls.d.ts
|
|
213
|
+
//#region ../../../../../src/pulls/pulls.d.ts
|
|
214
214
|
interface GitHubPullRequest {
|
|
215
215
|
number: number;
|
|
216
216
|
title: string;
|
|
@@ -235,8 +235,50 @@ interface GitHubPullRequestFile {
|
|
|
235
235
|
/** Set only when `status === "renamed"`. */
|
|
236
236
|
previous_filename?: string;
|
|
237
237
|
}
|
|
238
|
+
/** One inline comment in a `POST /pulls/{pull_number}/reviews` request body. */
|
|
239
|
+
interface CreateReviewComment {
|
|
240
|
+
/** File path relative to the repo root. */
|
|
241
|
+
path: string;
|
|
242
|
+
/** 1-indexed line in the file's current (`RIGHT`) version — GitHub anchors a review comment to a line, not a column. */
|
|
243
|
+
line: number;
|
|
244
|
+
/** Almost always `"RIGHT"` (the PR's own new content) — `"LEFT"` targets the base/pre-PR version instead. */
|
|
245
|
+
side: "LEFT" | "RIGHT";
|
|
246
|
+
body: string;
|
|
247
|
+
}
|
|
248
|
+
interface CreateReviewInput {
|
|
249
|
+
/** The PR's head SHA the review attaches to. */
|
|
250
|
+
commit_id: string;
|
|
251
|
+
/** The review's own top-level summary, shown above its inline comments. */
|
|
252
|
+
body: string;
|
|
253
|
+
/**
|
|
254
|
+
* `"COMMENT"` never blocks a merge by itself — the right choice for an
|
|
255
|
+
* advisory bot review. `"REQUEST_CHANGES"`/`"APPROVE"` carry the same
|
|
256
|
+
* real weight as a human reviewer's own review state, affecting
|
|
257
|
+
* required-approval counts and dismissal.
|
|
258
|
+
*/
|
|
259
|
+
event: "COMMENT" | "REQUEST_CHANGES" | "APPROVE";
|
|
260
|
+
comments?: CreateReviewComment[];
|
|
261
|
+
}
|
|
262
|
+
/** `POST /pulls/{pull_number}/reviews`'s response — only the fields any known consumer needs. */
|
|
263
|
+
interface GitHubPullRequestReview {
|
|
264
|
+
id: number;
|
|
265
|
+
html_url: string;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* One review thread — GraphQL-only (`resolveReviewThread`, the mutation
|
|
269
|
+
* this exists to support, has no REST equivalent at all). `id` here is a
|
|
270
|
+
* GraphQL node ID (`PRRT_...`), not the same numeric ID space as REST's
|
|
271
|
+
* review-comment `id` — pass it straight through to `resolveReviewThread()`,
|
|
272
|
+
* never compare it against a REST-sourced ID.
|
|
273
|
+
*/
|
|
274
|
+
interface ReviewThread {
|
|
275
|
+
id: string;
|
|
276
|
+
isResolved: boolean;
|
|
277
|
+
/** The thread's first comment's author login (e.g. `"the-holocron-sentinel[bot]"`) — `undefined` if GitHub ever returns a thread with no comments, which shouldn't happen in practice. Callers filter on this before resolving anything, so a bot never touches a human reviewer's own thread. */
|
|
278
|
+
authorLogin: string | undefined;
|
|
279
|
+
}
|
|
238
280
|
//#endregion
|
|
239
|
-
//#region src/repos/repos.d.ts
|
|
281
|
+
//#region ../../../../../src/repos/repos.d.ts
|
|
240
282
|
interface GitHubRepo {
|
|
241
283
|
default_branch: string;
|
|
242
284
|
full_name: string;
|
|
@@ -246,14 +288,14 @@ interface GitHubContents {
|
|
|
246
288
|
encoding: string;
|
|
247
289
|
}
|
|
248
290
|
//#endregion
|
|
249
|
-
//#region src/rulesets/rulesets.d.ts
|
|
291
|
+
//#region ../../../../../src/rulesets/rulesets.d.ts
|
|
250
292
|
interface GitHubRuleset {
|
|
251
293
|
id: number;
|
|
252
294
|
name: string;
|
|
253
295
|
enforcement: string;
|
|
254
296
|
}
|
|
255
297
|
//#endregion
|
|
256
|
-
//#region src/secrets/secrets.d.ts
|
|
298
|
+
//#region ../../../../../src/secrets/secrets.d.ts
|
|
257
299
|
type SecretScope = {
|
|
258
300
|
kind: "repo";
|
|
259
301
|
} | {
|
|
@@ -268,23 +310,23 @@ interface GitHubPublicKey {
|
|
|
268
310
|
key: string;
|
|
269
311
|
}
|
|
270
312
|
//#endregion
|
|
271
|
-
//#region src/security/security.d.ts
|
|
313
|
+
//#region ../../../../../src/security/security.d.ts
|
|
272
314
|
interface CodeScanningSetupResult {
|
|
273
315
|
run_id: number;
|
|
274
316
|
run_url: string;
|
|
275
317
|
}
|
|
276
318
|
//#endregion
|
|
277
|
-
//#region src/teams/teams.d.ts
|
|
319
|
+
//#region ../../../../../src/teams/teams.d.ts
|
|
278
320
|
type TeamPermission = "pull" | "triage" | "push" | "maintain" | "admin";
|
|
279
321
|
//#endregion
|
|
280
|
-
//#region src/user/user.d.ts
|
|
322
|
+
//#region ../../../../../src/user/user.d.ts
|
|
281
323
|
interface GitHubUser {
|
|
282
324
|
login: string;
|
|
283
325
|
name: string | null;
|
|
284
326
|
email: string | null;
|
|
285
327
|
}
|
|
286
328
|
//#endregion
|
|
287
|
-
//#region src/workflows/workflows.d.ts
|
|
329
|
+
//#region ../../../../../src/workflows/workflows.d.ts
|
|
288
330
|
interface GitHubWorkflowRun {
|
|
289
331
|
id: number;
|
|
290
332
|
name: string | null;
|
|
@@ -303,7 +345,7 @@ interface WorkflowRunFilter {
|
|
|
303
345
|
status?: string;
|
|
304
346
|
}
|
|
305
347
|
//#endregion
|
|
306
|
-
//#region src/app-auth/app-auth.d.ts
|
|
348
|
+
//#region ../../../../../src/app-auth/app-auth.d.ts
|
|
307
349
|
interface GitHubAppCredentials {
|
|
308
350
|
/** The App's numeric id (not the client id). */
|
|
309
351
|
appId: string;
|
|
@@ -331,7 +373,7 @@ declare function getInstallationAccessToken(creds: GitHubAppCredentials, install
|
|
|
331
373
|
/** The whole flow in one call — an already-authenticated `GitHubClient` scoped to one installation. */
|
|
332
374
|
declare function createInstallationClient(creds: GitHubAppCredentials, installationId: number, opts?: Pick<GitHubClientOptions, "baseUrl" | "fetch">): Promise<GitHubClient>;
|
|
333
375
|
//#endregion
|
|
334
|
-
//#region src/webhooks/webhooks.d.ts
|
|
376
|
+
//#region ../../../../../src/webhooks/webhooks.d.ts
|
|
335
377
|
/**
|
|
336
378
|
* GitHub's own webhook mechanics — signature verification and header/
|
|
337
379
|
* payload shapes. Pure functions, no REST call, no auth token: these
|
|
@@ -398,7 +440,7 @@ interface GitHubPullRequestWebhookPayload {
|
|
|
398
440
|
};
|
|
399
441
|
}
|
|
400
442
|
//#endregion
|
|
401
|
-
//#region src/index.d.ts
|
|
443
|
+
//#region ../../../../../src/index.d.ts
|
|
402
444
|
declare function createGitHubClient(opts: GitHubClientOptions): {
|
|
403
445
|
branches: {
|
|
404
446
|
protectBranch: (repo: string, branch: string, payload: Record<string, unknown>) => Promise<void>;
|
|
@@ -466,6 +508,9 @@ declare function createGitHubClient(opts: GitHubClientOptions): {
|
|
|
466
508
|
getPullRequest: (repo: string, number: number) => Promise<GitHubPullRequest>;
|
|
467
509
|
listCommits: (repo: string, number: number) => Promise<GitHubPullRequestCommit[]>;
|
|
468
510
|
listFiles: (repo: string, number: number) => Promise<GitHubPullRequestFile[]>;
|
|
511
|
+
createReview: (repo: string, number: number, input: CreateReviewInput) => Promise<GitHubPullRequestReview>;
|
|
512
|
+
listReviewThreads: (repo: string, number: number) => Promise<ReviewThread[]>;
|
|
513
|
+
resolveReviewThread: (threadId: string) => Promise<void>;
|
|
469
514
|
};
|
|
470
515
|
repos: {
|
|
471
516
|
getRepo: (repo: string) => Promise<GitHubRepo>;
|
|
@@ -509,4 +554,4 @@ declare function createGitHubClient(opts: GitHubClientOptions): {
|
|
|
509
554
|
};
|
|
510
555
|
type GitHubClient = ReturnType<typeof createGitHubClient>;
|
|
511
556
|
//#endregion
|
|
512
|
-
export { type CheckRunAnnotation, type CheckRunAnnotationLevel, type CheckRunConclusion, type CheckRunOutput, type CheckRunStatus, type CodeScanningSetupResult, type CreateCheckRunInput, type CreatePagesPayload, type CreatePullInput, type GitBlob, type GitCommit, type GitContents, type GitHubAppCredentials, type GitHubCheckRun, GitHubClient, type GitHubClientOptions, type GitHubContents, type GitHubEnvironment, type GitHubInstallationWebhookPayload, type GitHubIssue, type GitHubLabel, type GitHubMilestone, type GitHubPages, type GitHubPublicKey, type GitHubPullRequest, type GitHubPullRequestCommit, type GitHubPullRequestFile, type GitHubPullRequestWebhookPayload, type GitHubPushWebhookPayload, type GitHubRepo, type GitHubRuleset, type GitHubUser, type GitHubWebhookHeaders, type GitHubWorkflowRun, type GitPull, type GitRef, type GitTree, type GitTreeItem, type InstallationAccessToken, type IssueSearchParams, type PagesBuildStatus, type PagesBuildType, type SecretScope, type TeamPermission, type UpdateCheckRunInput, type UpdatePagesPayload, type WorkflowRunFilter, createAppJWT, createGitHubClient, createInstallationClient, getInstallationAccessToken, parseGitHubWebhookHeaders, verifyGitHubWebhookSignature };
|
|
557
|
+
export { type CheckRunAnnotation, type CheckRunAnnotationLevel, type CheckRunConclusion, type CheckRunOutput, type CheckRunStatus, type CodeScanningSetupResult, type CreateCheckRunInput, type CreatePagesPayload, type CreatePullInput, type CreateReviewComment, type CreateReviewInput, type GitBlob, type GitCommit, type GitContents, type GitHubAppCredentials, type GitHubCheckRun, GitHubClient, type GitHubClientOptions, type GitHubContents, type GitHubEnvironment, type GitHubInstallationWebhookPayload, type GitHubIssue, type GitHubLabel, type GitHubMilestone, type GitHubPages, type GitHubPublicKey, type GitHubPullRequest, type GitHubPullRequestCommit, type GitHubPullRequestFile, type GitHubPullRequestReview, type GitHubPullRequestWebhookPayload, type GitHubPushWebhookPayload, type GitHubRepo, type GitHubRuleset, type GitHubUser, type GitHubWebhookHeaders, type GitHubWorkflowRun, type GitPull, type GitRef, type GitTree, type GitTreeItem, type InstallationAccessToken, type IssueSearchParams, type PagesBuildStatus, type PagesBuildType, type ReviewThread, type SecretScope, type TeamPermission, type UpdateCheckRunInput, type UpdatePagesPayload, type WorkflowRunFilter, createAppJWT, createGitHubClient, createInstallationClient, getInstallationAccessToken, parseGitHubWebhookHeaders, verifyGitHubWebhookSignature };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import { ProviderApiError, createRestClient } from "@theholocron/http-client";
|
|
2
2
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region ../../../../../src/graphql/graphql.ts
|
|
4
|
+
function createGitHubGraphQLClient(config) {
|
|
5
|
+
const rest = createRestClient({
|
|
6
|
+
baseUrl: config.baseUrl ?? "https://api.github.com",
|
|
7
|
+
token: config.token,
|
|
8
|
+
vendor: "GitHub GraphQL",
|
|
9
|
+
fetch: config.fetch,
|
|
10
|
+
logger: config.logger,
|
|
11
|
+
errors: config.errors
|
|
12
|
+
});
|
|
13
|
+
return { async query(document, variables) {
|
|
14
|
+
const result = await rest.request("/graphql", {
|
|
15
|
+
method: "POST",
|
|
16
|
+
body: {
|
|
17
|
+
query: document,
|
|
18
|
+
variables
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
if (result.errors && result.errors.length > 0) throw new ProviderApiError(`GitHub GraphQL → ${result.errors.map((e) => e.message).join("; ")}`, 200, result.errors);
|
|
22
|
+
return result.data;
|
|
23
|
+
} };
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region ../../../../../src/utils.ts
|
|
4
27
|
function createGitHubRestClient(opts) {
|
|
5
28
|
return createRestClient({
|
|
6
29
|
baseUrl: opts.baseUrl ?? "https://api.github.com",
|
|
@@ -15,13 +38,28 @@ function createGitHubRestClient(opts) {
|
|
|
15
38
|
errors: opts.errors
|
|
16
39
|
});
|
|
17
40
|
}
|
|
41
|
+
/** GitHub's GraphQL endpoint — a distinct client from `createGitHubRestClient()`'s REST one; see `graphql/graphql.ts` for why a shared transport still needed its own response-error handling. */
|
|
42
|
+
function createGitHubGraphQLApiClient(opts) {
|
|
43
|
+
return createGitHubGraphQLClient({
|
|
44
|
+
baseUrl: opts.baseUrl,
|
|
45
|
+
token: opts.token,
|
|
46
|
+
fetch: opts.fetch,
|
|
47
|
+
logger: opts.logger,
|
|
48
|
+
errors: opts.errors
|
|
49
|
+
});
|
|
50
|
+
}
|
|
18
51
|
/** `/repos/owner/name` prefix from a `"owner/name"` repo string. */
|
|
19
52
|
function repoBase(repo) {
|
|
20
53
|
const [owner, name] = repo.split("/", 2);
|
|
21
54
|
return `/repos/${owner}/${name}`;
|
|
22
55
|
}
|
|
56
|
+
/** `["owner", "name"]` from a `"owner/name"` repo string — GraphQL's `repository(owner:, name:)` args take them separately, unlike REST's single path segment. */
|
|
57
|
+
function splitRepo(repo) {
|
|
58
|
+
const [owner, name] = repo.split("/", 2);
|
|
59
|
+
return [owner ?? "", name ?? ""];
|
|
60
|
+
}
|
|
23
61
|
//#endregion
|
|
24
|
-
//#region src/branches/branches.ts
|
|
62
|
+
//#region ../../../../../src/branches/branches.ts
|
|
25
63
|
function branches(rest) {
|
|
26
64
|
return { protectBranch: (repo, branch, payload) => rest.request(`${repoBase(repo)}/branches/${encodeURIComponent(branch)}/protection`, {
|
|
27
65
|
method: "PUT",
|
|
@@ -29,7 +67,7 @@ function branches(rest) {
|
|
|
29
67
|
}) };
|
|
30
68
|
}
|
|
31
69
|
//#endregion
|
|
32
|
-
//#region src/checks/checks.ts
|
|
70
|
+
//#region ../../../../../src/checks/checks.ts
|
|
33
71
|
function checks(rest) {
|
|
34
72
|
return {
|
|
35
73
|
createCheckRun: (repo, input) => rest.request(`${repoBase(repo)}/check-runs`, {
|
|
@@ -44,7 +82,7 @@ function checks(rest) {
|
|
|
44
82
|
};
|
|
45
83
|
}
|
|
46
84
|
//#endregion
|
|
47
|
-
//#region src/environments/environments.ts
|
|
85
|
+
//#region ../../../../../src/environments/environments.ts
|
|
48
86
|
function environments(rest) {
|
|
49
87
|
return {
|
|
50
88
|
listEnvironments: (repo) => rest.request(`${repoBase(repo)}/environments`).then((r) => r.environments),
|
|
@@ -59,7 +97,7 @@ function environments(rest) {
|
|
|
59
97
|
};
|
|
60
98
|
}
|
|
61
99
|
//#endregion
|
|
62
|
-
//#region src/git/git.ts
|
|
100
|
+
//#region ../../../../../src/git/git.ts
|
|
63
101
|
function git(rest) {
|
|
64
102
|
return {
|
|
65
103
|
getRef: (repo, branch) => rest.request(`${repoBase(repo)}/git/ref/heads/${branch}`),
|
|
@@ -117,7 +155,7 @@ function git(rest) {
|
|
|
117
155
|
};
|
|
118
156
|
}
|
|
119
157
|
//#endregion
|
|
120
|
-
//#region src/issues/issues.ts
|
|
158
|
+
//#region ../../../../../src/issues/issues.ts
|
|
121
159
|
function issues(rest) {
|
|
122
160
|
return {
|
|
123
161
|
listIssues: (repo, params = {}) => {
|
|
@@ -158,7 +196,7 @@ function issues(rest) {
|
|
|
158
196
|
};
|
|
159
197
|
}
|
|
160
198
|
//#endregion
|
|
161
|
-
//#region src/labels/labels.ts
|
|
199
|
+
//#region ../../../../../src/labels/labels.ts
|
|
162
200
|
function labels(rest) {
|
|
163
201
|
return {
|
|
164
202
|
listLabels: (repo) => rest.request(`${repoBase(repo)}/labels?per_page=100`),
|
|
@@ -174,7 +212,7 @@ function labels(rest) {
|
|
|
174
212
|
};
|
|
175
213
|
}
|
|
176
214
|
//#endregion
|
|
177
|
-
//#region src/pages/pages.ts
|
|
215
|
+
//#region ../../../../../src/pages/pages.ts
|
|
178
216
|
function pages(rest) {
|
|
179
217
|
return {
|
|
180
218
|
/** Returns null when Pages is not yet enabled (404). */
|
|
@@ -206,7 +244,7 @@ function pages(rest) {
|
|
|
206
244
|
};
|
|
207
245
|
}
|
|
208
246
|
//#endregion
|
|
209
|
-
//#region src/properties/properties.ts
|
|
247
|
+
//#region ../../../../../src/properties/properties.ts
|
|
210
248
|
function properties(rest) {
|
|
211
249
|
return {
|
|
212
250
|
/**
|
|
@@ -229,8 +267,34 @@ setProperties: (repo, values) => {
|
|
|
229
267
|
} };
|
|
230
268
|
}
|
|
231
269
|
//#endregion
|
|
232
|
-
//#region src/pulls/pulls.ts
|
|
233
|
-
|
|
270
|
+
//#region ../../../../../src/pulls/pulls.ts
|
|
271
|
+
const LIST_REVIEW_THREADS_QUERY = `
|
|
272
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
273
|
+
repository(owner: $owner, name: $name) {
|
|
274
|
+
pullRequest(number: $number) {
|
|
275
|
+
reviewThreads(first: 100) {
|
|
276
|
+
nodes {
|
|
277
|
+
id
|
|
278
|
+
isResolved
|
|
279
|
+
comments(first: 1) {
|
|
280
|
+
nodes {
|
|
281
|
+
author { login }
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
`;
|
|
290
|
+
const RESOLVE_REVIEW_THREAD_MUTATION = `
|
|
291
|
+
mutation($threadId: ID!) {
|
|
292
|
+
resolveReviewThread(input: { threadId: $threadId }) {
|
|
293
|
+
thread { id isResolved }
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
function pulls(rest, graphql) {
|
|
234
298
|
return {
|
|
235
299
|
getPullRequest: (repo, number) => rest.request(`${repoBase(repo)}/pulls/${number}`),
|
|
236
300
|
/**
|
|
@@ -246,11 +310,42 @@ function pulls(rest) {
|
|
|
246
310
|
* files (GitHub caps this endpoint at 3000 regardless of pagination)
|
|
247
311
|
* is an edge case no consumer here needs to paginate for today.
|
|
248
312
|
*/
|
|
249
|
-
listFiles: (repo, number) => rest.request(`${repoBase(repo)}/pulls/${number}/files?per_page=100`)
|
|
313
|
+
listFiles: (repo, number) => rest.request(`${repoBase(repo)}/pulls/${number}/files?per_page=100`),
|
|
314
|
+
/**
|
|
315
|
+
* Submits a review in one call — GitHub has no separate "create draft,
|
|
316
|
+
* then submit" step when `event` is provided directly (the multi-step
|
|
317
|
+
* `PENDING` review flow exists for the web UI's own draft-comments
|
|
318
|
+
* experience, not needed here).
|
|
319
|
+
*/
|
|
320
|
+
createReview: (repo, number, input) => rest.request(`${repoBase(repo)}/pulls/${number}/reviews`, {
|
|
321
|
+
method: "POST",
|
|
322
|
+
body: input
|
|
323
|
+
}),
|
|
324
|
+
/** Every review thread on a PR, resolved or not — GraphQL-only, `first: 100` covers every real PR's review-thread count in this org today; no consumer needs pagination yet. */
|
|
325
|
+
listReviewThreads: async (repo, number) => {
|
|
326
|
+
const [owner, name] = splitRepo(repo);
|
|
327
|
+
return (await graphql.query(LIST_REVIEW_THREADS_QUERY, {
|
|
328
|
+
owner,
|
|
329
|
+
name,
|
|
330
|
+
number
|
|
331
|
+
})).repository.pullRequest.reviewThreads.nodes.map((node) => ({
|
|
332
|
+
id: node.id,
|
|
333
|
+
isResolved: node.isResolved,
|
|
334
|
+
authorLogin: node.comments.nodes[0]?.author?.login
|
|
335
|
+
}));
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* Marks one review thread resolved. Requires `Contents: Write` —
|
|
339
|
+
* confirmed directly against GitHub's own behavior (surprising, since
|
|
340
|
+
* resolving a thread creates no commit, touches no file, moves no
|
|
341
|
+
* ref — it only toggles a boolean on PR conversation metadata), not
|
|
342
|
+
* `Pull requests: Write` the way `createReview()` needs.
|
|
343
|
+
*/
|
|
344
|
+
resolveReviewThread: (threadId) => graphql.query(RESOLVE_REVIEW_THREAD_MUTATION, { threadId })
|
|
250
345
|
};
|
|
251
346
|
}
|
|
252
347
|
//#endregion
|
|
253
|
-
//#region src/repos/repos.ts
|
|
348
|
+
//#region ../../../../../src/repos/repos.ts
|
|
254
349
|
function repos(rest) {
|
|
255
350
|
return {
|
|
256
351
|
getRepo: (repo) => rest.request(repoBase(repo)),
|
|
@@ -262,7 +357,7 @@ function repos(rest) {
|
|
|
262
357
|
};
|
|
263
358
|
}
|
|
264
359
|
//#endregion
|
|
265
|
-
//#region src/rulesets/rulesets.ts
|
|
360
|
+
//#region ../../../../../src/rulesets/rulesets.ts
|
|
266
361
|
function rulesets(rest) {
|
|
267
362
|
return {
|
|
268
363
|
listRulesets: (repo) => rest.request(`${repoBase(repo)}/rulesets`),
|
|
@@ -277,7 +372,7 @@ function rulesets(rest) {
|
|
|
277
372
|
};
|
|
278
373
|
}
|
|
279
374
|
//#endregion
|
|
280
|
-
//#region src/secrets/secrets.ts
|
|
375
|
+
//#region ../../../../../src/secrets/secrets.ts
|
|
281
376
|
function scopeBase(repo, scope) {
|
|
282
377
|
switch (scope.kind) {
|
|
283
378
|
case "repo": return `${repoBase(repo)}/actions`;
|
|
@@ -301,7 +396,7 @@ function secrets(rest) {
|
|
|
301
396
|
};
|
|
302
397
|
}
|
|
303
398
|
//#endregion
|
|
304
|
-
//#region src/security/security.ts
|
|
399
|
+
//#region ../../../../../src/security/security.ts
|
|
305
400
|
function security(rest) {
|
|
306
401
|
return {
|
|
307
402
|
enableVulnerabilityAlerts: (repo) => rest.request(`${repoBase(repo)}/vulnerability-alerts`, {
|
|
@@ -347,7 +442,7 @@ function security(rest) {
|
|
|
347
442
|
};
|
|
348
443
|
}
|
|
349
444
|
//#endregion
|
|
350
|
-
//#region src/teams/teams.ts
|
|
445
|
+
//#region ../../../../../src/teams/teams.ts
|
|
351
446
|
function teams(rest) {
|
|
352
447
|
return { addRepo: (org, teamSlug, owner, repo, permission) => rest.request(`/orgs/${org}/teams/${teamSlug}/repos/${owner}/${repo}`, {
|
|
353
448
|
method: "PUT",
|
|
@@ -355,7 +450,7 @@ function teams(rest) {
|
|
|
355
450
|
}) };
|
|
356
451
|
}
|
|
357
452
|
//#endregion
|
|
358
|
-
//#region src/topics/topics.ts
|
|
453
|
+
//#region ../../../../../src/topics/topics.ts
|
|
359
454
|
function topics(rest) {
|
|
360
455
|
return { setTopics: (repo, names) => rest.request(`${repoBase(repo)}/topics`, {
|
|
361
456
|
method: "PUT",
|
|
@@ -363,12 +458,12 @@ function topics(rest) {
|
|
|
363
458
|
}) };
|
|
364
459
|
}
|
|
365
460
|
//#endregion
|
|
366
|
-
//#region src/user/user.ts
|
|
461
|
+
//#region ../../../../../src/user/user.ts
|
|
367
462
|
function user(rest) {
|
|
368
463
|
return { getCurrentUser: () => rest.request("/user") };
|
|
369
464
|
}
|
|
370
465
|
//#endregion
|
|
371
|
-
//#region src/workflows/workflows.ts
|
|
466
|
+
//#region ../../../../../src/workflows/workflows.ts
|
|
372
467
|
function workflows(rest) {
|
|
373
468
|
return {
|
|
374
469
|
listRuns: (repo, filter) => {
|
|
@@ -400,7 +495,7 @@ function workflows(rest) {
|
|
|
400
495
|
};
|
|
401
496
|
}
|
|
402
497
|
//#endregion
|
|
403
|
-
//#region src/app-auth/pem.ts
|
|
498
|
+
//#region ../../../../../src/app-auth/pem.ts
|
|
404
499
|
/**
|
|
405
500
|
* PEM/DER handling for GitHub App private keys — Web Crypto only (no
|
|
406
501
|
* `node:crypto`), so this runs unchanged on Cloudflare Workers (no
|
|
@@ -487,7 +582,7 @@ function base64UrlEncode(bytes) {
|
|
|
487
582
|
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
488
583
|
}
|
|
489
584
|
//#endregion
|
|
490
|
-
//#region src/app-auth/app-auth.ts
|
|
585
|
+
//#region ../../../../../src/app-auth/app-auth.ts
|
|
491
586
|
/**
|
|
492
587
|
* GitHub App authentication — a signed App JWT, exchanged for a
|
|
493
588
|
* short-lived installation access token, exchanged for a ready-to-use
|
|
@@ -558,7 +653,7 @@ async function createInstallationClient(creds, installationId, opts = {}) {
|
|
|
558
653
|
});
|
|
559
654
|
}
|
|
560
655
|
//#endregion
|
|
561
|
-
//#region src/webhooks/webhooks.ts
|
|
656
|
+
//#region ../../../../../src/webhooks/webhooks.ts
|
|
562
657
|
/**
|
|
563
658
|
* GitHub's own webhook mechanics — signature verification and header/
|
|
564
659
|
* payload shapes. Pure functions, no REST call, no auth token: these
|
|
@@ -604,9 +699,10 @@ function parseGitHubWebhookHeaders(headers) {
|
|
|
604
699
|
};
|
|
605
700
|
}
|
|
606
701
|
//#endregion
|
|
607
|
-
//#region src/index.ts
|
|
702
|
+
//#region ../../../../../src/index.ts
|
|
608
703
|
function createGitHubClient(opts) {
|
|
609
704
|
const rest = createGitHubRestClient(opts);
|
|
705
|
+
const graphql = createGitHubGraphQLApiClient(opts);
|
|
610
706
|
return {
|
|
611
707
|
branches: branches(rest),
|
|
612
708
|
checks: checks(rest),
|
|
@@ -616,7 +712,7 @@ function createGitHubClient(opts) {
|
|
|
616
712
|
labels: labels(rest),
|
|
617
713
|
pages: pages(rest),
|
|
618
714
|
properties: properties(rest),
|
|
619
|
-
pulls: pulls(rest),
|
|
715
|
+
pulls: pulls(rest, graphql),
|
|
620
716
|
repos: repos(rest),
|
|
621
717
|
rulesets: rulesets(rest),
|
|
622
718
|
secrets: secrets(rest),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/github-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.1",
|
|
4
4
|
"description": "A TypeScript client for the GitHub REST API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github",
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@theholocron/observability": "^0.3.0",
|
|
36
|
-
"@theholocron/http-client": "^1.
|
|
36
|
+
"@theholocron/http-client": "^1.32.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
39
|
+
"@theholocron/cli": "5.0.0-alpha.79",
|
|
40
40
|
"@theholocron/eslint-config": "^8.4.3",
|
|
41
41
|
"@theholocron/tsconfig": "^8.2.0",
|
|
42
|
-
"@theholocron/tsdown-config": "^8.
|
|
42
|
+
"@theholocron/tsdown-config": "^8.6.1",
|
|
43
43
|
"@theholocron/vitest-config": "^8.2.0",
|
|
44
44
|
"@types/node": "^26.4.1",
|
|
45
45
|
"@vitest/coverage-v8": "^5.0.0",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"releases": "https://github.com/theholocron/clients/releases",
|
|
62
62
|
"wiki": "https://github.com/theholocron/clients/wiki",
|
|
63
63
|
"scripts": {
|
|
64
|
-
"delivery.build": "
|
|
64
|
+
"delivery.build": "holocron run delivery.build -- && node ../../scripts/check-bundle-size.mjs",
|
|
65
65
|
"sourceQuality.staticAnalysis": "holocron run sourceQuality.staticAnalysis --",
|
|
66
66
|
"test:watch": "vitest",
|
|
67
67
|
"verification.typeSafety": "holocron run verification.typeSafety --",
|