@gitkraken/core-gitlens 0.7.0 → 0.7.2

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 (125) hide show
  1. package/CHANGELOG.md +28 -2
  2. package/dist/git/remotes/azure-devops.js +3 -3
  3. package/dist/git/remotes/azure-devops.js.map +1 -1
  4. package/dist/plus/integrations/authentication/configuredIntegrationService.js +9 -2
  5. package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -1
  6. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +1 -1
  7. package/dist/plus/integrations/collectionMetadata.d.ts +48 -3
  8. package/dist/plus/integrations/collectionMetadata.js +138 -8
  9. package/dist/plus/integrations/collectionMetadata.js.map +1 -1
  10. package/dist/plus/integrations/errors.d.ts +3 -1
  11. package/dist/plus/integrations/errors.js +7 -3
  12. package/dist/plus/integrations/errors.js.map +1 -1
  13. package/dist/plus/integrations/index.d.ts +3 -3
  14. package/dist/plus/integrations/index.js.map +1 -1
  15. package/dist/plus/integrations/integrationService.d.ts +35 -1
  16. package/dist/plus/integrations/integrationService.js +90 -43
  17. package/dist/plus/integrations/integrationService.js.map +1 -1
  18. package/dist/plus/integrations/lite.js +5 -4
  19. package/dist/plus/integrations/lite.js.map +1 -1
  20. package/dist/plus/integrations/manager.d.ts +68 -23
  21. package/dist/plus/integrations/models/gitHostIntegration.d.ts +31 -15
  22. package/dist/plus/integrations/models/gitHostIntegration.js +71 -22
  23. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  24. package/dist/plus/integrations/models/integration.d.ts +70 -12
  25. package/dist/plus/integrations/models/integration.js +56 -1
  26. package/dist/plus/integrations/models/integration.js.map +1 -1
  27. package/dist/plus/integrations/models/issueReads.d.ts +17 -0
  28. package/dist/plus/integrations/models/issuesIntegration.js +2 -0
  29. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  30. package/dist/plus/integrations/models/pullRequestReads.d.ts +26 -0
  31. package/dist/plus/integrations/providers/azure/azure.d.ts +66 -1
  32. package/dist/plus/integrations/providers/azure/azure.js +192 -12
  33. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  34. package/dist/plus/integrations/providers/azure/search.d.ts +144 -0
  35. package/dist/plus/integrations/providers/azure/search.js +250 -0
  36. package/dist/plus/integrations/providers/azure/search.js.map +1 -0
  37. package/dist/plus/integrations/providers/azureDevOps.d.ts +73 -36
  38. package/dist/plus/integrations/providers/azureDevOps.js +191 -122
  39. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  40. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +176 -0
  41. package/dist/plus/integrations/providers/azureDevOpsServer.js +560 -0
  42. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -0
  43. package/dist/plus/integrations/providers/bitbucket-server/discovery.d.ts +12 -0
  44. package/dist/plus/integrations/providers/bitbucket-server/discovery.js +128 -0
  45. package/dist/plus/integrations/providers/bitbucket-server/discovery.js.map +1 -0
  46. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +10 -1
  47. package/dist/plus/integrations/providers/bitbucket-server/models.js +3 -2
  48. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
  49. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +58 -0
  50. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +485 -0
  51. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -0
  52. package/dist/plus/integrations/providers/bitbucket-server.d.ts +61 -3
  53. package/dist/plus/integrations/providers/bitbucket-server.js +114 -20
  54. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  55. package/dist/plus/integrations/providers/bitbucket.d.ts +9 -1
  56. package/dist/plus/integrations/providers/bitbucket.js +13 -2
  57. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  58. package/dist/plus/integrations/providers/github.d.ts +6 -6
  59. package/dist/plus/integrations/providers/github.js +35 -34
  60. package/dist/plus/integrations/providers/github.js.map +1 -1
  61. package/dist/plus/integrations/providers/gitlab.d.ts +6 -4
  62. package/dist/plus/integrations/providers/gitlab.js +32 -28
  63. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  64. package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
  65. package/dist/plus/integrations/providers/jira-server.d.ts +9 -0
  66. package/dist/plus/integrations/providers/jira-server.js +15 -7
  67. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  68. package/dist/plus/integrations/providers/jira.d.ts +9 -0
  69. package/dist/plus/integrations/providers/jira.js +14 -2
  70. package/dist/plus/integrations/providers/jira.js.map +1 -1
  71. package/dist/plus/integrations/providers/linear.js +2 -2
  72. package/dist/plus/integrations/providers/models.d.ts +10 -1
  73. package/dist/plus/integrations/providers/models.js +86 -0
  74. package/dist/plus/integrations/providers/models.js.map +1 -1
  75. package/dist/plus/integrations/providers/providersApi.d.ts +10 -0
  76. package/dist/plus/integrations/providers/providersApi.js +18 -3
  77. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  78. package/dist/plus/integrations/providers/utils.d.ts +12 -1
  79. package/dist/plus/integrations/providers/utils.js +36 -6
  80. package/dist/plus/integrations/providers/utils.js.map +1 -1
  81. package/dist/plus/integrations/reads/broaden.js +6 -6
  82. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  83. package/dist/plus/integrations/reads/context.d.ts +1 -1
  84. package/dist/plus/integrations/reads/counts.d.ts +18 -4
  85. package/dist/plus/integrations/reads/counts.js +66 -15
  86. package/dist/plus/integrations/reads/counts.js.map +1 -1
  87. package/dist/plus/integrations/reads/cursors.js +1 -1
  88. package/dist/plus/integrations/reads/drains.d.ts +2 -1
  89. package/dist/plus/integrations/reads/drains.js +1 -1
  90. package/dist/plus/integrations/reads/filters.d.ts +1 -1
  91. package/dist/plus/integrations/reads/filters.js +17 -12
  92. package/dist/plus/integrations/reads/filters.js.map +1 -1
  93. package/dist/plus/integrations/reads/hierarchy.js +2 -2
  94. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  95. package/dist/plus/integrations/reads/hierarchy.utils.js +1 -1
  96. package/dist/plus/integrations/reads/issueBatch.js +1 -1
  97. package/dist/plus/integrations/reads/issueTracker.js +2 -2
  98. package/dist/plus/integrations/reads/issues.js +2 -2
  99. package/dist/plus/integrations/reads/paging.js +1 -1
  100. package/dist/plus/integrations/reads/resolveRepository.d.ts +12 -11
  101. package/dist/plus/integrations/reads/resolveRepository.js +110 -19
  102. package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
  103. package/dist/plus/integrations/reads/searchIssues.js +4 -2
  104. package/dist/plus/integrations/reads/searchIssues.js.map +1 -1
  105. package/dist/plus/integrations/reads/searchPullRequests.js +9 -3
  106. package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
  107. package/dist/plus/integrations/reads/sweeps.js +1 -1
  108. package/dist/plus/integrations/reads/trackerIssue.d.ts +9 -5
  109. package/dist/plus/integrations/reads/trackerIssue.js +15 -9
  110. package/dist/plus/integrations/reads/trackerIssue.js.map +1 -1
  111. package/dist/plus/integrations/reads/warnings.d.ts +6 -2
  112. package/dist/plus/integrations/reads/warnings.js +15 -19
  113. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  114. package/dist/plus/integrations/results.d.ts +84 -6
  115. package/dist/plus/integrations/results.js +9 -2
  116. package/dist/plus/integrations/results.js.map +1 -1
  117. package/dist/plus/integrations/utils/domain.utils.d.ts +19 -0
  118. package/dist/plus/integrations/utils/domain.utils.js +36 -1
  119. package/dist/plus/integrations/utils/domain.utils.js.map +1 -1
  120. package/dist/plus/integrations/utils/integration.utils.d.ts +1 -0
  121. package/dist/plus/integrations/utils/integration.utils.js +12 -1
  122. package/dist/plus/integrations/utils/integration.utils.js.map +1 -1
  123. package/docs/integrations.md +263 -74
  124. package/docs/kepler-read-api-parity.md +19 -6
  125. package/package.json +1 -1
@@ -2,15 +2,18 @@ import { PagedResult } from "../../../utils/paging.js";
2
2
  import { Emitter } from "../../../utils/event.js";
3
3
  import { IssueOrPullRequest, IssueOrPullRequestState, IssueOrPullRequestType } from "../../../git/models/issueOrPullRequest.js";
4
4
  import { Issue, IssueShape } from "../../../git/models/issue.js";
