@gitkraken/core-gitlens 0.9.3 → 0.9.5

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.
Files changed (160) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/dist/git/models/issue.d.ts +25 -2
  3. package/dist/git/models/issue.js +3 -1
  4. package/dist/git/models/issue.js.map +1 -1
  5. package/dist/git/models/pullRequest.d.ts +55 -5
  6. package/dist/git/models/pullRequest.js +5 -1
  7. package/dist/git/models/pullRequest.js.map +1 -1
  8. package/dist/git/utils/issue.utils.d.ts +4 -0
  9. package/dist/git/utils/issue.utils.js +4 -0
  10. package/dist/git/utils/issue.utils.js.map +1 -1
  11. package/dist/git/utils/pullRequest.utils.d.ts +4 -0
  12. package/dist/git/utils/pullRequest.utils.js +8 -0
  13. package/dist/git/utils/pullRequest.utils.js.map +1 -1
  14. package/dist/plus/git-github/api/github.d.ts +64 -4
  15. package/dist/plus/git-github/api/github.js +232 -15
  16. package/dist/plus/git-github/api/github.js.map +1 -1
  17. package/dist/plus/git-github/models.d.ts +48 -6
  18. package/dist/plus/git-github/models.js +11 -10
  19. package/dist/plus/git-github/models.js.map +1 -1
  20. package/dist/plus/integrations/fieldPresence.d.ts +75 -0
  21. package/dist/plus/integrations/fieldPresence.js +381 -0
  22. package/dist/plus/integrations/fieldPresence.js.map +1 -0
  23. package/dist/plus/integrations/index.d.ts +6 -4
  24. package/dist/plus/integrations/index.js +2 -1
  25. package/dist/plus/integrations/index.js.map +1 -1
  26. package/dist/plus/integrations/integrationService.d.ts +13 -4
  27. package/dist/plus/integrations/integrationService.js.map +1 -1
  28. package/dist/plus/integrations/manager.d.ts +62 -7
  29. package/dist/plus/integrations/models/gitHostIntegration.d.ts +103 -9
  30. package/dist/plus/integrations/models/gitHostIntegration.js +116 -5
  31. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  32. package/dist/plus/integrations/models/integration.d.ts +91 -4
  33. package/dist/plus/integrations/models/integration.js +56 -7
  34. package/dist/plus/integrations/models/integration.js.map +1 -1
  35. package/dist/plus/integrations/models/issueReads.d.ts +14 -0
  36. package/dist/plus/integrations/models/issuesIntegration.d.ts +44 -3
  37. package/dist/plus/integrations/models/issuesIntegration.js +51 -1
  38. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  39. package/dist/plus/integrations/providers/azure/azure.js +3 -3
  40. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  41. package/dist/plus/integrations/providers/azure/models.d.ts +36 -4
  42. package/dist/plus/integrations/providers/azure/models.js +118 -8
  43. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  44. package/dist/plus/integrations/providers/azureDevOps.d.ts +102 -5
  45. package/dist/plus/integrations/providers/azureDevOps.js +264 -45
  46. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  47. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +30 -6
  48. package/dist/plus/integrations/providers/azureDevOpsServer.js +82 -21
  49. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  50. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +21 -1
  51. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +74 -10
  52. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  53. package/dist/plus/integrations/providers/bitbucket/models.d.ts +45 -8
  54. package/dist/plus/integrations/providers/bitbucket/models.js +32 -9
  55. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  56. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +2 -6
  57. package/dist/plus/integrations/providers/bitbucket-server/models.js +1 -3
  58. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
  59. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +3 -1
  60. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +4 -1
  61. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  62. package/dist/plus/integrations/providers/bitbucket-server.d.ts +2 -2
  63. package/dist/plus/integrations/providers/bitbucket-server.js +7 -5
  64. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  65. package/dist/plus/integrations/providers/bitbucket.d.ts +22 -2
  66. package/dist/plus/integrations/providers/bitbucket.js +29 -6
  67. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  68. package/dist/plus/integrations/providers/github.d.ts +40 -3
  69. package/dist/plus/integrations/providers/github.js +133 -11
  70. package/dist/plus/integrations/providers/github.js.map +1 -1
  71. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +34 -1
  72. package/dist/plus/integrations/providers/gitlab/gitlab.js +118 -4
  73. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  74. package/dist/plus/integrations/providers/gitlab/models.d.ts +70 -5
  75. package/dist/plus/integrations/providers/gitlab/models.js +106 -13
  76. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  77. package/dist/plus/integrations/providers/gitlab.d.ts +31 -2
  78. package/dist/plus/integrations/providers/gitlab.js +48 -8
  79. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  80. package/dist/plus/integrations/providers/jira-server.d.ts +3 -2
  81. package/dist/plus/integrations/providers/jira-server.js +18 -9
  82. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  83. package/dist/plus/integrations/providers/jira.d.ts +26 -2
  84. package/dist/plus/integrations/providers/jira.js +120 -9
  85. package/dist/plus/integrations/providers/jira.js.map +1 -1
  86. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +79 -0
  87. package/dist/plus/integrations/providers/jiraIssueByKey.js +58 -7
  88. package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
  89. package/dist/plus/integrations/providers/linear.d.ts +19 -1
  90. package/dist/plus/integrations/providers/linear.js +105 -7
  91. package/dist/plus/integrations/providers/linear.js.map +1 -1
  92. package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +42 -0
  93. package/dist/plus/integrations/providers/linearIssuesEtag.js +94 -0
  94. package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -0
  95. package/dist/plus/integrations/providers/models.d.ts +70 -8
  96. package/dist/plus/integrations/providers/models.js +59 -21
  97. package/dist/plus/integrations/providers/models.js.map +1 -1
  98. package/dist/plus/integrations/providers/providerErrors.js +8 -1
  99. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  100. package/dist/plus/integrations/providers/providersApi.d.ts +70 -4
  101. package/dist/plus/integrations/providers/providersApi.js +148 -4
  102. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  103. package/dist/plus/integrations/providers/pullRequestReviews.d.ts +13 -0
  104. package/dist/plus/integrations/providers/pullRequestReviews.js +30 -6
  105. package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -1
  106. package/dist/plus/integrations/providers/trello.js +11 -7
  107. package/dist/plus/integrations/providers/trello.js.map +1 -1
  108. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +11 -0
  109. package/dist/plus/integrations/providers/utils/providerPaging.js +47 -1
  110. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  111. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  112. package/dist/plus/integrations/reads/batchEtags.d.ts +69 -0
  113. package/dist/plus/integrations/reads/batchEtags.js +114 -0
  114. package/dist/plus/integrations/reads/batchEtags.js.map +1 -0
  115. package/dist/plus/integrations/reads/counts.js +2 -2
  116. package/dist/plus/integrations/reads/counts.js.map +1 -1
  117. package/dist/plus/integrations/reads/currentAccount.js +2 -2
  118. package/dist/plus/integrations/reads/currentAccount.js.map +1 -1
  119. package/dist/plus/integrations/reads/cursors.d.ts +8 -0
  120. package/dist/plus/integrations/reads/cursors.js +5 -3
  121. package/dist/plus/integrations/reads/cursors.js.map +1 -1
  122. package/dist/plus/integrations/reads/drains.d.ts +13 -4
  123. package/dist/plus/integrations/reads/drains.js +29 -5
  124. package/dist/plus/integrations/reads/drains.js.map +1 -1
  125. package/dist/plus/integrations/reads/etag.d.ts +26 -0
  126. package/dist/plus/integrations/reads/etag.js +108 -0
  127. package/dist/plus/integrations/reads/etag.js.map +1 -0
  128. package/dist/plus/integrations/reads/filters.d.ts +8 -0
  129. package/dist/plus/integrations/reads/filters.js +2 -1
  130. package/dist/plus/integrations/reads/filters.js.map +1 -1
  131. package/dist/plus/integrations/reads/hierarchy.js +3 -3
  132. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  133. package/dist/plus/integrations/reads/issueBatch.d.ts +47 -16
  134. package/dist/plus/integrations/reads/issueBatch.js +55 -87
  135. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  136. package/dist/plus/integrations/reads/issueTracker.d.ts +10 -2
  137. package/dist/plus/integrations/reads/issueTracker.js +23 -6
  138. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  139. package/dist/plus/integrations/reads/issues.d.ts +1 -1
  140. package/dist/plus/integrations/reads/issues.js +4 -4
  141. package/dist/plus/integrations/reads/issues.js.map +1 -1
  142. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +44 -6
  143. package/dist/plus/integrations/reads/pullRequestBatch.js +31 -34
  144. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -1
  145. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +5 -2
  146. package/dist/plus/integrations/reads/pullRequestBranches.js +4 -3
  147. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
  148. package/dist/plus/integrations/reads/pullRequests.js +8 -4
  149. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  150. package/dist/plus/integrations/reads/sweeps.js +8 -4
  151. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  152. package/dist/plus/integrations/reads/warnings.d.ts +23 -8
  153. package/dist/plus/integrations/reads/warnings.js +43 -19
  154. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  155. package/dist/plus/integrations/results.d.ts +12 -4
  156. package/dist/plus/integrations/results.js +2 -0
  157. package/dist/plus/integrations/results.js.map +1 -1
  158. package/docs/integrations.md +389 -23
  159. package/docs/kepler-read-api-parity.md +16 -2
  160. package/package.json +2 -2
