@effected/github 0.23.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -174,11 +174,12 @@ interface ActionsOidcVerifyOptions {
174
174
  *
175
175
  * @public
176
176
  */
177
- export declare const ActionsOidc: {
177
+ export declare class ActionsOidc {
178
+ private constructor();
178
179
  /** The Actions OIDC issuer, `https://token.actions.githubusercontent.com`. */
179
- readonly issuer: "https://token.actions.githubusercontent.com";
180
+ static readonly issuer: "https://token.actions.githubusercontent.com";
180
181
  /** Verify a runner-issued OIDC token: signature against GitHub's JWKS, iss, aud, exp/nbf, then typed claims. */
181
- readonly verify: (token: string, options: ActionsOidcVerifyOptions) => Effect.Effect<ActionsOidcClaims, JwtError, JwksResolver>;
182
+ static readonly verify: (token: string, options: ActionsOidcVerifyOptions) => Effect.Effect<ActionsOidcClaims, JwtError, JwksResolver>;
182
183
  /**
183
184
  * A valid claims payload for tests, overridable field by field.
184
185
  *
@@ -189,8 +190,8 @@ export declare const ActionsOidc: {
189
190
  * {@link ActionsOidc.issuer}; `aud` is a placeholder to override with the
190
191
  * audience under test.
191
192
  */
192
- readonly testClaims: (overrides?: Readonly<Record<string, unknown>>) => Record<string, unknown>;
193
- };
193
+ static readonly testClaims: (overrides?: Readonly<Record<string, unknown>>) => Record<string, unknown>;
194
+ }
194
195
  /**
195
196
  * Why a GitHub call failed, as a value you can branch on.
196
197
  *
@@ -760,7 +761,8 @@ export declare class PageOptions extends PageOptions_base {
760
761
  * Every member is an `Effect`, a `Stream`, or a function returning one — the
761
762
  * rule that keeps `Layer.mock` and `layerTest(Partial<Shape>)` useful. That
762
763
  * includes `rateLimit`, which is an `Effect`-valued property rather than a
763
- * getter for exactly this reason.
764
+ * getter for exactly this reason. The one plain value is `apiVersion`, a
765
+ * string fixed at construction that no double needs to stub.
764
766
  *
765
767
  * @public
766
768
  */
@@ -820,6 +822,20 @@ interface GitHubClientShape {
820
822
  * a caller that wants to pace itself proactively reads this.
821
823
  */
822
824
  readonly rateLimit: Effect.Effect<Option.Option<RateLimitSnapshot>>;
825
+ /**
826
+ * The REST api-version this client pins, as sent in `x-github-api-version`.
827
+ *
828
+ * @remarks
829
+ * A plain value, not an `Effect`: it is fixed when the client is built and
830
+ * reading it does no work. Resource services read it to shape a request for
831
+ * the version it goes out under — a body field one version requires and a
832
+ * later one removed, say. Calendar versions are `YYYY-MM-DD`, so two of them
833
+ * compare correctly as strings: `client.apiVersion < "2026-03-10"`.
834
+ *
835
+ * A call that sets its own `x-github-api-version` header goes out under that
836
+ * version instead; this is the version of every other call.
837
+ */
838
+ readonly apiVersion: string;
823
839
  }
824
840
  /**
825
841
  * How a client layer is built.
@@ -845,6 +861,25 @@ interface GitHubClientOptions {
845
861
  * a hand-written double of this service.
846
862
  */
847
863
  readonly fetch?: typeof globalThis.fetch | undefined;
864
+ /**
865
+ * The REST api-version every request pins, sent as `x-github-api-version`.
866
+ * Defaults to `"2026-03-10"`.
867
+ *
868
+ * @remarks
869
+ * Without the header GitHub serves its oldest supported version, which it
870
+ * deprecates and then sunsets, so the client always sends one. A call that
871
+ * sets its own `x-github-api-version` header keeps it: the per-call header
872
+ * wins over this option.
873
+ *
874
+ * A GitHub Enterprise Server release that predates the default version
875
+ * rejects the header, so a client pointed at one through `baseUrl` sets the
876
+ * newest version that server supports here.
877
+ *
878
+ * Must be a calendar version, `YYYY-MM-DD`. Anything else is a wiring
879
+ * mistake and kills the fiber building the client, with a defect naming
880
+ * this option, rather than reaching GitHub as a header it rejects.
881
+ */
882
+ readonly apiVersion?: string | undefined;
848
883
  }
849
884
  /**
850
885
  * One call served by {@link GitHubClient.layerFixture}, as recorded in
@@ -864,7 +899,7 @@ interface RecordedCall {
864
899
  }
865
900
  /**
866
901
  * A raw HTTP failure recorded for {@link GitHubClient.layerFixture}, made by
867
- * {@link (GitHubFixtures:variable).failure}.
902
+ * {@link (GitHubFixtures:class).failure}.
868
903
  *
869
904
  * @remarks
870
905
  * Branded, so a fixture's data payload that happens to have a `status` and a
@@ -894,7 +929,8 @@ export declare class RawFailure {
894
929
  *
895
930
  * @public
896
931
  */