5
- import { PullRequest, PullRequestFilter, PullRequestMergeMethod, PullRequestStateFilter } from "../../../git/models/pullRequest.js";
5
+ import { PullRequest, PullRequestFilter, PullRequestMergeMethod, PullRequestSearchCriteria, PullRequestStateFilter } from "../../../git/models/pullRequest.js";
6
6
  import { Account, UnidentifiedAuthor } from "../../../git/models/author.js";
7
7
  import { DefaultBranch } from "../../../git/models/defaultBranch.js";
8
8
  import { RepositoryMetadata } from "../../../git/models/repositoryMetadata.js";
9
9
  import { AuthenticationSessionLike, ProviderAuthenticationSession } from "../authentication/models.js";
10
10
  import { GitSelfManagedHostIntegrationId } from "../constants.js";
11
+ import { ProviderOrganization } from "../results.js";
12
+ import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "../models/pullRequestReads.js";
11
13
  import { ProvidersApi } from "./providersApi.js";
12
14
  import { GitHostIntegration, SearchMyPullRequestsOptions, SearchPullRequestsOptions } from "../models/gitHostIntegration.js";
13
- import { ProviderPullRequest, ProviderRepository } from "./models.js";
15
+ import "../models/integration.js";
16
+ import { ProviderHierarchyResult, ProviderPullRequest, ProviderRepoInput, ProviderRepository } from "./models.js";
14
17
  import { IntegrationConnectionChangeEvent } from "../integrationService.js";
15
18
  import { IntegrationAuthenticationService } from "../authentication/integrationAuthenticationService.js";
16
19
  import { IntegrationAuthenticationProviderDescriptor } from "../authentication/integrationAuthenticationProvider.js";
@@ -25,7 +28,7 @@ export declare class BitbucketServerIntegration extends GitHostIntegration<GitSe
25
28
  readonly name: string;
26
29
  constructor(ctx: IntegrationServiceContext, authenticationService: IntegrationAuthenticationService, getProvidersApi: () => Promise<ProvidersApi>, didChangeConnection: Emitter<IntegrationConnectionChangeEvent>, _domain: string);
27
30
  get domain(): string;
28
- protected get apiBaseUrl(): string;
31
+ protected apiBaseUrlFor(session: ProviderAuthenticationSession): string;
29
32
  protected mergeProviderPullRequest(session: ProviderAuthenticationSession, pr: PullRequest, options?: {
30
33
  mergeMethod?: PullRequestMergeMethod;
31
34
  }): Promise<boolean>;
@@ -53,8 +56,30 @@ export declare class BitbucketServerIntegration extends GitHostIntegration<GitSe
53
56
  connectionId?: string;
54
57
  }): Promise<ProviderRepository | undefined>;
55
58
  protected getProviderRepositoryMetadata(_session: AuthenticationSessionLike, _repo: BitbucketRepositoryDescriptor, _cancellation?: AbortSignal): Promise<RepositoryMetadata | undefined>;
59
+ /**
60
+ * Accounts by {@link getAccountKey}. One integration serves every installation on its host, and installations
61
+ * mounted at different context paths are different servers whose users differ, even under the same token.
62
+ */
56
63
  private _accounts;
64
+ /** The installation the session's reads address, plus the credential — what decides whose account it is. */
65
+ private getAccountKey;
66
+ /**
67
+ * The account request the account cache would otherwise answer; see `IntegrationBase.validateCredential`. Needed
68
+ * without any discovery cache: a repo-scoped pull request read fans out across its repositories in the SDK with
69
+ * no request to the connection first, so a dead token comes back as one refused repository per request.
70
+ *
71
+ * A project access token never confirms: its bot user authenticates, but `/users` does not list it, so the SDK
72
+ * cannot find the current user and the check proves nothing.
73
+ */
74
+ protected validateCredential(session: ProviderAuthenticationSession): Promise<void>;
57
75
  protected getProviderCurrentAccount(session: ProviderAuthenticationSession): Promise<Account | undefined>;
76
+ protected getProviderOrganizationsForUser(session: ProviderAuthenticationSession): Promise<ProviderHierarchyResult<ProviderOrganization>>;
77
+ protected getProviderRepositoriesForOrg(session: ProviderAuthenticationSession, org: string, options?: {
78
+ cursor?: string;
79
+ }): Promise<ProviderHierarchyResult<ProviderRepository>>;
80
+ protected getProviderRepositoriesForUser(session: ProviderAuthenticationSession, options?: {
81
+ cursor?: string;
82
+ }): Promise<ProviderHierarchyResult<ProviderRepository>>;
58
83
  protected searchProviderMyPullRequests(session: ProviderAuthenticationSession, repos?: BitbucketRepositoryDescriptor[], _cancellation?: AbortSignal, options?: SearchMyPullRequestsOptions): Promise<PullRequest[] | undefined>;
59
84
  protected getProviderMyPullRequestsForUser(session: ProviderAuthenticationSession, options?: {
60
85
  state?: PullRequestStateFilter[];
@@ -62,6 +87,39 @@ export declare class BitbucketServerIntegration extends GitHostIntegration<GitSe
62
87
  filters?: PullRequestFilter[];
63
88
  }): Promise<PagedResult<ProviderPullRequest> | undefined>;
64
89
  protected searchProviderPullRequests(session: ProviderAuthenticationSession, searchQuery: string, repos?: BitbucketRepositoryDescriptor[], cancellation?: AbortSignal, options?: SearchPullRequestsOptions): Promise<PullRequest[] | undefined>;
90
+ /**
91
+ * The filtered pull-request search, read by this module's own requests rather than the SDK's: the SDK's list
92
+ * reads carry no text, draft or participant-status filter and no per-facet continuation. Every request goes to
93
+ * the session's own address, context path included, so one connection's cursor can't be replayed on another.
94
+ */
95
+ protected searchProviderPullRequestsPage(session: ProviderAuthenticationSession, options: {
96
+ repos?: ProviderRepoInput[];
97
+ org?: string;
98
+ criteria?: PullRequestSearchCriteria;
99
+ cursor?: string;
100
+ pageSize?: number;
101
+ summary?: boolean;
102
+ }, cancellation?: AbortSignal): Promise<ProviderPullRequestSearchPage | undefined>;
103
+ /**
104
+ * Counts each scope by reading it, since Bitbucket Data Center has neither a count query nor a total on its
105
+ * pages. The facade hands over one scope per call and runs those calls concurrently (see `countPullRequests`),
106
+ * so scopes here are counted one after another rather than multiplying that concurrency.
107
+ */
108
+ protected countProviderPullRequests(session: ProviderAuthenticationSession, scopes: readonly {
109
+ repos?: ProviderRepoInput[];
110
+ org?: string;
111
+ criteria?: PullRequestSearchCriteria;
112
+ }[], cancellation?: AbortSignal): Promise<ProviderPullRequestCount[] | undefined>;
113
+ /**
114
+ * The session's own user, which a relationship facet filters by. Resolved per session rather than from the
115
+ * primary connection, so a read pinned to one account never filters by another's identity; an account that
116
+ * can't be resolved refuses the read instead of widening it to everyone's pull requests.
117
+ *
118
+ * The lookup is raced against `cancellation` so a cancelled read settles at once. The SDK's current-user read
119
+ * takes no signal, so the request itself runs on; its answer still lands in the per-token account cache, so a
120
+ * cold lookup a cancellation abandoned isn't wasted on the next read.
121
+ */
122
+ private getSearchUser;
65
123
  private getWorkspaceRepoInputs;
66
124
  protected searchProviderMyIssues(_session: AuthenticationSessionLike, _repos?: BitbucketRepositoryDescriptor[]): Promise<IssueShape[] | undefined>;