@@ -1,11 +1,12 @@
1
1
  import { Event } from "../../utils/event.js";
2
- import { IssueSearchCriteria, IssueShape, IssueSorting } from "../../git/models/issue.js";
2
+ import { IssueSearchCriteria, IssueShape, IssueSorting, IssueStateFilter } from "../../git/models/issue.js";
3
3
  import { PullRequestFilter, PullRequestSearchCriteria, PullRequestShape, PullRequestStateFilter } from "../../git/models/pullRequest.js";
4
4
  import { ConfiguredIntegrationDescriptor } from "./authentication/models.js";
5
5
  import { IntegrationIds } from "./constants.js";
6
6
  import { ConfiguredIntegrationsChangeEvent } from "./authentication/configuredIntegrationService.js";
7
- import { IssueFilter } from "./providerFilters.js";
8
7
  import { ConnectionStateChangeEvent, ProviderBroadenResult, ProviderOrganization, ProviderPagedResult, ProviderRepositoryShape, ProviderResult, ProviderSweepResult, ResolveRepositoryResult } from "./results.js";
8
+ import { IssueFilter } from "./providerFilters.js";
9
+ import { IssueEtagInclude, PullRequestEtagInclude } from "./models/integration.js";
9
10
  import { IssueCountResult, IssueCountScope, PullRequestCountResult, PullRequestCountScope } from "./reads/counts.js";
