@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 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/utils.ts
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
- function pulls(rest) {
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.31.0",
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.31.0"
36
+ "@theholocron/http-client": "^1.32.1"
37
37
  },
38
38
  "devDependencies": {
39
- "@theholocron/cli": "5.0.0-alpha.33",
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.2.0",
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": "tsdown",
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 --",