67
125
  /**
@@ -1,11 +1,13 @@
1
- import { CancellationError } from "../../../utils/cancellation.js";
1
+ import { CancellationError, raceWithSignal } from "../../../utils/cancellation.js";
2
2
  import { nonnullSettled } from "../../../utils/promise.js";
3
+ import { AuthenticationError } from "../../../git/errors.js";
3
4
  import { md5 } from "../../../utils/crypto.js";
4
5
  import "../../../git/models/pullRequest.js";
6
+ import { getResponseHeader } from "../errors.js";
5
7
  import "../constants.js";
6
8
  import { toTokenWithInfo } from "../authentication/models.js";
7
- import { ProviderPullRequestReviewState, fromProviderPullRequest, providerPullRequestMatchesSearch, providersMetadata, toProviderPullRequestStates } from "./models.js";
8
9
  import { collectProviderPagedResult, flatSettledOrThrow, parsePageCursor, toPageCursor } from "./utils/providerPaging.js";
10
+ import { ProviderPullRequestReviewState, fromProviderPullRequest, providerPullRequestMatchesSearch, providersMetadata, toProviderPullRequestStates } from "./models.js";
9
11
  import { GitHostIntegration } from "../models/gitHostIntegration.js";
10
12
  //#region ../plus/integrations/src/providers/bitbucket-server.ts
11
13
  const metadata = providersMetadata["bitbucket-server"];
@@ -26,17 +28,17 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
26
28
  get domain() {
27
29
  return this._domain;
28
30
  }
29
- get apiBaseUrl() {
30
- return `${this._session?.protocol ?? "https:"}//${this.domain}/rest/api/1.0`;
31
+ apiBaseUrlFor(session) {
32
+ return this.getSelfManagedApiBaseUrl(session);
31
33
  }
32
34
  async mergeProviderPullRequest(session, pr, options) {
33
35
  return (await this.getProvidersApi()).mergePullRequest(toTokenWithInfo(this.id, session), pr, {
34
36
  mergeMethod: options?.mergeMethod,
35
- baseUrl: this.apiBaseUrl
37
+ baseUrl: this.apiBaseUrlFor(session)
36
38
  });
37
39
  }
38
40
  async getProviderAccountForCommit(session, repo, rev, options) {
39
- return (await this.authenticationService.apis.bitbucket)?.getServerAccountForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, this.apiBaseUrl, { avatarSize: options?.avatarSize });
41
+ return (await this.authenticationService.apis.bitbucket)?.getServerAccountForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, this.apiBaseUrlFor(session), { avatarSize: options?.avatarSize });
40
42
  }
41
43
  async getProviderAccountForEmail(_session, _repo, _email, _options) {
42
44
  return Promise.resolve(void 0);
@@ -46,33 +48,57 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
46
48
  }
47
49
  async getProviderLinkedIssueOrPullRequest(session, repo, { id }, type) {
48
50
  if (type === "issue") return;
49
- return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestById(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, id, this.apiBaseUrl);
51
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestById(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, id, this.apiBaseUrlFor(session));
50
52
  }
51
53
  async getProviderIssue(_session, _repo, _id) {
52
54
  return Promise.resolve(void 0);
53
55
  }
54
56
  async getProviderPullRequestForBranch(session, repo, branch, _options) {
55
- return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForBranch(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, branch, this.apiBaseUrl);
57
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForBranch(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, branch, this.apiBaseUrlFor(session));
56
58
  }
57
59
  async getProviderPullRequestForCommit(session, repo, rev) {
58
- return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, this.apiBaseUrl);
60
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, this.apiBaseUrlFor(session));
59
61
  }
60
62
  async getRepoInfo(repo) {
61
63
  const api = await this.getProvidersApi();
62
64
  const session = await this.resolveReadSession(repo.connectionId, void 0);
63
65
  if (session == null) return void 0;
64
- return api.getRepo(toTokenWithInfo(this.id, session), repo.owner, repo.name, repo.project, { baseUrl: this.apiBaseUrl });
66
+ return api.getRepo(toTokenWithInfo(this.id, session), repo.owner, repo.name, repo.project, { baseUrl: this.apiBaseUrlFor(session) });
65
67
  }
66
68
  async getProviderRepositoryMetadata(_session, _repo, _cancellation) {
67
69
  return Promise.resolve(void 0);
68
70
  }
71
+ /**
72
+ * Accounts by {@link getAccountKey}. One integration serves every installation on its host, and installations
73
+ * mounted at different context paths are different servers whose users differ, even under the same token.
74
+ */
69
75
  _accounts;
76
+ /** The installation the session's reads address, plus the credential — what decides whose account it is. */
77
+ getAccountKey(session) {
78
+ return `${this.apiBaseUrlFor(session)}\n${session.accessToken}`;
79
+ }
80
+ /**
81
+ * The account request the account cache would otherwise answer; see `IntegrationBase.validateCredential`. Needed
82
+ * without any discovery cache: a repo-scoped pull request read fans out across its repositories in the SDK with
83
+ * no request to the connection first, so a dead token comes back as one refused repository per request.
84
+ *
85
+ * A project access token never confirms: its bot user authenticates, but `/users` does not list it, so the SDK
86
+ * cannot find the current user and the check proves nothing.
87
+ */
88
+ async validateCredential(session) {
89
+ if (await (await this.getProvidersApi()).getCurrentUser(toTokenWithInfo(this.id, session), { baseUrl: this.apiBaseUrlFor(session) }).catch((ex) => {
90
+ if (!(ex instanceof AuthenticationError)) throw ex;
91
+ const response = ex.original?.response;
92
+ if (getResponseHeader(response?.headers, "x-ausername") || /not (?:a|currently) licensed/i.test(ex.original?.message ?? "")) throw new Error("Bitbucket Data Center could not confirm the credential", { cause: ex });
93
+ throw ex;
94
+ }) == null) throw new Error("Bitbucket Data Center did not confirm the credential");
95
+ }
70
96
  async getProviderCurrentAccount(session) {
71
- const { accessToken } = session;
97
+ const key = this.getAccountKey(session);
72
98
  this._accounts ??= /* @__PURE__ */ new Map();
73
- if (this._accounts.get(accessToken) == null) {
74
- const user = await (await this.getProvidersApi()).getCurrentUser(toTokenWithInfo(this.id, session), { baseUrl: this.apiBaseUrl });
75
- this._accounts.set(accessToken, user ? {
99
+ if (this._accounts.get(key) == null) {
100
+ const user = await (await this.getProvidersApi()).getCurrentUser(toTokenWithInfo(this.id, session), { baseUrl: this.apiBaseUrlFor(session) });
101
+ this._accounts.set(key, user ? {
76
102
  provider: this,
77
103
  id: user.id,
78
104
  name: user.name ?? void 0,
@@ -81,19 +107,31 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
81
107
  username: user.username ?? void 0
82
108
  } : void 0);
83
109
  }
84
- return this._accounts.get(accessToken);
110
+ return this._accounts.get(key);
111
+ }
112
+ async getProviderOrganizationsForUser(session) {
113
+ return (await this.getProvidersApi()).getBitbucketServerProjects(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), session.id);
114
+ }
115
+ async getProviderRepositoriesForOrg(session, org, options) {
116
+ return (await this.getProvidersApi()).getBitbucketServerRepositories(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), session.id, {
117
+ project: org,
118
+ cursor: options?.cursor
119
+ });
120
+ }
121
+ async getProviderRepositoriesForUser(session, options) {
122
+ return (await this.getProvidersApi()).getBitbucketServerRepositories(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), session.id, options);
85
123
  }
86
124
  async searchProviderMyPullRequests(session, repos, _cancellation, options) {
87
125
  if (repos != null) return;
88
126
  const api = await this.getProvidersApi();
89
127
  if (!api) return;
90
- return (await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrl, { states: toProviderPullRequestStates(options?.state) }))?.data.map((pr) => fromProviderPullRequest(pr, this));
128
+ return (await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), { states: toProviderPullRequestStates(options?.state) }))?.data.map((pr) => fromProviderPullRequest(pr, this));
91
129
  }
92
130
  async getProviderMyPullRequestsForUser(session, options) {
93
131
  const api = await this.getProvidersApi();
94
132
  const states = toProviderPullRequestStates(options?.state);
95
133
  const page = parsePageCursor(options?.cursor);
96
- const result = await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrl, {
134
+ const result = await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), {
97
135
  states,
98
136
  page
99
137
  });