897
- export declare const GitHubFixtures: {
932
+ export declare class GitHubFixtures {
933
+ private constructor();
898
934
  /**
899
935
  * A raw failure: what GitHub answered, classified at call time by the same
900
936
  * classifier the live client uses.
@@ -924,12 +960,12 @@ export declare const GitHubFixtures: {
924
960
  * });
925
961
  * ```
926
962
  */
927
- readonly failure: (response: {
963
+ static readonly failure: (response: {
928
964
  readonly status: number;
929
965
  readonly headers?: Readonly<Record<string, string>> | undefined;
930
966
  readonly body?: unknown;
931
967
  }) => RawFailure;
932
- };
968
+ }
933
969
  /**
934
970
  * A recorded response table for {@link GitHubClient.layerFixture}.
935
971
  *
@@ -944,7 +980,7 @@ export interface GitHubFixtures {
944
980
  * is how a suite stubs a 404 (or a rate-limit, or a 422) deliberately,
945
981
  * rather than relying on a route's absence to produce one — absence is a
946
982
  * wiring mistake and {@link (GitHubFixtures:interface).unstubbed} treats it as
947
- * such. A {@link RawFailure} from {@link (GitHubFixtures:variable).failure}
983
+ * such. A {@link RawFailure} from {@link (GitHubFixtures:class).failure}
948
984
  * fails it too, classified from GitHub's raw response.
949
985
  *
950
986
  * A value of `undefined` counts as unstubbed, so stub a route that answers
@@ -987,6 +1023,15 @@ export interface GitHubFixtures {
987
1023
  readonly unstubbed?: "die" | "fail" | "empty" | undefined;
988
1024
  /** What `rateLimit` answers. */
989
1025
  readonly rateLimit?: RateLimitSnapshot | undefined;
1026
+ /**
1027
+ * What `apiVersion` answers; defaults to the live client's default,
1028
+ * `"2026-03-10"`.
1029
+ *
1030
+ * @remarks
1031
+ * Set it to drive a resource's version-dependent branch — a request body
1032
+ * an older api-version needs — without a live client.
1033
+ */
1034
+ readonly apiVersion?: string | undefined;
990
1035
  /**
991
1036
  * Every call the fixture served, in order. Populated as the test runs.
992
1037
  *
@@ -1063,11 +1108,14 @@ export declare class GitHubClient extends GitHubClient_base {
1063
1108
  * member **dies** naming itself.
1064
1109
  *
1065
1110
  * @remarks
1066
- * No member has an honest default. A fabricated response — an empty list, a
1111
+ * No request member has an honest default. A fabricated response — an empty list, a
1067
1112
  * made-up sha — would leak into the code under test as fact, so the double
1068
1113
  * fails loudly instead, which also makes it proof that a test touches nothing
1069
1114
  * but what it stubbed.
1070
1115
  *
1116
+ * `rateLimit` answers `Option.none()` and `apiVersion` the live default,
1117
+ * because a real client legitimately answers both without a request.
1118
+ *
1071
1119
  * For recorded responses that page for real, use
1072
1120
  * {@link GitHubClient.layerFixture}.
1073
1121
  */
@@ -1088,7 +1136,7 @@ export declare class GitHubClient extends GitHubClient_base {
1088
1136
  *
1089
1137
  * **It records every call it serves, including one that fails.** A call
1090
1138
  * answered by a recorded `GitHubError` or a
1091
- * {@link (GitHubFixtures:variable).failure} is recorded before it fails, so
1139
+ * {@link (GitHubFixtures:class).failure} is recorded before it fails, so
1092
1140
  * one fixture both records the calls and classifies a raw failure the way
1093
1141
  * the live client would; there is no need to classify by hand inside a
1094
1142
  * {@link GitHubClient.layerTest} handler.
@@ -1249,7 +1297,7 @@ declare const ArtifactMetadata_base: Context.ServiceClass<ArtifactMetadata, "@ef
1249
1297
  export declare class ArtifactMetadata extends ArtifactMetadata_base {
1250
1298
  /** The live service, built over a `GitHubClient`. */
1251
1299
  static readonly layer: Layer.Layer<ArtifactMetadata, never, GitHubClient>;
1252
- /** An in-memory double; unstubbed members die naming themselves. */
1300
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
1253
1301
  static readonly makeTest: (overrides?: Partial<ArtifactMetadataShape>) => ArtifactMetadataShape;
1254
1302
  /** {@link ArtifactMetadata.makeTest} behind a `Layer`. */
1255
1303
  static readonly layerTest: (overrides?: Partial<ArtifactMetadataShape>) => Layer.Layer<ArtifactMetadata>;
@@ -1317,7 +1365,7 @@ declare const Attestation_base: Context.ServiceClass<Attestation, "@effected/git
1317
1365
  export declare class Attestation extends Attestation_base {
1318
1366
  /** The live service, built over a `GitHubClient`. */
1319
1367
  static readonly layer: Layer.Layer<Attestation, never, GitHubClient>;
1320
- /** An in-memory double; unstubbed members die naming themselves. */
1368
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
1321
1369
  static readonly makeTest: (overrides?: Partial<AttestationShape>) => AttestationShape;
1322
1370
  /** {@link Attestation.makeTest} behind a `Layer`. */
1323
1371
  static readonly layerTest: (overrides?: Partial<AttestationShape>) => Layer.Layer<Attestation>;
@@ -1463,7 +1511,8 @@ interface AuthenticatedAppShape {
1463
1511
  *
1464
1512
  * @remarks
1465
1513
  * Irreversible from the app's side: only the account can install it again.
1466
- * An installation that does not exist (or is already gone) fails with
1514
+ * GitHub answers 202 and removes the installation in the background, so it
1515
+ * may still be listed briefly after this returns. An installation that does not exist (or is already gone) fails with
1467
1516
  * `GitHubError { kind: "notFound" }`.
1468
1517
  */
1469
1518
  readonly uninstall: (installationId: number) => Effect.Effect<void, GitHubError>;
@@ -1510,7 +1559,7 @@ declare const AuthenticatedApp_base: Context.ServiceClass<AuthenticatedApp, "@ef
1510
1559
  export declare class AuthenticatedApp extends AuthenticatedApp_base {
1511
1560
  /** The live service, built over an App-JWT `GitHubClient`. */
1512
1561
  static readonly layer: Layer.Layer<AuthenticatedApp, never, GitHubClient>;
1513
- /** An in-memory double; unstubbed members die naming themselves. */
1562
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
1514
1563
  static readonly makeTest: (overrides?: Partial<AuthenticatedAppShape>) => AuthenticatedAppShape;
1515
1564
  /** {@link AuthenticatedApp.makeTest} behind a `Layer`. */
1516
1565
  static readonly layerTest: (overrides?: Partial<AuthenticatedAppShape>) => Layer.Layer<AuthenticatedApp>;
@@ -1915,7 +1964,7 @@ declare const CheckRun_base: Context.ServiceClass<CheckRun, "@effected/github/Ch
1915
1964
  export declare class CheckRun extends CheckRun_base {
1916
1965
  /** The live service, built over a `GitHubClient`. */
1917
1966
  static readonly layer: Layer.Layer<CheckRun, never, GitHubClient>;
1918
- /** An in-memory double; unstubbed members die naming themselves. */
1967
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
1919
1968
  static readonly makeTest: (overrides?: Partial<CheckRunShape>) => CheckRunShape;
1920
1969
  /** {@link CheckRun.makeTest} behind a `Layer`. */
1921
1970
  static readonly layerTest: (overrides?: Partial<CheckRunShape>) => Layer.Layer<CheckRun>;
@@ -1934,7 +1983,15 @@ export declare class CheckRun extends CheckRun_base {
1934
1983
  interface CodeScanningSetup {
1935
1984
  /** Whether default setup is `configured` or `not-configured`. */
1936
1985
  readonly state?: "configured" | "not-configured" | undefined;
1937
- /** The CodeQL languages to analyse. */
1986
+ /**
1987
+ * The CodeQL languages to analyse.
1988
+ *
1989
+ * @remarks
1990
+ * CodeQL's names, not linguist's: JavaScript and TypeScript are the one
1991
+ * combined `javascript-typescript`, and the separate `javascript` and
1992
+ * `typescript` values are no longer accepted under the api-version the
1993
+ * client pins.
1994
+ */
1938
1995
  readonly languages?: ReadonlyArray<string> | undefined;
1939
1996
  /** `default` or `extended`. */
1940
1997
  readonly query_suite?: string | undefined;
@@ -2003,7 +2060,7 @@ export declare class CodeScanning extends CodeScanning_base {
2003
2060
  * with a clean typecheck.
2004
2061
  */
2005
2062
  static readonly layer: Layer.Layer<CodeScanning, never, GitHubClient>;
2006
- /** An in-memory double; unstubbed members die naming themselves. */
2063
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2007
2064
  static readonly makeTest: (overrides?: Partial<CodeScanningShape>) => CodeScanningShape;
2008
2065
  /** {@link CodeScanning.makeTest} behind a `Layer`. */
2009
2066
  static readonly layerTest: (overrides?: Partial<CodeScanningShape>) => Layer.Layer<CodeScanning>;
@@ -2080,7 +2137,7 @@ export declare class DeploymentEnvironment extends DeploymentEnvironment_base {
2080
2137
  * further down throws at import time with a clean typecheck.
2081
2138
  */
2082
2139
  static readonly layer: Layer.Layer<DeploymentEnvironment, never, GitHubClient>;
2083
- /** An in-memory double; unstubbed members die naming themselves. */
2140
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2084
2141
  static readonly makeTest: (overrides?: Partial<DeploymentEnvironmentShape>) => DeploymentEnvironmentShape;
2085
2142
  /** {@link DeploymentEnvironment.makeTest} behind a `Layer`. */
2086
2143
  static readonly layerTest: (overrides?: Partial<DeploymentEnvironmentShape>) => Layer.Layer<DeploymentEnvironment>;
@@ -2192,7 +2249,7 @@ export declare class GitBranch extends GitBranch_base {
2192
2249
  * layer is built.
2193
2250
  */
2194
2251
  static readonly layer: Layer.Layer<GitBranch, never, GitHubClient>;
2195
- /** An in-memory double; unstubbed members die naming themselves. */
2252
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2196
2253
  static readonly makeTest: (overrides?: Partial<GitBranchShape>) => GitBranchShape;
2197
2254
  /** {@link GitBranch.makeTest} behind a `Layer`. */
2198
2255
  static readonly layerTest: (overrides?: Partial<GitBranchShape>) => Layer.Layer<GitBranch>;
@@ -2328,7 +2385,7 @@ declare const GitCommit_base: Context.ServiceClass<GitCommit, "@effected/github/
2328
2385
  export declare class GitCommit extends GitCommit_base {
2329
2386
  /** The live service, built over a `GitHubClient`. */
2330
2387
  static readonly layer: Layer.Layer<GitCommit, never, GitHubClient>;
2331
- /** An in-memory double; unstubbed members die naming themselves. */
2388
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2332
2389
  static readonly makeTest: (overrides?: Partial<GitCommitShape>) => GitCommitShape;
2333
2390
  /** {@link GitCommit.makeTest} behind a `Layer`. */
2334
2391
  static readonly layerTest: (overrides?: Partial<GitCommitShape>) => Layer.Layer<GitCommit>;
@@ -2372,7 +2429,7 @@ declare const InstallationTokenStore_base: Context.ServiceClass<InstallationToke
2372
2429
  export declare class InstallationTokenStore extends InstallationTokenStore_base {
2373
2430
  /** An in-process store over a `Ref`, expiring entries against `Clock`. */
2374
2431
  static readonly layerMemory: Layer.Layer<InstallationTokenStore>;
2375
- /** An in-memory double; unstubbed members die naming themselves. */
2432
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2376
2433
  static readonly makeTest: (overrides?: Partial<InstallationTokenStoreShape>) => InstallationTokenStoreShape;
2377
2434
  /** {@link InstallationTokenStore.makeTest} behind a `Layer`. */
2378
2435
  static readonly layerTest: (overrides?: Partial<InstallationTokenStoreShape>) => Layer.Layer<InstallationTokenStore>;
@@ -2669,6 +2726,15 @@ interface GitHubAppOptions {
2669
2726
  readonly retry?: RetryPolicy | "off" | undefined;
2670
2727
  /** A replacement `fetch`, for tests and proxies. */
2671
2728
  readonly fetch?: typeof globalThis.fetch | undefined;
2729
+ /**
2730
+ * The REST api-version the app's clients pin; defaults to `"2026-03-10"`.
2731
+ *
2732
+ * @remarks
2733
+ * The same option as `GitHubClientOptions.apiVersion`, applied to every
2734
+ * client this module builds: as the app, as an installation, and
2735
+ * unauthenticated.
2736
+ */
2737
+ readonly apiVersion?: string | undefined;
2672
2738
  }
2673
2739
  declare const GitHubApp_base: Context.ServiceClass<GitHubApp, "@effected/github/GitHubApp", GitHubAppShape>;
2674
2740
  /**
@@ -2875,7 +2941,7 @@ export declare class GitHubApp extends GitHubApp_base {
2875
2941
  * ```
2876
2942
  */
2877
2943
  static readonly cachedClientLayer: (request: CachedTokenRequest, options?: GitHubAppOptions) => Layer.Layer<GitHubClient, GitHubAppError, GitHubApp | InstallationTokenStore>;
2878
- /** An in-memory double; unstubbed members die naming themselves. */
2944
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
2879
2945
  static readonly makeTest: (overrides?: Partial<GitHubAppShape>) => GitHubAppShape;
2880
2946
  /** {@link GitHubApp.makeTest} behind a `Layer`. */
2881
2947
  static readonly layerTest: (overrides?: Partial<GitHubAppShape>) => Layer.Layer<GitHubApp>;
@@ -3077,7 +3143,7 @@ declare const GitHubCommit_base: Context.ServiceClass<GitHubCommit, "@effected/g
3077
3143
  export declare class GitHubCommit extends GitHubCommit_base {
3078
3144
  /** The live service, built over a `GitHubClient`. */
3079
3145
  static readonly layer: Layer.Layer<GitHubCommit, never, GitHubClient>;
3080
- /** An in-memory double; unstubbed members die naming themselves. */
3146
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3081
3147
  static readonly makeTest: (overrides?: Partial<GitHubCommitShape>) => GitHubCommitShape;
3082
3148
  /** {@link GitHubCommit.makeTest} behind a `Layer`. */
3083
3149
  static readonly layerTest: (overrides?: Partial<GitHubCommitShape>) => Layer.Layer<GitHubCommit>;
@@ -3137,7 +3203,7 @@ declare const GitHubContent_base: Context.ServiceClass<GitHubContent, "@effected
3137
3203
  export declare class GitHubContent extends GitHubContent_base {
3138
3204
  /** The live service, built over a `GitHubClient`. */
3139
3205
  static readonly layer: Layer.Layer<GitHubContent, never, GitHubClient>;
3140
- /** An in-memory double; unstubbed members die naming themselves. */
3206
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3141
3207
  static readonly makeTest: (overrides?: Partial<GitHubContentShape>) => GitHubContentShape;
3142
3208
  /** {@link GitHubContent.makeTest} behind a `Layer`. */
3143
3209
  static readonly layerTest: (overrides?: Partial<GitHubContentShape>) => Layer.Layer<GitHubContent>;
@@ -3233,7 +3299,7 @@ declare const PullRequestComment_base: Context.ServiceClass<PullRequestComment,
3233
3299
  export declare class PullRequestComment extends PullRequestComment_base {
3234
3300
  /** The live service, built over a `GitHubClient`. */
3235
3301
  static readonly layer: Layer.Layer<PullRequestComment, never, GitHubClient>;
3236
- /** An in-memory double; unstubbed members die naming themselves. */
3302
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3237
3303
  static readonly makeTest: (overrides?: Partial<PullRequestCommentShape>) => PullRequestCommentShape;
3238
3304
  /** {@link PullRequestComment.makeTest} behind a `Layer`. */
3239
3305
  static readonly layerTest: (overrides?: Partial<PullRequestCommentShape>) => Layer.Layer<PullRequestComment>;
@@ -3390,7 +3456,7 @@ declare const GitHubIssue_base: Context.ServiceClass<GitHubIssue, "@effected/git
3390
3456
  export declare class GitHubIssue extends GitHubIssue_base {
3391
3457
  /** The live service, built over a `GitHubClient`. */
3392
3458
  static readonly layer: Layer.Layer<GitHubIssue, never, GitHubClient>;
3393
- /** An in-memory double; unstubbed members die naming themselves. */
3459
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3394
3460
  static readonly makeTest: (overrides?: Partial<GitHubIssueShape>) => GitHubIssueShape;
3395
3461
  /** {@link GitHubIssue.makeTest} behind a `Layer`. */
3396
3462
  static readonly layerTest: (overrides?: Partial<GitHubIssueShape>) => Layer.Layer<GitHubIssue>;
@@ -3510,7 +3576,7 @@ declare const GitHubRelease_base: Context.ServiceClass<GitHubRelease, "@effected
3510
3576
  export declare class GitHubRelease extends GitHubRelease_base {
3511
3577
  /** The live service, built over a `GitHubClient`. */
3512
3578
  static readonly layer: Layer.Layer<GitHubRelease, never, GitHubClient>;
3513
- /** An in-memory double; unstubbed members die naming themselves. */
3579
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3514
3580
  static readonly makeTest: (overrides?: Partial<GitHubReleaseShape>) => GitHubReleaseShape;
3515
3581
  /** {@link GitHubRelease.makeTest} behind a `Layer`. */
3516
3582
  static readonly layerTest: (overrides?: Partial<GitHubReleaseShape>) => Layer.Layer<GitHubRelease>;
@@ -3598,17 +3664,21 @@ type OwnerType = "User" | "Organization";
3598
3664
  */
3599
3665
  export declare const SECURITY_ANALYSIS_STATUS_FIELDS: ReadonlySet<string>;
3600
3666
  /**
3601
- * Settings reachable **only** through the GraphQL `updateRepository` mutation,
3602
- * mapped from snake_case keys to camelCase GraphQL input fields.
3667
+ * Settings written through the GraphQL `updateRepository` mutation, mapped
3668
+ * from snake_case keys to camelCase GraphQL input fields.
3603
3669
  *
3604
3670
  * @remarks
3605
- * GitHub never exposed these on the REST repository endpoint — the
3606
- * `PATCH /repos/{owner}/{repo}` route accepts none of them, and
3607
- * `has_discussions` is the treacherous one: the REST **read** returns it, so
3608
- * routing its write to the PATCH looks symmetric, but the PATCH silently
3609
- * ignores unknown body fields and answers 200, so the write would look applied
3610
- * while the repository never changed. Setting any of these forces a second
3611
- * round trip to learn the repository's node id.
3671
+ * `applySettings` checks this map **first**, so a key here always goes
3672
+ * through GraphQL, even when the REST patch also declares it.
3673
+ * `has_sponsorships` and `has_discussions` are GraphQL-only: the
3674
+ * `PATCH /repos/{owner}/{repo}` route accepts neither, and `has_discussions`
3675
+ * is the treacherous one — the REST **read** returns it, so routing its write
3676
+ * to the PATCH looks symmetric, but the PATCH silently ignores unknown body
3677
+ * fields and answers 200, so the write would look applied while the
3678
+ * repository never changed. `has_pull_requests` is in the REST patch's body
3679
+ * too; GraphQL is preferred for it so the three toggles travel together.
3680
+ * Setting any of these forces a second round trip to learn the repository's
3681
+ * node id.
3612
3682
  *
3613
3683
  * @public
3614
3684
  */
@@ -3648,7 +3718,7 @@ export declare const transformSecurityAndAnalysis: (value: unknown) => Record<st
3648
3718
  * agree right up until a field is dropped, which is exactly the case anyone
3649
3719
  * reading a dry run is trying to check.
3650
3720
  *
3651
- * Both lists use the **caller's** key names, not the wire names, because the
3721
+ * Every list uses the **caller's** key names, not the wire names, because the
3652
3722
  * audience for them is a person reading a plan against the config they wrote.
3653
3723
  *
3654
3724
  * @public
@@ -3658,10 +3728,25 @@ interface AppliedSettings {
3658
3728
  readonly rest: ReadonlyArray<string>;
3659
3729
  /** Keys sent through the GraphQL mutation, named as the caller supplied them. */
3660
3730
  readonly graphql: ReadonlyArray<string>;
3731
+ /**
3732
+ * Keys neither API accepts, which were **not sent**.
3733
+ *
3734
+ * @remarks
3735
+ * A key that is not a GraphQL-only setting and not in the REST patch's
3736
+ * declared body — a typo such as `has_discussion`, or a setting GitHub has
3737
+ * not described — lands here, as does a key the client's api-version
3738
+ * removed from the patch (`use_squash_pr_title_as_default` under
3739
+ * `2026-03-10` and later; a client pinned to an older version still sends
3740
+ * it). Sending it would be worse than useless: the
3741
+ * REST `PATCH` ignores unknown fields and answers 200, so the key would be
3742
+ * reported applied while the repository never changed. A caller that wants
3743
+ * an unknown key to fail the run checks this list.
3744
+ */
3745
+ readonly ignored: ReadonlyArray<string>;
3661
3746
  }
3662
3747
  /**
3663
- * Read and update a repository's settings, and look up its default branch, node
3664
- * id and owner type.
3748
+ * Read and update a repository's settings and topics, and look up its default
3749
+ * branch, node id and owner type.
3665
3750
  *
3666
3751
  * @public
3667
3752
  */
@@ -3707,30 +3792,58 @@ interface GitHubRepositoryShape {
3707
3792
  * `updateSettings` is the thin, faithfully-typed PATCH and returns what
3708
3793
  * GitHub then reports. This is the **applicator**: it takes an open map,
3709
3794
  * routes each key to whichever API can actually set it, and returns an
3710
- * {@link AppliedSettings} naming the keys that were sent through each.
3795
+ * {@link AppliedSettings} naming the keys that were sent through each and
3796
+ * the keys neither accepts.
3711
3797
  *
3712
3798
  * Three settings — `has_sponsorships`, `has_pull_requests` and
3713
- * `has_discussions` ({@link GRAPHQL_ONLY_SETTINGS}) — are only reachable
3714
- * through GraphQL's `updateRepository`, which addresses a repository by **node
3715
- * id**. So a map touching any of them costs an extra read; a map touching none
3799
+ * `has_discussions` ({@link GRAPHQL_ONLY_SETTINGS}) — are written through
3800
+ * GraphQL's `updateRepository`, which addresses a repository by **node id**;
3801
+ * the first and last are reachable no other way, and GraphQL is preferred
3802
+ * for `has_pull_requests`. So a map touching any of them costs an extra read; a map touching none
3716
3803
  * does not, which is the common case.
3717
3804
  *
3718
3805
  * The map is open by design. GitHub's settings surface is large and moving,
3719
- * and a closed type here would date the package — but it also means a typo is
3720
- * forwarded rather than rejected, so a caller that owns a schema should
3721
- * validate before calling.
3806
+ * and a closed type here would date the package. A key that is neither
3807
+ * GraphQL-only nor in the REST patch's declared body — the key list is
3808
+ * generated from GitHub's OpenAPI description — is not sent and is reported
3809
+ * in `ignored`, rather than forwarded to a `PATCH` that would ignore it and
3810
+ * answer 200. It does not fail the call, so additive GitHub API growth never
3811
+ * breaks a run; a caller that owns a schema should still validate first.
3722
3812
  */
3723
3813
  readonly applySettings: (settings: Record<string, unknown>) => Effect.Effect<AppliedSettings, GitHubError | GitHubGraphQLError, Repo>;
3814
+ /**
3815
+ * The repository's topics, as GitHub stores them.
3816
+ *
3817
+ * @remarks
3818
+ * Reads `GET /repos/{owner}/{repo}/topics`, which answers the whole set in
3819
+ * one object, so there is nothing to paginate. GitHub stores every topic
3820
+ * lowercased, so this is the value to compare a desired set against.
3821
+ */
3822
+ readonly topics: Effect.Effect<ReadonlyArray<string>, GitHubError, Repo>;
3823
+ /**
3824
+ * Replace the repository's whole topic set, and return the set GitHub stored.
3825
+ *
3826
+ * @remarks
3827
+ * `PUT /repos/{owner}/{repo}/topics` replaces rather than merges, so `names`
3828
+ * is the complete desired set and an empty array clears every topic.
3829
+ *
3830
+ * **The return value is not `names`.** GitHub lowercases every topic it
3831
+ * stores, so a caller that records what it sent — `Effect`, say — sees drift
3832
+ * on the next read, which answers `effect`. Record the returned array, which
3833
+ * is GitHub's own answer to the write, as the applied state.
3834
+ */
3835
+ readonly setTopics: (names: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<string>, GitHubError, Repo>;
3724
3836
  }
3725
3837
  declare const GitHubRepository_base: Context.ServiceClass<GitHubRepository, "@effected/github/GitHubRepository", GitHubRepositoryShape>;
3726
3838
  /**
3727
3839
  * Read and update a repository's settings, including settings only GraphQL can
3728
- * write, and look up its default branch, node id and owner type.
3840
+ * write, read and replace its topics, and look up its default branch, node id
3841
+ * and owner type.
3729
3842
  *
3730
3843
  * @remarks
3731
3844
  * Provide it with {@link GitHubRepository.layer}, which needs a `GitHubClient`;
3732
- * every member also needs a `Repo` in `R`. `settings`, `defaultBranch`, `nodeId`
3733
- * and `ownerType` are `Effect` values, not functions.
3845
+ * every member also needs a `Repo` in `R`. `settings`, `defaultBranch`, `nodeId`,
3846
+ * `ownerType` and `topics` are `Effect` values, not functions.
3734
3847
  *
3735
3848
  * @example
3736
3849
  * ```ts
@@ -3741,7 +3854,7 @@ declare const GitHubRepository_base: Context.ServiceClass<GitHubRepository, "@ef
3741
3854
  * const repository = yield* GitHubRepository;
3742
3855
  * const branch = yield* repository.defaultBranch;
3743
3856
  * const applied = yield* repository.applySettings({ has_wiki: false, has_discussions: true });
3744
- * return { branch, applied }; // applied.rest, applied.graphql
3857
+ * return { branch, applied }; // applied.rest, applied.graphql, applied.ignored
3745
3858
  * });
3746
3859
  * ```
3747
3860
  *
@@ -3750,7 +3863,7 @@ declare const GitHubRepository_base: Context.ServiceClass<GitHubRepository, "@ef
3750
3863
  export declare class GitHubRepository extends GitHubRepository_base {
3751
3864
  /** The live service, built over a `GitHubClient`. */
3752
3865
  static readonly layer: Layer.Layer<GitHubRepository, never, GitHubClient>;
3753
- /** An in-memory double; unstubbed members die naming themselves. */
3866
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3754
3867
  static readonly makeTest: (overrides?: Partial<GitHubRepositoryShape>) => GitHubRepositoryShape;
3755
3868
  /** {@link GitHubRepository.makeTest} behind a `Layer`. */
3756
3869
  static readonly layerTest: (overrides?: Partial<GitHubRepositoryShape>) => Layer.Layer<GitHubRepository>;
@@ -3880,7 +3993,7 @@ declare const GitTag_base: Context.ServiceClass<GitTag, "@effected/github/GitTag
3880
3993
  export declare class GitTag extends GitTag_base {
3881
3994
  /** The live service, built over a `GitHubClient`. */
3882
3995
  static readonly layer: Layer.Layer<GitTag, never, GitHubClient>;
3883
- /** An in-memory double; unstubbed members die naming themselves. */
3996
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
3884
3997
  static readonly makeTest: (overrides?: Partial<GitTagShape>) => GitTagShape;
3885
3998
  /** {@link GitTag.makeTest} behind a `Layer`. */
3886
3999
  static readonly layerTest: (overrides?: Partial<GitTagShape>) => Layer.Layer<GitTag>;
@@ -3917,7 +4030,27 @@ declare const PullRequestInfo_base: Schema.Class<PullRequestInfo, Schema.Struct<
3917
4030
  readonly mergedAt: Schema.Option<Schema.DateTimeUtcFromString>;
3918
4031
  /** The description, when GitHub sent one. */
3919
4032
  readonly body: Schema.optionalKey<Schema.String>;
3920
- /** The merge commit, once there is one. */
4033
+ /**
4034
+ * The sha of the commit the merge produced; absent until the pull request
4035
+ * has merged.
4036
+ *
4037
+ * @remarks
4038
+ * Read from GraphQL's `PullRequest.mergeCommit.oid`. The REST pull request
4039
+ * object no longer carries `merge_commit_sha` under the api-version this
4040
+ * package pins, so a merged pull request costs one extra GraphQL round trip
4041
+ * per single read (`get`, `update`, `upsert`), and an open or
4042
+ * closed-unmerged one costs nothing. When the REST response does carry the
4043
+ * field (a client pinned to an older api-version), it is used for a merged
4044
+ * pull request and the GraphQL read is skipped.
4045
+ *
4046
+ * **A list read leaves it absent unless asked.** `list` and
4047
+ * `listAssociatedWithCommit` fill it only when called with
4048
+ * `mergeCommits: true`, at one GraphQL call per 100 merged pull requests.
4049
+ *
4050
+ * It is never the speculative test-merge commit GitHub computes for an open
4051
+ * pull request, so `mergeCommitSha === sha` means "this commit is what the
4052
+ * pull request merged as".
4053
+ */
3921
4054
  readonly mergeCommitSha: Schema.optionalKey<Schema.String>;
3922
4055
  }>, {}>;
3923
4056
  /**
@@ -3951,7 +4084,7 @@ interface UpsertedPullRequest {
3951
4084
  */
3952
4085
  interface PullRequestShape {
3953
4086
  /** Read one pull request. Fails `notFound` when it does not exist. */
3954
- readonly get: (number: number) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
4087
+ readonly get: (number: number) => Effect.Effect<PullRequestInfo, GitHubError | GitHubGraphQLError, Repo>;
3955
4088
  /**
3956
4089
  * Open, closed or all pull requests, optionally filtered.
3957
4090
  *
@@ -3968,13 +4101,20 @@ interface PullRequestShape {
3968
4101
  * in the wrong account — the filter then matches nothing, silently. When the
3969
4102
  * head may live in a fork, pass a qualified `owner:ref` built from the source
3970
4103
  * owner rather than from anything this projection carries.
4104
+ *
4105
+ * **`mergeCommitSha` is absent on every result unless `mergeCommits` is
4106
+ * `true`.** The REST list no longer carries it, and filling it costs one
4107
+ * GraphQL call per 100 merged pull requests in the result, so it is opt-in.
4108
+ * Only with the option can this fail with `GitHubGraphQLError`.
3971
4109
  */
3972
4110
  readonly list: (options?: {
3973
4111
  readonly head?: string | undefined;
3974
4112
  readonly base?: string | undefined;
3975
4113
  readonly state?: "open" | "closed" | "all" | undefined;
3976
4114
  readonly page?: PageOptions | undefined;
3977
- }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError, Repo>;
4115
+ /** Fill `mergeCommitSha` on merged results from GraphQL. Defaults to `false`. */
4116
+ readonly mergeCommits?: boolean | undefined;
4117
+ }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError | GitHubGraphQLError, Repo>;
3978
4118
  /**
3979
4119
  * The files a pull request changes.
3980
4120
  *
@@ -3992,10 +4132,17 @@ interface PullRequestShape {
3992
4132
  *
3993
4133
  * @remarks
3994
4134
  * Paginated: pass `page` to bound the walk.
4135
+ *
4136
+ * **`mergeCommitSha` is absent on every result unless `mergeCommits` is
4137
+ * `true`**, at one GraphQL call per 100 merged pull requests — so a caller
4138
+ * matching `sha` against the merge commit passes it. Only with the option
4139
+ * can this fail with `GitHubGraphQLError`.
3995
4140
  */
3996
4141
  readonly listAssociatedWithCommit: (sha: string, options?: {
3997
4142
  readonly page?: PageOptions | undefined;
3998
- }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError, Repo>;
4143
+ /** Fill `mergeCommitSha` on merged results from GraphQL. Defaults to `false`. */
4144
+ readonly mergeCommits?: boolean | undefined;
4145
+ }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError | GitHubGraphQLError, Repo>;
3999
4146
  /** Open a pull request from `head` into `base`. */
4000
4147
  readonly create: (input: {
4001
4148
  readonly title: string;
@@ -4010,7 +4157,7 @@ interface PullRequestShape {
4010
4157
  readonly body?: string | undefined;
4011
4158
  readonly state?: "open" | "closed" | undefined;
4012
4159
  readonly base?: string | undefined;
4013
- }) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
4160
+ }) => Effect.Effect<PullRequestInfo, GitHubError | GitHubGraphQLError, Repo>;
4014
4161
  /**
4015
4162
  * Update the open pull request for `head`→`base`, or open one.
4016
4163
  *
@@ -4024,7 +4171,7 @@ interface PullRequestShape {
4024
4171
  readonly base: string;
4025
4172
  readonly body?: string | undefined;
4026
4173
  readonly draft?: boolean | undefined;
4027
- }) => Effect.Effect<UpsertedPullRequest, GitHubError, Repo>;
4174
+ }) => Effect.Effect<UpsertedPullRequest, GitHubError | GitHubGraphQLError, Repo>;
4028
4175
  /** Merge a pull request and return the merge commit sha. `method` defaults to GitHub's choice. */
4029
4176
  readonly merge: (number: number, options?: {
4030
4177
  readonly method?: "merge" | "squash" | "rebase" | undefined;
@@ -4079,7 +4226,7 @@ declare const PullRequest_base: Context.ServiceClass<PullRequest, "@effected/git
4079
4226
  export declare class PullRequest extends PullRequest_base {
4080
4227
  /** The live service, built over a `GitHubClient`. */
4081
4228
  static readonly layer: Layer.Layer<PullRequest, never, GitHubClient>;
4082
- /** An in-memory double; unstubbed members die naming themselves. */
4229
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4083
4230
  static readonly makeTest: (overrides?: Partial<PullRequestShape>) => PullRequestShape;
4084
4231
  /** {@link PullRequest.makeTest} behind a `Layer`. */
4085
4232
  static readonly layerTest: (overrides?: Partial<PullRequestShape>) => Layer.Layer<PullRequest>;
@@ -4175,7 +4322,7 @@ export declare class RepositorySecret extends RepositorySecret_base {
4175
4322
  * further down throws at import time with a clean typecheck.
4176
4323
  */
4177
4324
  static readonly layer: Layer.Layer<RepositorySecret, never, GitHubClient>;
4178
- /** An in-memory double; unstubbed members die naming themselves. */
4325
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4179
4326
  static readonly makeTest: (overrides?: Partial<RepositorySecretShape>) => RepositorySecretShape;
4180
4327
  /** {@link RepositorySecret.makeTest} behind a `Layer`. */
4181
4328
  static readonly layerTest: (overrides?: Partial<RepositorySecretShape>) => Layer.Layer<RepositorySecret>;
@@ -4255,7 +4402,7 @@ export declare class RepositorySecurity extends RepositorySecurity_base {
4255
4402
  * further down throws at import time with a clean typecheck.
4256
4403
  */
4257
4404
  static readonly layer: Layer.Layer<RepositorySecurity, never, GitHubClient>;
4258
- /** An in-memory double; unstubbed members die naming themselves. */
4405
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4259
4406
  static readonly makeTest: (overrides?: Partial<RepositorySecurityShape>) => RepositorySecurityShape;
4260
4407
  /** {@link RepositorySecurity.makeTest} behind a `Layer`. */
4261
4408
  static readonly layerTest: (overrides?: Partial<RepositorySecurityShape>) => Layer.Layer<RepositorySecurity>;
@@ -4360,7 +4507,7 @@ export declare class RepositoryVariable extends RepositoryVariable_base {
4360
4507
  * further down throws at import time with a clean typecheck.
4361
4508
  */
4362
4509
  static readonly layer: Layer.Layer<RepositoryVariable, never, GitHubClient>;
4363
- /** An in-memory double; unstubbed members die naming themselves. */
4510
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4364
4511
  static readonly makeTest: (overrides?: Partial<RepositoryVariableShape>) => RepositoryVariableShape;
4365
4512
  /** {@link RepositoryVariable.makeTest} behind a `Layer`. */
4366
4513
  static readonly layerTest: (overrides?: Partial<RepositoryVariableShape>) => Layer.Layer<RepositoryVariable>;
@@ -4490,7 +4637,7 @@ export declare class Ruleset extends Ruleset_base {
4490
4637
  * further down throws at import time with a clean typecheck.
4491
4638
  */
4492
4639
  static readonly layer: Layer.Layer<Ruleset, never, GitHubClient>;
4493
- /** An in-memory double; unstubbed members die naming themselves. */
4640
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4494
4641
  static readonly makeTest: (overrides?: Partial<RulesetShape>) => RulesetShape;
4495
4642
  /** {@link Ruleset.makeTest} behind a `Layer`. */
4496
4643
  static readonly layerTest: (overrides?: Partial<RulesetShape>) => Layer.Layer<Ruleset>;
@@ -4702,15 +4849,21 @@ interface WorkflowDispatchShape {
4702
4849
  * Fire a `workflow_dispatch` event and report the run it created.
4703
4850
  *
4704
4851
  * @remarks
4705
- * Sends the same request as {@link WorkflowDispatchShape.dispatch} with
4706
- * `return_run_details: true`. GitHub then answers 200 with the run's id and
4707
- * URLs, which arrive as `Option.some` of a {@link DispatchedRun}; a 200 body
4708
- * that does not have that shape fails with a `decode` `GitHubError`.
4709
- *
4710
- * A 204 with no body is `Option.none()`. That is what a GitHub Enterprise
4711
- * Server predating the field answers — it ignores `return_run_details` and
4712
- * still dispatches — so it is **not a failure**: the workflow was dispatched,
4713
- * the server just did not say which run it created.
4852
+ * Sends the same request as {@link WorkflowDispatchShape.dispatch}. Under
4853
+ * the api-version the client pins by default, GitHub answers every dispatch
4854
+ * with 200 and the run's id and URLs, which arrive as `Option.some` of a
4855
+ * {@link DispatchedRun}; a 200 body that does not have that shape fails with
4856
+ * a `decode` `GitHubError`.
4857
+ *
4858
+ * A 204 with no body is `Option.none()`. That is what an older api-version
4859
+ * answers when it does not report the run — a GitHub Enterprise Server that
4860
+ * predates the field, say — and it is **not a failure**: the workflow was
4861
+ * dispatched, the server just did not say which run it created.
4862
+ *
4863
+ * Older api-versions report the run only when asked, so a client pinned
4864
+ * before `2026-03-10` (`GitHubClientShape.apiVersion`) sends
4865
+ * `return_run_details: true`; from `2026-03-10` on the flag is removed from
4866
+ * the request and is not sent.
4714
4867
  *
4715
4868
  * Under `GitHubClient.layerFixture`, stub the 204 the way every other
4716
4869
  * no-body route is stubbed: answer the dispatch route with `null`. `""`
@@ -4760,8 +4913,8 @@ interface WorkflowDispatchShape {
4760
4913
  *
4761
4914
  * The run is identified by {@link WorkflowDispatchShape.dispatchWithRun}:
4762
4915
  * when GitHub reports the run it created, exactly that run is polled, so
4763
- * concurrent dispatches cannot be confused. When it does not (a 204 from a
4764
- * GitHub Enterprise Server predating `return_run_details`), the run is found
4916
+ * concurrent dispatches cannot be confused. When it does not (a 204 from an
4917
+ * older api-version), the run is found
4765
4918
  * instead by branch, creation time and workflow path — and on that fallback
4766
4919
  * alone, concurrent dispatches of the same workflow on the same ref can be
4767
4920
  * confused.
@@ -4801,7 +4954,7 @@ declare const WorkflowDispatch_base: Context.ServiceClass<WorkflowDispatch, "@ef
4801
4954
  export declare class WorkflowDispatch extends WorkflowDispatch_base {
4802
4955
  /** The live service, built over a `GitHubClient`. */
4803
4956
  static readonly layer: Layer.Layer<WorkflowDispatch, never, GitHubClient>;
4804
- /** An in-memory double; unstubbed members die naming themselves. */
4957
+ /** An in-memory double; an unstubbed member dies when run, naming itself. */
4805
4958
  static readonly makeTest: (overrides?: Partial<WorkflowDispatchShape>) => WorkflowDispatchShape;
4806
4959
  /** {@link WorkflowDispatch.makeTest} behind a `Layer`. */
4807
4960
  static readonly layerTest: (overrides?: Partial<WorkflowDispatchShape>) => Layer.Layer<WorkflowDispatch>;