10
11
  import { CurrentAccountResult } from "./reads/currentAccount.js";
11
12
  import { SupportedFilters } from "./reads/filters.js";
@@ -156,6 +157,12 @@ type PullRequestSweepCommonOptions = {
156
157
  */
157
158
  includeReviews?: boolean;
158
159
  forceSync?: boolean;
160
+ /**
161
+ * Page budget per provider. A stop at this budget with a resumable cursor is reported as
162
+ * `pagination-incomplete` with `recovery: 'page-budget'`. A part no budget reaches is reported beside it
163
+ * with `recovery: 'none'`: a `provider-limit` omission when the reported match count exceeds the provider's
164
+ * known result limit.
165
+ */
159
166
  maxPages?: number;
160
167
  /**
161
168
  * Fired once per target as it settles, for host-side per-provider attribution.
@@ -623,6 +630,16 @@ export interface IntegrationManager {
623
630
  * outright — Bitbucket because it has no issues, Trello because its single-issue read can fall back to a capped
624
631
  * board scan, which cannot prove an absence.
625
632
  *
633
+ * Change detection: every found row carries an opaque `etag`; send it back on the target and, where the host has a
634
+ * cheap check (GitHub/GHE, GitLab, Azure DevOps, Jira Cloud and Linear so far), an issue whose etag still matches comes
635
+ * back `{ key, unchanged: true, etag }` without being read again. That costs up to three integration calls instead
636
+ * of one — the cheap check, a full read of the targets with no etag started alongside it, and a full read of the
637
+ * ones that changed — and still one when no target carries an etag. `etagIncludes: ['reactions']` widens the etag
638
+ * to the thumbs-up count, which a host changes without moving the update time; only GitHub/GHE and GitLab rows
639
+ * carry a real count, so it widens nothing elsewhere. A cheap check that fails falls through to the full read,
640
+ * except on an auth, rate-limit or connection failure, which drops its targets with that warning. See
641
+ * {@link IssueBatchResult}.
642
+ *
626
643
  * A self-managed tracker (Jira Data Center) never falls back to the primary connection, unlike the paged reads:
627
644
  * the call is refused unless `domain` names a host or `connectionId` a configured connection that has one, and
628
645
  * every target's `resourceId` must name the host the read resolved to. Two self-hosted instances routinely issue
@@ -638,6 +655,12 @@ export interface IntegrationManager {
638
655
  * for a self-managed tracker unless `connectionId` names a configured host — see above.
639
656
  */
640
657
  domain?: string;
658
+ /**
659
+ * Widens every etag to the listed inputs; order and repeats don't matter, and an unknown value refuses the
660
+ * whole call. `'reactions'` is the thumbs-up count, and costs its field in the cheap check on GitHub/GHE and
661
+ * GitLab. Changes only which etag is computed (and the cheap check's selection); the full read is the same.
662
+ */
663
+ etagIncludes?: readonly IssueEtagInclude[];
641
664
  }): Promise<ProviderResult<IssueBatchResult>>;
642
665
  /**
643
666
  * Resolves several pull requests BY COORDINATE — `(owner, repo, number)`, plus `project` on Azure DevOps — in
@@ -663,6 +686,19 @@ export interface IntegrationManager {
663
686
  * Request cost: GitHub/GHE resolve up to 25 targets per request (one aliased GraphQL document). Every other
664
687
  * host costs one request per target, run with bounded concurrency; GitLab spends a second request to confirm a
665
688
  * miss, and Azure DevOps one more per target (two for a fork) to fill clone URLs.
689
+ *
690
+ * Change detection: every found row carries an opaque `etag`; send it back on the target and, where the host has a
691
+ * cheap check (GitHub/GHE, a minimal aliased document; GitLab, one minimal request per project; Azure DevOps, one
692
+ * request per target without the clone URL reads, which fingerprints the title, description, target branch and
693
+ * reviewers as Azure DevOps reports no update time, but stays blind to comments; Bitbucket Cloud, one list request
694
+ * per repository per 50 pull requests), a pull request whose etag still matches comes back `{ key, unchanged: true,
695
+ * etag }` without being read again. That costs up to three integration calls instead of one — the cheap check, a
696
+ * full read of the targets with no etag started alongside it, and a full read of the ones that changed — and still
697
+ * one when no target carries an etag.
698
+ * `etagIncludes` widens the etag to the listed inputs (mergeability, review decision, check rollup), which a host
699
+ * changes without moving the update time and each of which costs its own fields in the cheap check (the review
700
+ * decision costs the most). A cheap check that fails falls through to the full read, except on an auth, rate-limit
701
+ * or connection failure, which drops its targets with that warning. See {@link PullRequestBatchResult}.
666
702
  */