@@ -130,7 +168,7 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
130
168
  return (await collectProviderPagedResult((cursor) => {
131
169
  if (cancellation?.aborted) throw new CancellationError();
132
170
  return api.getPullRequestsForRepo(token, repo, {
133
- baseUrl: this.apiBaseUrl,
171
+ baseUrl: this.apiBaseUrlFor(session),
134
172
  cursor,
135
173
  states
136
174
  });
@@ -139,6 +177,61 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
139
177
  if (cancellation?.aborted) throw new CancellationError();
140
178
  return providerPullRequests.filter((pr) => providerPullRequestMatchesSearch(pr, searchQuery)).map((pr) => fromProviderPullRequest(pr, this));
141
179
  }
180
+ /**
181
+ * The filtered pull-request search, read by this module's own requests rather than the SDK's: the SDK's list
182
+ * reads carry no text, draft or participant-status filter and no per-facet continuation. Every request goes to
183
+ * the session's own address, context path included, so one connection's cursor can't be replayed on another.
184
+ */
185
+ async searchProviderPullRequestsPage(session, options, cancellation) {
186
+ return (await this.getProvidersApi()).searchBitbucketServerPullRequestsPage(toTokenWithInfo(this.id, session), {
187
+ baseUrl: this.apiBaseUrlFor(session),
188
+ connectionId: session.id,
189
+ provider: this,
190
+ repos: options.repos,
191
+ org: options.org,
192
+ criteria: options.criteria,
193
+ currentUser: await this.getSearchUser(session, options.criteria, cancellation),
194
+ cursor: options.cursor,
195
+ pageSize: options.pageSize
196
+ }, cancellation);
197
+ }
198
+ /**
199
+ * Counts each scope by reading it, since Bitbucket Data Center has neither a count query nor a total on its
200
+ * pages. The facade hands over one scope per call and runs those calls concurrently (see `countPullRequests`),
201
+ * so scopes here are counted one after another rather than multiplying that concurrency.
202
+ */
203
+ async countProviderPullRequests(session, scopes, cancellation) {
204
+ const api = await this.getProvidersApi();
205
+ const token = toTokenWithInfo(this.id, session);
206
+ const counts = [];
207
+ for (const scope of scopes) counts.push(await api.countBitbucketServerPullRequests(token, {
208
+ baseUrl: this.apiBaseUrlFor(session),
209
+ repos: scope.repos,
210
+ org: scope.org,
211
+ criteria: scope.criteria,
212
+ currentUser: await this.getSearchUser(session, scope.criteria, cancellation)
213
+ }, cancellation));
214
+ return counts;
215
+ }
216
+ /**
217
+ * The session's own user, which a relationship facet filters by. Resolved per session rather than from the
218
+ * primary connection, so a read pinned to one account never filters by another's identity; an account that
219
+ * can't be resolved refuses the read instead of widening it to everyone's pull requests.
220
+ *
221
+ * The lookup is raced against `cancellation` so a cancelled read settles at once. The SDK's current-user read
222
+ * takes no signal, so the request itself runs on; its answer still lands in the per-token account cache, so a
223
+ * cold lookup a cancellation abandoned isn't wasted on the next read.
224
+ */
225
+ async getSearchUser(session, criteria, cancellation) {
226
+ if (!criteria?.relationships?.length) return void 0;
227
+ const lookup = this.getProviderCurrentAccount(session);
228
+ const account = await (cancellation != null ? raceWithSignal(lookup, cancellation) : lookup);
229
+ if (account?.id == null || account.username == null) throw new Error("Unable to resolve the current Bitbucket Data Center account for a relationship search.");
230
+ return {
231
+ id: account.id,
232
+ username: account.username
233
+ };
234
+ }
142
235
  async getWorkspaceRepoInputs() {
143
236
  const remotes = await this.ctx.repositories.getOpenRemotes();
144
237
  const inputs = await nonnullSettled(remotes.map(async (r) => {
@@ -170,7 +263,8 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
170
263
  storagePrefix = "bitbucket-server";
171
264
  async providerOnConnect() {
172
265
  if (this._session == null) return;
173
- const accountStorageKey = md5(this._session.accessToken);
266
+ const accountKey = this.getAccountKey(this._session);
267
+ const accountStorageKey = md5(accountKey);
174
268
  const storedAccount = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:account`);
175
269
  let account = storedAccount?.data ? {
176
270
  ...storedAccount.data,
@@ -194,7 +288,7 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
194
288
  }
195
289
  }
196
290
  this._accounts ??= /* @__PURE__ */ new Map();
197
- this._accounts.set(this._session.accessToken, account);
291
+ this._accounts.set(accountKey, account);
198
292
  }
199
293
  providerOnDisconnect() {
200
294
  this._accounts = void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"bitbucket-server.js","names":[],"sources":["../../../../../plus/integrations/src/providers/bitbucket-server.ts"],"sourcesContent":["import type { Account, UnidentifiedAuthor } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { Issue, IssueShape } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestType } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type {\n\tPullRequest,\n\tPullRequestMergeMethod,\n\tPullRequestState,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport type { GitRemote } from '@gitlens/git/models/remote.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { md5 } from '@gitlens/utils/crypto.js';\nimport type { Emitter } from '@gitlens/utils/event.js';\nimport type { PagedResult } from '@gitlens/utils/paging.js';\nimport { nonnullSettled } from '@gitlens/utils/promise.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';\nimport type {\n\tAuthenticationSessionLike as AuthenticationSession,\n\tProviderAuthenticationSession,\n} from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport { GitSelfManagedHostIntegrationId } from '../constants.js';\nimport type { IntegrationServiceContext } from '../context.js';\nimport type { IntegrationConnectionChangeEvent } from '../integrationService.js';\nimport type { SearchMyPullRequestsOptions, SearchPullRequestsOptions } from '../models/gitHostIntegration.js';\nimport { GitHostIntegration } from '../models/gitHostIntegration.js';\nimport type { IntegrationKey } from '../models/integration.js';\nimport type { BitbucketRepositoryDescriptor } from './bitbucket/models.js';\nimport type { ProviderPullRequest, ProviderRepository } from './models.js';\nimport {\n\tfromProviderPullRequest,\n\tproviderPullRequestMatchesSearch,\n\tProviderPullRequestReviewState,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport type { ProvidersApi } from './providersApi.js';\nimport {\n\tcollectProviderPagedResult,\n\tflatSettledOrThrow,\n\tparsePageCursor,\n\ttoPageCursor,\n} from './utils/providerPaging.js';\n\nconst metadata = providersMetadata[GitSelfManagedHostIntegrationId.BitbucketServer];\nconst authProvider = Object.freeze({ id: metadata.id, scopes: metadata.scopes });\n\nexport class BitbucketServerIntegration extends GitHostIntegration<\n\tGitSelfManagedHostIntegrationId.BitbucketServer,\n\tBitbucketRepositoryDescriptor\n> {\n\treadonly authProvider: IntegrationAuthenticationProviderDescriptor = authProvider;\n\treadonly id = GitSelfManagedHostIntegrationId.BitbucketServer;\n\tprotected readonly key =\n\t\t`${this.id}:${this.domain}` satisfies IntegrationKey<GitSelfManagedHostIntegrationId.BitbucketServer>;\n\treadonly name: string = 'Bitbucket Data Center';\n\n\tconstructor(\n\t\tctx: IntegrationServiceContext,\n\t\tauthenticationService: IntegrationAuthenticationService,\n\t\tgetProvidersApi: () => Promise<ProvidersApi>,\n\t\tdidChangeConnection: Emitter<IntegrationConnectionChangeEvent>,\n\t\tprivate readonly _domain: string,\n\t) {\n\t\tsuper(ctx, authenticationService, getProvidersApi, didChangeConnection);\n\t}\n\n\tget domain(): string {\n\t\treturn this._domain;\n\t}\n\n\tprotected get apiBaseUrl(): string {\n\t\tconst protocol = this._session?.protocol ?? 'https:';\n\t\treturn `${protocol}//${this.domain}/rest/api/1.0`;\n\t}\n\n\tprotected override async mergeProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tpr: PullRequest,\n\t\toptions?: {\n\t\t\tmergeMethod?: PullRequestMergeMethod;\n\t\t},\n\t): Promise<boolean> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {\n\t\t\tmergeMethod: options?.mergeMethod,\n\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t});\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | UnidentifiedAuthor | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerAccountForCommit(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\trev,\n\t\t\tthis.apiBaseUrl,\n\t\t\t{\n\t\t\t\tavatarSize: options?.avatarSize,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_email: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t\ttype: undefined | IssueOrPullRequestType,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\tif (type === 'issue') {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestById(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tid,\n\t\t\tthis.apiBaseUrl,\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_id: string,\n\t): Promise<Issue | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\tbranch: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForBranch(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tbranch,\n\t\t\tthis.apiBaseUrl,\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\trev,\n\t\t\tthis.apiBaseUrl,\n\t\t);\n\t}\n\n\tpublic override async getRepoInfo(repo: {\n\t\towner: string;\n\t\tname: string;\n\t\tproject?: string;\n\t\tconnectionId?: string;\n\t}): Promise<ProviderRepository | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// `connectionId` targets a specific account (multi-account); omitted reads the primary.\n\t\tconst session = await this.resolveReadSession(repo.connectionId, undefined);\n\t\tif (session == null) return undefined;\n\n\t\treturn api.getRepo(toTokenWithInfo(this.id, session), repo.owner, repo.name, repo.project, {\n\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_cancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprivate _accounts: Map<string, Account | undefined> | undefined;\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst { accessToken } = session;\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\n\t\tconst cachedAccount = this._accounts.get(accessToken);\n\t\tif (cachedAccount == null) {\n\t\t\tconst api = await this.getProvidersApi();\n\t\t\tconst user = await api.getCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t});\n\t\t\tthis._accounts.set(\n\t\t\t\taccessToken,\n\t\t\t\tuser\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tprovider: this,\n\t\t\t\t\t\t\tid: user.id,\n\t\t\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\t\t\temail: user.email ?? undefined,\n\t\t\t\t\t\t\tavatarUrl: user.avatarUrl ?? undefined,\n\t\t\t\t\t\t\tusername: user.username ?? undefined,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t}\n\n\t\treturn this._accounts.get(accessToken);\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: BitbucketRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (repos != null) {\n\t\t\t// TODO: implement repos version\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst api = await this.getProvidersApi();\n\t\tif (!api) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst prs = await api.getBitbucketServerPullRequestsForCurrentUser(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrl,\n\t\t\t{ states: toProviderPullRequestStates(options?.state) },\n\t\t);\n\t\treturn prs?.data.map(pr => fromProviderPullRequest(pr, this));\n\t}\n\n\tprotected override async getProviderMyPullRequestsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions?: { state?: PullRequestStateFilter[]; cursor?: string; filters?: PullRequestFilter[] },\n\t): Promise<PagedResult<ProviderPullRequest> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst states = toProviderPullRequestStates(options?.state);\n\t\t// provider-apis translates the public 1-based `page` to Bitbucket Server's `start` offset and normalizes\n\t\t// `nextPageStart` back to the next page number. Thread that number inside our opaque cursor so the\n\t\t// ProviderBackend sweep drives the drain (bounded by its maxPages).\n\t\tconst page = parsePageCursor(options?.cursor);\n\t\tconst result = await api.getBitbucketServerPullRequestsForCurrentUser(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrl,\n\t\t\t{ states: states, page: page },\n\t\t);\n\t\tif (result == null) return undefined;\n\n\t\tconst account = options?.filters?.length ? await this.getProviderCurrentAccount(session) : undefined;\n\t\tconst identifiers = new Set([account?.id, account?.username].filter((id): id is string => id != null));\n\t\tif (options?.filters?.length && identifiers.size === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Unable to resolve the current Bitbucket Data Center account for the requested pull request filters.',\n\t\t\t);\n\t\t}\n\n\t\tconst values = options?.filters?.length\n\t\t\t? result.data.filter(pr => {\n\t\t\t\t\tconst isCurrentUser = (user: { id?: string | null; username?: string | null } | null | undefined) =>\n\t\t\t\t\t\tuser != null &&\n\t\t\t\t\t\t((user.id != null && identifiers.has(user.id)) ||\n\t\t\t\t\t\t\t(user.username != null && identifiers.has(user.username)));\n\t\t\t\t\tconst isAuthor = isCurrentUser(pr.author);\n\t\t\t\t\tconst isRequestedReviewer = pr.reviews?.some(\n\t\t\t\t\t\treview =>\n\t\t\t\t\t\t\tisCurrentUser(review.reviewer) &&\n\t\t\t\t\t\t\treview.state === ProviderPullRequestReviewState.ReviewRequested,\n\t\t\t\t\t);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t(options.filters!.includes(PullRequestFilter.Author) && isAuthor) ||\n\t\t\t\t\t\t(options.filters!.includes(PullRequestFilter.ReviewRequested) && isRequestedReviewer)\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t: result.data;\n\n\t\treturn {\n\t\t\tvalues: values,\n\t\t\tpaging: {\n\t\t\t\tmore: result.hasMore,\n\t\t\t\tcursor: result.hasMore && result.nextPage != null ? toPageCursor(result.nextPage) : '{}',\n\t\t\t},\n\t\t};\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: BitbucketRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst api = await this.getProvidersApi();\n\t\tif (!api) return undefined;\n\n\t\tconst repoInputs =\n\t\t\trepos != null\n\t\t\t\t? repos.map(r => ({ name: r.name, namespace: r.owner }))\n\t\t\t\t: await this.getWorkspaceRepoInputs();\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\t// An explicitly-empty `repos` means \"search these zero repos\" -> no results; reserve `undefined`\n\t\t// (\"scope couldn't be determined\") for when no repos were requested and none were discovered.\n\t\tif (repoInputs.length === 0) return repos != null ? [] : undefined;\n\n\t\tconst token = toTokenWithInfo(this.id, session);\n\t\tconst states = toProviderPullRequestStates(options?.include);\n\t\tconst providerPullRequests = await flatSettledOrThrow(\n\t\t\trepoInputs.map(async repo => {\n\t\t\t\tconst result = await collectProviderPagedResult(cursor => {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\treturn api.getPullRequestsForRepo(token, repo, {\n\t\t\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\treturn result.values;\n\t\t\t}),\n\t\t);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\treturn providerPullRequests\n\t\t\t.filter(pr => providerPullRequestMatchesSearch(pr, searchQuery))\n\t\t\t.map(pr => fromProviderPullRequest(pr, this));\n\t}\n\n\tprivate async getWorkspaceRepoInputs(): Promise<{ name: string; namespace: string }[]> {\n\t\tconst remotes = await this.ctx.repositories.getOpenRemotes();\n\t\tconst inputs = await nonnullSettled(\n\t\t\tremotes.map(async (r: GitRemote) => {\n\t\t\t\tconst integration = await this.authenticationService.getByRemote(r);\n\t\t\t\tif (integration !== this) return undefined;\n\n\t\t\t\t// Use the remote provider's parsing so the Bitbucket Server `scm/<project>/<repo>` prefix is\n\t\t\t\t// stripped; a raw `path.split('/')` would yield namespace=`scm`, name=`<project>`.\n\t\t\t\tconst namespace = r.provider?.owner;\n\t\t\t\tconst name = r.provider?.repoName;\n\t\t\t\treturn namespace != null && name != null ? { name: name, namespace: namespace } : undefined;\n\t\t\t}),\n\t\t);\n\t\t// Dedupe: a repo with multiple remotes (e.g. `origin` + `upstream`) can map to the same input,\n\t\t// which would otherwise fetch and return the same PRs more than once.\n\t\treturn [...new Map(inputs.map(i => [`${i.namespace}/${i.name}`, i])).values()];\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\t_session: AuthenticationSession,\n\t\t_repos?: BitbucketRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\t/**\n\t * Bitbucket Data Center exposes no issue tracker at all (issues live in Jira), so — like Bitbucket Cloud,\n\t * whose own tracker is deprecated — it is not an issue provider on the ProviderBackend surface. Without this\n\t * the facade would take `supportsIssues`' default `true` and route the read to a provider that registers no\n\t * issue client: the repo-scoped path fails with the SDK's `does not support function: getIssuesForReposFn`\n\t * as an opaque `kind: 'other'` warning, and `broadenIssues` first drains every repo of the org before hitting\n\t * the same failure. Its metadata already declares no issue filters, so this keeps both halves of the\n\t * capability answer consistent.\n\t */\n\toverride get supportsIssues(): boolean {\n\t\treturn false;\n\t}\n\n\tprivate readonly storagePrefix = 'bitbucket-server';\n\tprotected override async providerOnConnect(): Promise<void> {\n\t\tif (this._session == null) return;\n\n\t\tconst accountStorageKey = md5(this._session.accessToken);\n\n\t\tconst storedAccount = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:account`);\n\n\t\tlet account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;\n\n\t\tif (storedAccount == null) {\n\t\t\taccount = await this.getProviderCurrentAccount(this._session);\n\t\t\tif (account != null) {\n\t\t\t\t// Clear all other stored workspaces and repositories and accounts when our session changes\n\t\t\t\tawait this.ctx.storage.deleteWithPrefix(this.storagePrefix);\n\t\t\t\tawait this.ctx.storage.store(`${this.storagePrefix}:${accountStorageKey}:account`, {\n\t\t\t\t\tv: 1,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tid: account.id,\n\t\t\t\t\t\tname: account.name,\n\t\t\t\t\t\temail: account.email,\n\t\t\t\t\t\tavatarUrl: account.avatarUrl,\n\t\t\t\t\t\tusername: account.username,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\t\tthis._accounts.set(this._session.accessToken, account);\n\t}\n\n\tprotected override providerOnDisconnect(): void {\n\t\tthis._accounts = undefined;\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bitbucket-server.js","names":[],"sources":["../../../../../plus/integrations/src/providers/bitbucket-server.ts"],"sourcesContent":["import type { Account, UnidentifiedAuthor } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { Issue, IssueShape } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestType } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type {\n\tPullRequest,\n\tPullRequestMergeMethod,\n\tPullRequestSearchCriteria,\n\tPullRequestState,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport type { GitRemote } from '@gitlens/git/models/remote.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport { CancellationError, raceWithSignal } from '@gitlens/utils/cancellation.js';\nimport { md5 } from '@gitlens/utils/crypto.js';\nimport type { Emitter } from '@gitlens/utils/event.js';\nimport type { PagedResult } from '@gitlens/utils/paging.js';\nimport { nonnullSettled } from '@gitlens/utils/promise.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';\nimport type {\n\tAuthenticationSessionLike as AuthenticationSession,\n\tProviderAuthenticationSession,\n} from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport { GitSelfManagedHostIntegrationId } from '../constants.js';\nimport type { IntegrationServiceContext } from '../context.js';\nimport type { ResponseHeaders } from '../errors.js';\nimport { AuthenticationError, getResponseHeader } from '../errors.js';\nimport type { IntegrationConnectionChangeEvent } from '../integrationService.js';\nimport type { SearchMyPullRequestsOptions, SearchPullRequestsOptions } from '../models/gitHostIntegration.js';\nimport { GitHostIntegration } from '../models/gitHostIntegration.js';\nimport type { IntegrationKey, ProviderPullRequestCount, ProviderPullRequestSearchPage } from '../models/integration.js';\nimport type { BitbucketServerSearchUser } from './bitbucket-server/pullRequestSearch.js';\nimport type { BitbucketRepositoryDescriptor } from './bitbucket/models.js';\nimport type {\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepoInput,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tfromProviderPullRequest,\n\tproviderPullRequestMatchesSearch,\n\tProviderPullRequestReviewState,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport type { ProvidersApi } from './providersApi.js';\nimport {\n\tcollectProviderPagedResult,\n\tflatSettledOrThrow,\n\tparsePageCursor,\n\ttoPageCursor,\n} from './utils/providerPaging.js';\n\nconst metadata = providersMetadata[GitSelfManagedHostIntegrationId.BitbucketServer];\nconst authProvider = Object.freeze({ id: metadata.id, scopes: metadata.scopes });\n\nexport class BitbucketServerIntegration extends GitHostIntegration<\n\tGitSelfManagedHostIntegrationId.BitbucketServer,\n\tBitbucketRepositoryDescriptor\n> {\n\treadonly authProvider: IntegrationAuthenticationProviderDescriptor = authProvider;\n\treadonly id = GitSelfManagedHostIntegrationId.BitbucketServer;\n\tprotected readonly key =\n\t\t`${this.id}:${this.domain}` satisfies IntegrationKey<GitSelfManagedHostIntegrationId.BitbucketServer>;\n\treadonly name: string = 'Bitbucket Data Center';\n\n\tconstructor(\n\t\tctx: IntegrationServiceContext,\n\t\tauthenticationService: IntegrationAuthenticationService,\n\t\tgetProvidersApi: () => Promise<ProvidersApi>,\n\t\tdidChangeConnection: Emitter<IntegrationConnectionChangeEvent>,\n\t\tprivate readonly _domain: string,\n\t) {\n\t\tsuper(ctx, authenticationService, getProvidersApi, didChangeConnection);\n\t}\n\n\tget domain(): string {\n\t\treturn this._domain;\n\t}\n\n\tprotected apiBaseUrlFor(session: ProviderAuthenticationSession): string {\n\t\treturn this.getSelfManagedApiBaseUrl(session);\n\t}\n\n\tprotected override async mergeProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tpr: PullRequest,\n\t\toptions?: {\n\t\t\tmergeMethod?: PullRequestMergeMethod;\n\t\t},\n\t): Promise<boolean> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {\n\t\t\tmergeMethod: options?.mergeMethod,\n\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t});\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | UnidentifiedAuthor | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerAccountForCommit(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\trev,\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\t{\n\t\t\t\tavatarSize: options?.avatarSize,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_email: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t\ttype: undefined | IssueOrPullRequestType,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\tif (type === 'issue') {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestById(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tid,\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_id: string,\n\t): Promise<Issue | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\tbranch: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForBranch(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tbranch,\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: BitbucketRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\trev,\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t);\n\t}\n\n\tpublic override async getRepoInfo(repo: {\n\t\towner: string;\n\t\tname: string;\n\t\tproject?: string;\n\t\tconnectionId?: string;\n\t}): Promise<ProviderRepository | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// `connectionId` targets a specific account (multi-account); omitted reads the primary.\n\t\tconst session = await this.resolveReadSession(repo.connectionId, undefined);\n\t\tif (session == null) return undefined;\n\n\t\treturn api.getRepo(toTokenWithInfo(this.id, session), repo.owner, repo.name, repo.project, {\n\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\t_session: AuthenticationSession,\n\t\t_repo: BitbucketRepositoryDescriptor,\n\t\t_cancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\t/**\n\t * Accounts by {@link getAccountKey}. One integration serves every installation on its host, and installations\n\t * mounted at different context paths are different servers whose users differ, even under the same token.\n\t */\n\tprivate _accounts: Map<string, Account | undefined> | undefined;\n\n\t/** The installation the session's reads address, plus the credential — what decides whose account it is. */\n\tprivate getAccountKey(session: ProviderAuthenticationSession): string {\n\t\treturn `${this.apiBaseUrlFor(session)}\\n${session.accessToken}`;\n\t}\n\n\t/**\n\t * The account request the account cache would otherwise answer; see `IntegrationBase.validateCredential`. Needed\n\t * without any discovery cache: a repo-scoped pull request read fans out across its repositories in the SDK with\n\t * no request to the connection first, so a dead token comes back as one refused repository per request.\n\t *\n\t * A project access token never confirms: its bot user authenticates, but `/users` does not list it, so the SDK\n\t * cannot find the current user and the check proves nothing.\n\t */\n\tprotected override async validateCredential(session: ProviderAuthenticationSession): Promise<void> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst user = await api\n\t\t\t.getCurrentUser(toTokenWithInfo(this.id, session), { baseUrl: this.apiBaseUrlFor(session) })\n\t\t\t.catch((ex: unknown) => {\n\t\t\t\tif (!(ex instanceof AuthenticationError)) throw ex;\n\n\t\t\t\t// Bitbucket Data Center names the user it authenticated in `X-AUSERNAME`, and answers a dead token\n\t\t\t\t// exactly as it answers no credential: the same 401 and body, without that header. So a refusal that\n\t\t\t\t// names a user, or says the user holds no license, came from a credential that authenticated, and\n\t\t\t\t// proves nothing about the scopes' refusals.\n\t\t\t\tconst response = (ex.original as { response?: { headers?: ResponseHeaders } } | undefined)?.response;\n\t\t\t\tif (\n\t\t\t\t\tgetResponseHeader(response?.headers, 'x-ausername') ||\n\t\t\t\t\t/not (?:a|currently) licensed/i.test(ex.original?.message ?? '')\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error('Bitbucket Data Center could not confirm the credential', { cause: ex });\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t});\n\t\tif (user == null) {\n\t\t\tthrow new Error('Bitbucket Data Center did not confirm the credential');\n\t\t}\n\t}\n\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst key = this.getAccountKey(session);\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\n\t\tconst cachedAccount = this._accounts.get(key);\n\t\tif (cachedAccount == null) {\n\t\t\tconst api = await this.getProvidersApi();\n\t\t\tconst user = await api.getCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t});\n\t\t\tthis._accounts.set(\n\t\t\t\tkey,\n\t\t\t\tuser\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tprovider: this,\n\t\t\t\t\t\t\tid: user.id,\n\t\t\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\t\t\temail: user.email ?? undefined,\n\t\t\t\t\t\t\tavatarUrl: user.avatarUrl ?? undefined,\n\t\t\t\t\t\t\tusername: user.username ?? undefined,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t}\n\n\t\treturn this._accounts.get(key);\n\t}\n\n\tprotected override async getProviderOrganizationsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization>> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.getBitbucketServerProjects(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\tsession.id,\n\t\t);\n\t}\n\n\tprotected override async getProviderRepositoriesForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg: string,\n\t\toptions?: { cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository>> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.getBitbucketServerRepositories(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\tsession.id,\n\t\t\t{\n\t\t\t\tproject: org,\n\t\t\t\tcursor: options?.cursor,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderRepositoriesForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions?: { cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository>> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.getBitbucketServerRepositories(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\tsession.id,\n\t\t\toptions,\n\t\t);\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: BitbucketRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (repos != null) {\n\t\t\t// TODO: implement repos version\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst api = await this.getProvidersApi();\n\t\tif (!api) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst prs = await api.getBitbucketServerPullRequestsForCurrentUser(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\t{ states: toProviderPullRequestStates(options?.state) },\n\t\t);\n\t\treturn prs?.data.map(pr => fromProviderPullRequest(pr, this));\n\t}\n\n\tprotected override async getProviderMyPullRequestsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions?: { state?: PullRequestStateFilter[]; cursor?: string; filters?: PullRequestFilter[] },\n\t): Promise<PagedResult<ProviderPullRequest> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst states = toProviderPullRequestStates(options?.state);\n\t\t// provider-apis translates the public 1-based `page` to Bitbucket Server's `start` offset and normalizes\n\t\t// `nextPageStart` back to the next page number. Thread that number inside our opaque cursor so the\n\t\t// ProviderBackend sweep drives the drain (bounded by its maxPages).\n\t\tconst page = parsePageCursor(options?.cursor);\n\t\tconst result = await api.getBitbucketServerPullRequestsForCurrentUser(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\t{ states: states, page: page },\n\t\t);\n\t\tif (result == null) return undefined;\n\n\t\tconst account = options?.filters?.length ? await this.getProviderCurrentAccount(session) : undefined;\n\t\tconst identifiers = new Set([account?.id, account?.username].filter((id): id is string => id != null));\n\t\tif (options?.filters?.length && identifiers.size === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Unable to resolve the current Bitbucket Data Center account for the requested pull request filters.',\n\t\t\t);\n\t\t}\n\n\t\tconst values = options?.filters?.length\n\t\t\t? result.data.filter(pr => {\n\t\t\t\t\tconst isCurrentUser = (user: { id?: string | null; username?: string | null } | null | undefined) =>\n\t\t\t\t\t\tuser != null &&\n\t\t\t\t\t\t((user.id != null && identifiers.has(user.id)) ||\n\t\t\t\t\t\t\t(user.username != null && identifiers.has(user.username)));\n\t\t\t\t\tconst isAuthor = isCurrentUser(pr.author);\n\t\t\t\t\tconst isRequestedReviewer = pr.reviews?.some(\n\t\t\t\t\t\treview =>\n\t\t\t\t\t\t\tisCurrentUser(review.reviewer) &&\n\t\t\t\t\t\t\treview.state === ProviderPullRequestReviewState.ReviewRequested,\n\t\t\t\t\t);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t(options.filters!.includes(PullRequestFilter.Author) && isAuthor) ||\n\t\t\t\t\t\t(options.filters!.includes(PullRequestFilter.ReviewRequested) && isRequestedReviewer)\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t: result.data;\n\n\t\treturn {\n\t\t\tvalues: values,\n\t\t\tpaging: {\n\t\t\t\tmore: result.hasMore,\n\t\t\t\tcursor: result.hasMore && result.nextPage != null ? toPageCursor(result.nextPage) : '{}',\n\t\t\t},\n\t\t};\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: BitbucketRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst api = await this.getProvidersApi();\n\t\tif (!api) return undefined;\n\n\t\tconst repoInputs =\n\t\t\trepos != null\n\t\t\t\t? repos.map(r => ({ name: r.name, namespace: r.owner }))\n\t\t\t\t: await this.getWorkspaceRepoInputs();\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\t// An explicitly-empty `repos` means \"search these zero repos\" -> no results; reserve `undefined`\n\t\t// (\"scope couldn't be determined\") for when no repos were requested and none were discovered.\n\t\tif (repoInputs.length === 0) return repos != null ? [] : undefined;\n\n\t\tconst token = toTokenWithInfo(this.id, session);\n\t\tconst states = toProviderPullRequestStates(options?.include);\n\t\tconst providerPullRequests = await flatSettledOrThrow(\n\t\t\trepoInputs.map(async repo => {\n\t\t\t\tconst result = await collectProviderPagedResult(cursor => {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\treturn api.getPullRequestsForRepo(token, repo, {\n\t\t\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\treturn result.values;\n\t\t\t}),\n\t\t);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\treturn providerPullRequests\n\t\t\t.filter(pr => providerPullRequestMatchesSearch(pr, searchQuery))\n\t\t\t.map(pr => fromProviderPullRequest(pr, this));\n\t}\n\n\t/**\n\t * The filtered pull-request search, read by this module's own requests rather than the SDK's: the SDK's list\n\t * reads carry no text, draft or participant-status filter and no per-facet continuation. Every request goes to\n\t * the session's own address, context path included, so one connection's cursor can't be replayed on another.\n\t */\n\tprotected override async searchProviderPullRequestsPage(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions: {\n\t\t\trepos?: ProviderRepoInput[];\n\t\t\torg?: string;\n\t\t\tcriteria?: PullRequestSearchCriteria;\n\t\t\tcursor?: string;\n\t\t\tpageSize?: number;\n\t\t\tsummary?: boolean;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<ProviderPullRequestSearchPage | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\treturn api.searchBitbucketServerPullRequestsPage(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t\tconnectionId: session.id,\n\t\t\t\tprovider: this,\n\t\t\t\trepos: options.repos,\n\t\t\t\torg: options.org,\n\t\t\t\tcriteria: options.criteria,\n\t\t\t\tcurrentUser: await this.getSearchUser(session, options.criteria, cancellation),\n\t\t\t\tcursor: options.cursor,\n\t\t\t\tpageSize: options.pageSize,\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t/**\n\t * Counts each scope by reading it, since Bitbucket Data Center has neither a count query nor a total on its\n\t * pages. The facade hands over one scope per call and runs those calls concurrently (see `countPullRequests`),\n\t * so scopes here are counted one after another rather than multiplying that concurrency.\n\t */\n\tprotected override async countProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tscopes: readonly { repos?: ProviderRepoInput[]; org?: string; criteria?: PullRequestSearchCriteria }[],\n\t\tcancellation?: AbortSignal,\n\t): Promise<ProviderPullRequestCount[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst token = toTokenWithInfo(this.id, session);\n\t\tconst counts: ProviderPullRequestCount[] = [];\n\t\tfor (const scope of scopes) {\n\t\t\tcounts.push(\n\t\t\t\tawait api.countBitbucketServerPullRequests(\n\t\t\t\t\ttoken,\n\t\t\t\t\t{\n\t\t\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t\t\t\trepos: scope.repos,\n\t\t\t\t\t\torg: scope.org,\n\t\t\t\t\t\tcriteria: scope.criteria,\n\t\t\t\t\t\tcurrentUser: await this.getSearchUser(session, scope.criteria, cancellation),\n\t\t\t\t\t},\n\t\t\t\t\tcancellation,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn counts;\n\t}\n\n\t/**\n\t * The session's own user, which a relationship facet filters by. Resolved per session rather than from the\n\t * primary connection, so a read pinned to one account never filters by another's identity; an account that\n\t * can't be resolved refuses the read instead of widening it to everyone's pull requests.\n\t *\n\t * The lookup is raced against `cancellation` so a cancelled read settles at once. The SDK's current-user read\n\t * takes no signal, so the request itself runs on; its answer still lands in the per-token account cache, so a\n\t * cold lookup a cancellation abandoned isn't wasted on the next read.\n\t */\n\tprivate async getSearchUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcriteria: PullRequestSearchCriteria | undefined,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<BitbucketServerSearchUser | undefined> {\n\t\tif (!criteria?.relationships?.length) return undefined;\n\n\t\tconst lookup = this.getProviderCurrentAccount(session);\n\t\tconst account = await (cancellation != null ? raceWithSignal(lookup, cancellation) : lookup);\n\t\tif (account?.id == null || account.username == null) {\n\t\t\tthrow new Error('Unable to resolve the current Bitbucket Data Center account for a relationship search.');\n\t\t}\n\n\t\treturn { id: account.id, username: account.username };\n\t}\n\n\tprivate async getWorkspaceRepoInputs(): Promise<{ name: string; namespace: string }[]> {\n\t\tconst remotes = await this.ctx.repositories.getOpenRemotes();\n\t\tconst inputs = await nonnullSettled(\n\t\t\tremotes.map(async (r: GitRemote) => {\n\t\t\t\tconst integration = await this.authenticationService.getByRemote(r);\n\t\t\t\tif (integration !== this) return undefined;\n\n\t\t\t\t// Use the remote provider's parsing so the Bitbucket Server `scm/<project>/<repo>` prefix is\n\t\t\t\t// stripped; a raw `path.split('/')` would yield namespace=`scm`, name=`<project>`.\n\t\t\t\tconst namespace = r.provider?.owner;\n\t\t\t\tconst name = r.provider?.repoName;\n\t\t\t\treturn namespace != null && name != null ? { name: name, namespace: namespace } : undefined;\n\t\t\t}),\n\t\t);\n\t\t// Dedupe: a repo with multiple remotes (e.g. `origin` + `upstream`) can map to the same input,\n\t\t// which would otherwise fetch and return the same PRs more than once.\n\t\treturn [...new Map(inputs.map(i => [`${i.namespace}/${i.name}`, i])).values()];\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\t_session: AuthenticationSession,\n\t\t_repos?: BitbucketRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\t/**\n\t * Bitbucket Data Center exposes no issue tracker at all (issues live in Jira), so — like Bitbucket Cloud,\n\t * whose own tracker is deprecated — it is not an issue provider on the ProviderBackend surface. Without this\n\t * the facade would take `supportsIssues`' default `true` and route the read to a provider that registers no\n\t * issue client: the repo-scoped path fails with the SDK's `does not support function: getIssuesForReposFn`\n\t * as an opaque `kind: 'other'` warning, and `broadenIssues` first drains every repo of the org before hitting\n\t * the same failure. Its metadata already declares no issue filters, so this keeps both halves of the\n\t * capability answer consistent.\n\t */\n\toverride get supportsIssues(): boolean {\n\t\treturn false;\n\t}\n\n\tprivate readonly storagePrefix = 'bitbucket-server';\n\tprotected override async providerOnConnect(): Promise<void> {\n\t\tif (this._session == null) return;\n\n\t\tconst accountKey = this.getAccountKey(this._session);\n\t\tconst accountStorageKey = md5(accountKey);\n\n\t\tconst storedAccount = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:account`);\n\n\t\tlet account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;\n\n\t\tif (storedAccount == null) {\n\t\t\taccount = await this.getProviderCurrentAccount(this._session);\n\t\t\tif (account != null) {\n\t\t\t\t// Clear all other stored workspaces and repositories and accounts when our session changes\n\t\t\t\tawait this.ctx.storage.deleteWithPrefix(this.storagePrefix);\n\t\t\t\tawait this.ctx.storage.store(`${this.storagePrefix}:${accountStorageKey}:account`, {\n\t\t\t\t\tv: 1,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tid: account.id,\n\t\t\t\t\t\tname: account.name,\n\t\t\t\t\t\temail: account.email,\n\t\t\t\t\t\tavatarUrl: account.avatarUrl,\n\t\t\t\t\t\tusername: account.username,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\t\tthis._accounts.set(accountKey, account);\n\t}\n\n\tprotected override providerOnDisconnect(): void {\n\t\tthis._accounts = undefined;\n\t}\n}\n"],"mappings":"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"}
@@ -6,8 +6,9 @@ import { DefaultBranch } from "../../../git/models/defaultBranch.js";
6
6
  import { RepositoryMetadata } from "../../../git/models/repositoryMetadata.js";
7
7
  import { AuthenticationSessionLike, ProviderAuthenticationSession } from "../authentication/models.js";
8
8
  import { GitCloudHostIntegrationId } from "../constants.js";
9
- import { GitHostIntegration, SearchMyPullRequestsOptions, SearchPullRequestsOptions } from "../models/gitHostIntegration.js";
10
9
  import { ProviderOrganization } from "../results.js";
10
+ import { ProviderRefusal } from "../collectionMetadata.js";
11
+ import { GitHostIntegration, SearchMyPullRequestsOptions, SearchPullRequestsOptions } from "../models/gitHostIntegration.js";
11
12
  import { ProviderApiPagedResult, ProviderHierarchyResult, ProviderPullRequest, ProviderRepository } from "./models.js";
12
13
  import { IntegrationAuthenticationProviderDescriptor } from "../authentication/integrationAuthenticationProvider.js";
13
14
  import { BitbucketRepositoryDescriptor } from "./bitbucket/models.js";
@@ -48,6 +49,13 @@ export declare class BitbucketIntegration extends GitHostIntegration<GitCloudHos
48
49
  protected getProviderRepositoryMetadata(session: ProviderAuthenticationSession, repo: BitbucketRepositoryDescriptor, cancellation?: AbortSignal): Promise<RepositoryMetadata | undefined>;
49
50
  private _accounts;
50
51
  protected getProviderCurrentAccount(session: ProviderAuthenticationSession): Promise<Account | undefined>;
52
+ /** The profile request the account cache would otherwise answer; see `IntegrationBase.validateCredential`. */
53
+ protected validateCredential(session: ProviderAuthenticationSession): Promise<void>;
54
+ /**
55
+ * Bitbucket's `403` for a token missing the OAuth scopes a request needs, which a reconnect fixes by consenting to
56
+ * them again; see `IntegrationBase.isCredentialRefusal`.
57
+ */
58
+ protected isCredentialRefusal(refusal: ProviderRefusal): boolean;
51
59
  private _workspaces;
52
60
  private getProviderResourcesForCurrentUser;
53
61
  protected getProviderOrganizationsForUser(session: ProviderAuthenticationSession): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined>;
@@ -3,11 +3,11 @@ import { CancellationError } from "../../../utils/cancellation.js";
3
3
  import { batchResults, flatSettled, nonnullSettled } from "../../../utils/promise.js";
4
4
  import { md5 } from "../../../utils/crypto.js";
5
5
  import "../../../git/models/pullRequest.js";
6
- import { toCollectionScopeFailure } from "../collectionMetadata.js";
7
6
  import "../constants.js";
7
+ import { toCollectionScopeFailure } from "../collectionMetadata.js";
8
8
  import { toTokenWithInfo } from "../authentication/models.js";
9
- import { fromProviderPullRequest, getProviderPullRequestIdentity, providersMetadata, toProviderPullRequestStates } from "./models.js";
10
9
  import { collectProviderPagedResult, flatSettledOrThrow, mergeCollectionMetadata, parsePageCursor, toPageCursor } from "./utils/providerPaging.js";
10
+ import { fromProviderPullRequest, getProviderPullRequestIdentity, providersMetadata, toProviderPullRequestStates } from "./models.js";
11
11
  import { GitHostIntegration } from "../models/gitHostIntegration.js";
12
12
  //#region ../plus/integrations/src/providers/bitbucket.ts
13
13
  const metadata = providersMetadata["bitbucket"];
@@ -76,6 +76,17 @@ var BitbucketIntegration = class extends GitHostIntegration {
76
76
  }
77
77
  return this._accounts.get(accessToken);
78
78
  }
79
+ /** The profile request the account cache would otherwise answer; see `IntegrationBase.validateCredential`. */
80
+ async validateCredential(session) {
81
+ if (await (await this.getProvidersApi()).getCurrentUser(toTokenWithInfo(this.id, session)) == null) throw new Error("Bitbucket did not confirm the credential");
82
+ }
83
+ /**
84
+ * Bitbucket's `403` for a token missing the OAuth scopes a request needs, which a reconnect fixes by consenting to
85
+ * them again; see `IntegrationBase.isCredentialRefusal`.
86
+ */
87
+ isCredentialRefusal(refusal) {
88
+ return refusal.status === 403 && /required privilege scopes/i.test(refusal.detail ?? "");
89
+ }
79
90
  _workspaces;
80
91
  async getProviderResourcesForCurrentUser(session, force = false) {
81
92
  this._workspaces ??= /* @__PURE__ */ new Map();