667
703
  getPullRequestsBatch(options: {
668
704
  providerId: IntegrationIds;
@@ -671,6 +707,13 @@ export interface IntegrationManager {
671
707
  connectionId?: string;
672
708
  /** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
673
709
  domain?: string;
710
+ /**
711
+ * Widens every etag to the listed inputs; order and repeats don't matter, and an unknown value refuses the
712
+ * whole call. Each entry widens the etag to one input a host changes without moving the update time, and
713
+ * costs its own fields in the cheap check; `'checks'` is the check rollup. Changes only which etag is
714
+ * computed (and the cheap check's selection); the full read is the same.
715
+ */
716
+ etagIncludes?: readonly PullRequestEtagInclude[];
674
717
  }): Promise<ProviderResult<PullRequestBatchResult>>;
675
718
  /**
676
719
  * Finds, for each branch, every pull request whose head is that branch — in any state (open, closed or merged),
@@ -682,10 +725,14 @@ export interface IntegrationManager {
682
725
  * branch in a fork, `headOwner` (the base repository's own owner, or none, means the base repository). A pull
683
726
  * request matches only when its head repository is the right one — the base repository itself, or the fork
684
727
  * `headOwner` owns — so a `main` in the base repository never claims every fork's `main`. The match is on the
685
- * head branch NAME, so a merged pull request whose branch was since deleted is still found.
728
+ * head branch NAME, so a merged pull request whose branch was since deleted is still found, and a fork is matched
729
+ * by its owner, so one whose fork was since deleted still matches that `headOwner`.
686
730
  *
687
731
  * Same result contract as {@link getPullRequestsBatch}, echoed under the caller's own `key`:
688
- * - `{ key, pullRequests: [...] }` — found. `truncated` means more may match than were returned.
732
+ * - `{ key, pullRequests: [...] }` — found. `truncated` means a pull request that wasn't returned could still
733
+ * match. One exception on GitHub/GHE: on a branch name more forks share than the first request returned, a
734
+ * pull request from a since-deleted fork that request didn't return can't be found at all, so it can be
735
+ * missing from an answer, even an empty one, that isn't `truncated`.
689
736
  * - `{ key, pullRequests: [] }` with no `truncated` — PROVEN NONE: the host answered and nothing matched, or the
690
737
  * base repository doesn't exist or isn't visible to this connection. Safe to cache.
691
738
  * - No item for a key, with `fetchFailed` and a warning — the read could not check. Never treat that as none.
@@ -695,9 +742,12 @@ export interface IntegrationManager {
695
742
  * looks the branch ref up and so answers "none" once a merged branch is deleted. The caller owns caching.
696
743
  *
697
744
  * Request cost: GitHub/GHE answer up to 25 targets per request (one aliased GraphQL document, fetching up to 10
698
- * full pull requests per target). Every other host costs one request per target, run with bounded concurrency;
699
- * GitLab and Azure DevOps then resolve each matched pull request — typically 0–1 per branch — through
700
- * {@link getPullRequestsBatch}'s own read, at that read's cost, so their rows are exactly its rows. Rows carry
745
+ * full pull requests per target). That document matches the branch name across every fork, so a target whose
746
+ * name more forks share than it returned costs one more REST request filtered by head owner, and a match only
747
+ * that request found is resolved through {@link getPullRequestsBatch}'s own read, so its row is identical to the
748
+ * others; the answer is the union of both requests' matches. Every other host costs one request per target, run
749
+ * with bounded concurrency; GitLab and Azure DevOps then resolve each matched pull request — typically 0–1 per
750
+ * branch — through {@link getPullRequestsBatch}'s own read, at that read's cost, so their rows are exactly its rows. Rows carry
701
751
  * the list reads' fields on GitHub/GHE and Bitbucket Data Center and Bitbucket Cloud's by-id read's on
702
752
  * Bitbucket Cloud. A `headOwner` naming another owner is refused on Bitbucket Data Center and Azure DevOps,
703
753
  * where a fork can't be found by its owner.
@@ -751,6 +801,11 @@ export interface IntegrationManager {
751
801
  * full, so which projects a round covers doesn't depend on how their issues are ordered.
752
802
  */
753
803
  sort?: IssueSorting;
804
+ /**
805
+ * Which issue states to read. Omitted reads open issues. `'closed'`/`'all'` need
806
+ * `getSupportedFilters().issueStates` and are refused otherwise (warning + `fetchFailed`).
807
+ */
808
+ state?: IssueStateFilter;
754
809
  forceSync?: boolean;
755
810
  page?: number;
756
811
  /**
@@ -12,9 +12,9 @@ import { IntegrationIds } from "../constants.js";
12
12
  import { ProviderOrganization } from "../results.js";
13
13
  import { ProviderScopeFailure } from "../collectionMetadata.js";
14
14
  import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "./pullRequestReads.js";
15
- import { MyIssuesForReposOptions, ProviderIssueSearchPage, ProviderSearchCount } from "./issueReads.js";
16
- import { BatchSlot, IntegrationBase, IntegrationResult, IntegrationType } from "./integration.js";
17
15
  import { ProviderApiPagedResult, ProviderHierarchyResult, ProviderIssue, ProviderPullRequest, ProviderRepoInput, ProviderReposInput, ProviderRepository } from "../providers/models.js";
16
+ import { MyIssuesForReposOptions, ProviderIssueSearchPage, ProviderSearchCount } from "./issueReads.js";
17
+ import { BatchSlot, IntegrationBase, IntegrationResult, IntegrationType, IssueEtagFields, IssueEtagInclude, PullRequestEtagFields, PullRequestEtagInclude } from "./integration.js";
18
18
  import { CollectionMetadata } from "@gitkraken/provider-apis";
19
19
  //#region ../plus/integrations/src/models/gitHostIntegration.d.ts
20
20
  /** Read options for {@link GitHostIntegration.searchMyPullRequests} and the provider hook behind it. */
@@ -132,6 +132,14 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
132
132
  * filters and no issue read is answering the same capability question twice, and the two must agree.
133
133
  */
134
134
  get supportsIssues(): boolean;
135
+ /**
136
+ * Whether this host has the cheap check behind the batch pull request read's etags
137
+ * ({@link getProviderPullRequestsEtagFields}). The read decides before calling anything, so a host without one
138
+ * full-reads every target in a single call.
139
+ */
140
+ get supportsPullRequestEtags(): boolean;
141
+ /** The issue twin of {@link supportsPullRequestEtags}: whether {@link getProviderIssuesEtagFields} exists. */
142
+ get supportsIssueEtags(): boolean;
135
143
  /**
136
144
  * Lists the organizations (orgs/workspaces/groups) the current user belongs to on this host.
137
145
  * `truncated === true` means the defensive page-drain backstop stopped before the upstream listing was
@@ -271,8 +279,9 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
271
279
  connectionId?: string;
272
280
  }): Promise<IntegrationResult<PullRequest[] | undefined>>;
273
281
  /**
274
- * Account-wide, user-scoped counterpart of {@link getMyPullRequestsForReposResult} that returns the raw
275
- * `ProviderPullRequest` shape (not the normalized model). Unlike the repo-scoped core, this needs no
282
+ * Account-wide, user-scoped counterpart of {@link getMyPullRequestsForReposResult} that returns each host's raw
283
+ * rows: provider-apis' `ProviderPullRequest`, or GitHub's own `PullRequest`, still to be tagged for the read
284
+ * (`toPullRequestRow`). Unlike the repo-scoped core, this needs no
276
285
  * `repos` — it reads the current user's pull requests across the account, so the ProviderBackend sweep
277
286
  * can drive its Kanban "done" column even when no repositories are supplied (where the repo-scoped core
278
287
  * rejects an empty `repos` input). Recovers thrown errors into `{ error }` so callers surface warnings.
@@ -285,10 +294,11 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
285
294
  filters?: PullRequestFilter[];
286
295
  /** Request only the stable list fields, omitting optional provider enrichments. */
287
296
  summary?: boolean;
288
- }, connectionId?: string): Promise<IntegrationResult<ProviderApiPagedResult<ProviderPullRequest> | undefined>>;
297
+ }, connectionId?: string): Promise<IntegrationResult<ProviderApiPagedResult<ProviderPullRequest | PullRequest> | undefined>>;
289
298
  /**
290
299
  * Reads the current user's pull requests across the whole account using each provider's native "my PRs"
291
- * query, returning the raw provider shape. Without `filters`, the exact user scopes depend on provider-native
300
+ * query, returning its raw rows (see {@link getMyPullRequestsForUserResult}). Without `filters`, the exact user
301
+ * scopes depend on provider-native
292
302
  * behavior and options like `includeReviewRequested`. With `filters`, each member is an exact account-wide OR
293
303
  * relationship validated by the facade before this provider hook is called. Optional: providers that can't
294
304
  * express an account-wide user query leave it undefined and the surface falls back to repo-scoped.
@@ -307,7 +317,17 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
307
317
  includeReviewRequested?: boolean;
308
318
  filters?: PullRequestFilter[];
309
319
  summary?: boolean;
310
- }): Promise<ProviderApiPagedResult<ProviderPullRequest> | undefined>;
320
+ }): Promise<ProviderApiPagedResult<ProviderPullRequest | PullRequest> | undefined>;
321
+ /**
322
+ * The current account as each of `pullRequests` identifies its members, in order: what a raw row's
323
+ * `authoredByMe` and `viewer` are resolved against when it's mapped. Most hosts give a person one id, so every
324
+ * row gets the account itself; Azure DevOps Server answers per collection (see `AzureDevOpsServerIntegration`).
325
+ * Throws only when the account itself can't be read.
326
+ */
327
+ getPullRequestViewers(pullRequests: readonly (ProviderPullRequest | PullRequest)[], connectionId?: string): Promise<({
328
+ id: string;
329
+ username?: string;
330
+ } | undefined)[]>;
311
331
  /**
312
332
  * Parses a Repo/Project paging cursor into its `cursors` bundle. Guards against valid JSON whose
313
333
  * `cursors` is a truthy non-array (e.g. `{ "cursors": "..." }`), which would otherwise bypass the
@@ -423,7 +443,10 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
423
443
  * as a failure against the integration's request-exception budget only when EVERY slot rejected, and not even
424
444
  * then when a credential that checks out was refused by each target's own scope (`settleBatchRefusals`).
425
445
  * Server errors and timeouts on the targets show one notice however many hit one, and cost a strike only as
426
- * part of that whole-call failure (`reportDeferredRequestFailures`), so a call never spends more than one.
446
+ * part of that whole-call failure (`reportDeferredRequestFailures`), so a call spends at most one. A batch read
447
+ * with etags makes up to two such calls (a full read of the targets without an etag, and a full read of the ones
448
+ * that changed), so it can spend two; its cheap check ({@link getIssuesEtagFieldsResult}) spends nothing unless
449
+ * the credential is refused.
427
450
  */
428
451
  getIssuesBatchResult(coordinates: readonly {
429
452
  owner: string;
@@ -458,7 +481,10 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
458
481
  * call counts as a failure against the integration's request-exception budget only when EVERY slot rejected,
459
482
  * and not even then when a credential that checks out was refused by each target's own scope
460
483
  * (`settleBatchRefusals`). Server errors and timeouts on the targets show one notice however many hit one, and
461
- * cost a strike only as part of that whole-call failure (`reportDeferredRequestFailures`).
484
+ * cost a strike only as part of that whole-call failure (`reportDeferredRequestFailures`), so one call spends at
485
+ * most one. A batch read with etags makes up to two such calls (a full read of the targets without an etag, and a
486
+ * full read of the ones that changed), so it can spend two; its cheap check
487
+ * ({@link getPullRequestsEtagFieldsResult}) spends nothing unless the credential is refused.
462
488
  */
463
489
  getPullRequestsBatchResult(coordinates: readonly {
464
490
  owner: string;
@@ -492,6 +518,74 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
492
518
  username?: string;
493
519
  };
494
520
  } | undefined, cancellation?: AbortSignal): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined>;
521
+ /**
522
+ * Result-returning wrapper for the cheap check behind the batch issue read's etags: each coordinate's change
523
+ * state ({@link IssueEtagFields}), plus the inputs of each of `options.etagIncludes`, in ONE call to
524
+ * {@link getProviderIssuesEtagFields}. The slots mean what
525
+ * {@link getIssuesBatchResult}'s do — `fulfilled` with `undefined` is a PROVEN ABSENCE, `rejected` means that
526
+ * target could not be checked.
527
+ *
528
+ * Unlike there, failures other than a refused credential are never the call's: every slot comes back as it
529
+ * settled, even when none answered, so each failed target is judged by its own reason. Such failures spend no
530
+ * strike and show no notice, since the targets they touch fall through to the full read, which does both if the
531
+ * host really is failing, or are dropped as rate-limited or without a connection. Refusals are settled as there
532
+ * (`settleBatchRefusals` with `keepOtherFailures`), and only a refused credential fails the call, on the auth path
533
+ * (`handleEtagCheckException`). The failure budget is reset only when some target answered.
534
+ */
535
+ getIssuesEtagFieldsResult(coordinates: readonly {
536
+ owner: string;
537
+ repo: string;
538
+ number: number;
539
+ project?: string;
540
+ }[], options: {
541
+ etagIncludes?: readonly IssueEtagInclude[];
542
+ }, cancellation?: AbortSignal, connectionId?: string): Promise<IntegrationResult<BatchSlot<IssueEtagFields | undefined>[] | undefined>>;
543
+ /**
544
+ * OPTIONAL: the cheap check behind the batch issue read's etags — one settled slot per input coordinate, in
545
+ * order, holding the issue's change state in the vocabulary {@link getProviderIssuesBatch}'s rows end in, so
546
+ * both reads compute the same etag. Each include's inputs are read only when it is listed in
547
+ * `options.etagIncludes`, and only where a full row carries them. `fulfilled` with `undefined` is a PROVEN
548
+ * ABSENCE, as there. A host implements this only where it is cheaper than the full read.
549
+ */
550
+ protected getProviderIssuesEtagFields?(session: ProviderAuthenticationSession, coordinates: readonly {
551
+ owner: string;
552
+ repo: string;
553
+ number: number;
554
+ project?: string;
555
+ }[], options: {
556
+ etagIncludes?: readonly IssueEtagInclude[];
557
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined>;
558
+ /**
559
+ * Result-returning wrapper for the cheap check behind the batch pull request read's etags: each coordinate's
560
+ * change state ({@link PullRequestEtagFields}), plus the inputs of each of `options.etagIncludes`, in ONE call to
561
+ * {@link getProviderPullRequestsEtagFields}. The slots mean what {@link getPullRequestsBatchResult}'s do —
562
+ * `fulfilled` with `undefined` is a PROVEN ABSENCE, `rejected` means that target could not be checked. Failures
563
+ * are judged and budgeted as in {@link getIssuesEtagFieldsResult}: only a refused credential fails the call or
564
+ * spends a strike.
565
+ */
566
+ getPullRequestsEtagFieldsResult(coordinates: readonly {
567
+ owner: string;
568
+ repo: string;
569
+ number: number;
570
+ project?: string;
571
+ }[], options: {
572
+ etagIncludes?: readonly PullRequestEtagInclude[];
573
+ }, cancellation?: AbortSignal, connectionId?: string): Promise<IntegrationResult<BatchSlot<PullRequestEtagFields | undefined>[] | undefined>>;
574
+ /**
575
+ * OPTIONAL: the cheap check behind the batch pull request read's etags — one settled slot per input coordinate,
576
+ * in order, holding the pull request's change state in the vocabulary {@link getProviderPullRequestsBatch}'s
577
+ * rows end in, after their WHOLE conversion chain, so both reads compute the same etag. Each include's inputs are
578
+ * read only when it is listed in `options.etagIncludes`. `fulfilled` with `undefined` is a PROVEN ABSENCE, as
579
+ * there. A host implements this only where it is cheaper than the full read.
580
+ */
581
+ protected getProviderPullRequestsEtagFields?(session: ProviderAuthenticationSession, coordinates: readonly {
582
+ owner: string;
583
+ repo: string;
584
+ number: number;
585
+ project?: string;
586
+ }[], options: {
587
+ etagIncludes?: readonly PullRequestEtagInclude[];
588
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined>;
495
589
  /**
496
590
  * Result-returning wrapper for the pull-requests-by-branch read: for each target, every pull request whose head
497
591
  * is that branch, in any state, in ONE call to {@link getProviderPullRequestsForBranches}. One settled slot
@@ -212,6 +212,18 @@ var GitHostIntegration = class extends IntegrationBase {
212
212
  return true;
213
213
  }
214
214
  /**
215
+ * Whether this host has the cheap check behind the batch pull request read's etags
216
+ * ({@link getProviderPullRequestsEtagFields}). The read decides before calling anything, so a host without one
217
+ * full-reads every target in a single call.
218
+ */
219
+ get supportsPullRequestEtags() {
220
+ return this.getProviderPullRequestsEtagFields != null;
221
+ }
222
+ /** The issue twin of {@link supportsPullRequestEtags}: whether {@link getProviderIssuesEtagFields} exists. */
223
+ get supportsIssueEtags() {
224
+ return this.getProviderIssuesEtagFields != null;
225
+ }
226
+ /**
215
227
  * Lists the organizations (orgs/workspaces/groups) the current user belongs to on this host.
216
228
  * `truncated === true` means the defensive page-drain backstop stopped before the upstream listing was
217
229
  * exhausted.
@@ -760,7 +772,7 @@ var GitHostIntegration = class extends IntegrationBase {
760
772
  value: void 0,
761
773
  duration: result.duration
762
774
  };
763
- const values = result.value.values.map((issue) => toIssueShape(issue, this)).filter((issue) => issue != null);
775
+ const values = result.value.values.map((issue) => toIssueShape(issue, this, { projection: "repos" })).filter((issue) => issue != null);
764
776
  return {
765
777
  value: {
766
778
  ...result.value,
@@ -1012,8 +1024,9 @@ var GitHostIntegration = class extends IntegrationBase {
1012
1024
  }
1013
1025
  }
1014
1026
  /**
1015
- * Account-wide, user-scoped counterpart of {@link getMyPullRequestsForReposResult} that returns the raw
1016
- * `ProviderPullRequest` shape (not the normalized model). Unlike the repo-scoped core, this needs no
1027
+ * Account-wide, user-scoped counterpart of {@link getMyPullRequestsForReposResult} that returns each host's raw
1028
+ * rows: provider-apis' `ProviderPullRequest`, or GitHub's own `PullRequest`, still to be tagged for the read
1029
+ * (`toPullRequestRow`). Unlike the repo-scoped core, this needs no
1017
1030
  * `repos` — it reads the current user's pull requests across the account, so the ProviderBackend sweep
1018
1031
  * can drive its Kanban "done" column even when no repositories are supplied (where the repo-scoped core
1019
1032
  * rejects an empty `repos` input). Recovers thrown errors into `{ error }` so callers surface warnings.
@@ -1044,6 +1057,20 @@ var GitHostIntegration = class extends IntegrationBase {
1044
1057
  }
1045
1058
  }
1046
1059
  /**
1060
+ * The current account as each of `pullRequests` identifies its members, in order: what a raw row's
1061
+ * `authoredByMe` and `viewer` are resolved against when it's mapped. Most hosts give a person one id, so every
1062
+ * row gets the account itself; Azure DevOps Server answers per collection (see `AzureDevOpsServerIntegration`).
1063
+ * Throws only when the account itself can't be read.
1064
+ */
1065
+ async getPullRequestViewers(pullRequests, connectionId) {
1066
+ const account = await this.getCurrentAccount({ connectionId });
1067
+ const viewer = account != null ? {
1068
+ id: account.id,
1069
+ username: account.username
1070
+ } : void 0;
1071
+ return pullRequests.map(() => viewer);
1072
+ }
1073
+ /**
1047
1074
  * Parses a Repo/Project paging cursor into its `cursors` bundle. Guards against valid JSON whose
1048
1075
  * `cursors` is a truthy non-array (e.g. `{ "cursors": "..." }`), which would otherwise bypass the
1049
1076
  * `?? []` fallback at call sites and flow into `.map()` downstream, throwing instead of degrading to
@@ -1187,7 +1214,10 @@ var GitHostIntegration = class extends IntegrationBase {
1187
1214
  * as a failure against the integration's request-exception budget only when EVERY slot rejected, and not even
1188
1215
  * then when a credential that checks out was refused by each target's own scope (`settleBatchRefusals`).
1189
1216
  * Server errors and timeouts on the targets show one notice however many hit one, and cost a strike only as
1190
- * part of that whole-call failure (`reportDeferredRequestFailures`), so a call never spends more than one.
1217
+ * part of that whole-call failure (`reportDeferredRequestFailures`), so a call spends at most one. A batch read
1218
+ * with etags makes up to two such calls (a full read of the targets without an etag, and a full read of the ones
1219
+ * that changed), so it can spend two; its cheap check ({@link getIssuesEtagFieldsResult}) spends nothing unless
1220
+ * the credential is refused.
1191
1221
  */
1192
1222
  async getIssuesBatchResult(coordinates, cancellation, connectionId) {
1193
1223
  const scope = getScopedLogger();
@@ -1235,7 +1265,10 @@ var GitHostIntegration = class extends IntegrationBase {
1235
1265
  * call counts as a failure against the integration's request-exception budget only when EVERY slot rejected,
1236
1266
  * and not even then when a credential that checks out was refused by each target's own scope
1237
1267
  * (`settleBatchRefusals`). Server errors and timeouts on the targets show one notice however many hit one, and
1238
- * cost a strike only as part of that whole-call failure (`reportDeferredRequestFailures`).
1268
+ * cost a strike only as part of that whole-call failure (`reportDeferredRequestFailures`), so one call spends at
1269
+ * most one. A batch read with etags makes up to two such calls (a full read of the targets without an etag, and a
1270
+ * full read of the ones that changed), so it can spend two; its cheap check
1271
+ * ({@link getPullRequestsEtagFieldsResult}) spends nothing unless the credential is refused.
1239
1272
  */
1240
1273
  async getPullRequestsBatchResult(coordinates, options, cancellation, connectionId) {
1241
1274
  const scope = getScopedLogger();
@@ -1272,6 +1305,84 @@ var GitHostIntegration = class extends IntegrationBase {
1272
1305
  }
1273
1306
  }
1274
1307
  /**
1308
+ * Result-returning wrapper for the cheap check behind the batch issue read's etags: each coordinate's change
1309
+ * state ({@link IssueEtagFields}), plus the inputs of each of `options.etagIncludes`, in ONE call to
1310
+ * {@link getProviderIssuesEtagFields}. The slots mean what
1311
+ * {@link getIssuesBatchResult}'s do — `fulfilled` with `undefined` is a PROVEN ABSENCE, `rejected` means that
1312
+ * target could not be checked.
1313
+ *
1314
+ * Unlike there, failures other than a refused credential are never the call's: every slot comes back as it
1315
+ * settled, even when none answered, so each failed target is judged by its own reason. Such failures spend no
1316
+ * strike and show no notice, since the targets they touch fall through to the full read, which does both if the
1317
+ * host really is failing, or are dropped as rate-limited or without a connection. Refusals are settled as there
1318
+ * (`settleBatchRefusals` with `keepOtherFailures`), and only a refused credential fails the call, on the auth path
1319
+ * (`handleEtagCheckException`). The failure budget is reset only when some target answered.
1320
+ */
1321
+ async getIssuesEtagFieldsResult(coordinates, options, cancellation, connectionId) {
1322
+ const scope = getScopedLogger();
1323
+ const session = await this.resolveReadSession(connectionId, scope);
1324
+ if (session == null) return void 0;
1325
+ const start = performance.now();
1326
+ try {
1327
+ const slots = await this.getProviderIssuesEtagFields?.(session, coordinates, options, cancellation);
1328
+ if (slots == null) return {
1329
+ value: void 0,
1330
+ duration: performance.now() - start
1331
+ };
1332
+ const settled = await this.settleBatchRefusals(session, coordinates, slots, { keepOtherFailures: true });
1333
+ if (slots.some((slot) => slot.status === "fulfilled")) this.resetRequestExceptionCount("getIssuesEtagFields");
1334
+ return {
1335
+ value: settled,
1336
+ duration: performance.now() - start
1337
+ };
1338
+ } catch (ex) {
1339
+ this.handleEtagCheckException("getIssuesEtagFields", ex, {
1340
+ scope,
1341
+ connectionId
1342
+ });
1343
+ return {
1344
+ error: toError(ex),
1345
+ duration: performance.now() - start
1346
+ };
1347
+ }
1348
+ }
1349
+ /**
1350
+ * Result-returning wrapper for the cheap check behind the batch pull request read's etags: each coordinate's
1351
+ * change state ({@link PullRequestEtagFields}), plus the inputs of each of `options.etagIncludes`, in ONE call to
1352
+ * {@link getProviderPullRequestsEtagFields}. The slots mean what {@link getPullRequestsBatchResult}'s do —
1353
+ * `fulfilled` with `undefined` is a PROVEN ABSENCE, `rejected` means that target could not be checked. Failures
1354
+ * are judged and budgeted as in {@link getIssuesEtagFieldsResult}: only a refused credential fails the call or
1355
+ * spends a strike.
1356
+ */
1357
+ async getPullRequestsEtagFieldsResult(coordinates, options, cancellation, connectionId) {
1358
+ const scope = getScopedLogger();
1359
+ const session = await this.resolveReadSession(connectionId, scope);
1360
+ if (session == null) return void 0;
1361
+ const start = performance.now();
1362
+ try {
1363
+ const slots = await this.getProviderPullRequestsEtagFields?.(session, coordinates, options, cancellation);
1364
+ if (slots == null) return {
1365
+ value: void 0,
1366
+ duration: performance.now() - start
1367
+ };
1368
+ const settled = await this.settleBatchRefusals(session, coordinates, slots, { keepOtherFailures: true });
1369
+ if (slots.some((slot) => slot.status === "fulfilled")) this.resetRequestExceptionCount("getPullRequestsEtagFields");
1370
+ return {
1371
+ value: settled,
1372
+ duration: performance.now() - start
1373
+ };
1374
+ } catch (ex) {
1375
+ this.handleEtagCheckException("getPullRequestsEtagFields", ex, {
1376
+ scope,
1377
+ connectionId
1378
+ });
1379
+ return {
1380
+ error: toError(ex),
1381
+ duration: performance.now() - start
1382
+ };
1383
+ }
1384
+ }
1385
+ /**
1275
1386
  * Result-returning wrapper for the pull-requests-by-branch read: for each target, every pull request whose head
1276
1387
  * is that branch, in any state, in ONE call to {@link getProviderPullRequestsForBranches}. One settled slot
1277
1388
  * per target: `fulfilled` with an empty list means the host answered and nothing matched; `rejected` means